github.com/zntrio/harp/v2@v2.0.9/pkg/container/seal/v2/seal_test.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 package v2 18 19 import ( 20 "crypto/rand" 21 "testing" 22 23 "github.com/awnumar/memguard" 24 "github.com/google/go-cmp/cmp" 25 "github.com/google/go-cmp/cmp/cmpopts" 26 fuzz "github.com/google/gofuzz" 27 "github.com/stretchr/testify/assert" 28 29 containerv1 "github.com/zntrio/harp/v2/api/gen/go/harp/container/v1" 30 ) 31 32 var ( 33 opt = cmp.FilterPath( 34 func(p cmp.Path) bool { 35 // Remove ignoring of the fields below once go-cmp is able to ignore generated fields. 36 // See https://github.com/google/go-cmp/issues/153 37 ignoreXXXCache := 38 p.String() == "XXX_sizecache" || 39 p.String() == "Headers.XXX_sizecache" 40 return ignoreXXXCache 41 }, cmp.Ignore()) 42 43 ignoreOpts = []cmp.Option{ 44 cmpopts.IgnoreUnexported(containerv1.Container{}), 45 cmpopts.IgnoreUnexported(containerv1.Header{}), 46 opt, 47 } 48 ) 49 50 // ----------------------------------------------------------------------------- 51 52 func TestSeal(t *testing.T) { 53 type args struct { 54 container *containerv1.Container 55 peersPublicKey []string 56 } 57 tests := []struct { 58 name string 59 args args 60 want *containerv1.Container 61 wantErr bool 62 }{ 63 { 64 name: "nil", 65 wantErr: true, 66 }, 67 { 68 name: "empty container", 69 args: args{ 70 container: &containerv1.Container{}, 71 }, 72 wantErr: true, 73 }, 74 { 75 name: "empty container headers", 76 args: args{ 77 container: &containerv1.Container{ 78 Headers: &containerv1.Header{}, 79 }, 80 }, 81 wantErr: true, 82 }, 83 // --------------------------------------------------------------------- 84 { 85 name: "valid", 86 args: args{ 87 container: &containerv1.Container{ 88 Headers: &containerv1.Header{}, 89 Raw: []byte{0x01, 0x02, 0x03, 0x04}, 90 }, 91 peersPublicKey: []string{ 92 "v2.sk.AuSjVpMZben6n9fXiaDj8bMjSvhcZ9n7c82VOt7v9_UBzZJaMLamkQUFAVp_9frpAg", 93 "v2.sk.A0V1xCxGNtVAE9EVhaKi-pIADhd1in8xV_FI5Y0oHSHLAkew9gDAqiALSd6VgvBCbQ", 94 }, 95 }, 96 wantErr: false, 97 }, 98 } 99 for _, tt := range tests { 100 t.Run(tt.name, func(t *testing.T) { 101 adapter := New() 102 _, err := adapter.Seal(rand.Reader, tt.args.container, tt.args.peersPublicKey...) 103 if (err != nil) != tt.wantErr { 104 t.Errorf("Seal() error = %v, wantErr %v", err, tt.wantErr) 105 return 106 } 107 }) 108 } 109 } 110 111 func TestSealWithPSK(t *testing.T) { 112 psk := memguard.NewBufferRandom(64) 113 114 type args struct { 115 container *containerv1.Container 116 peersPublicKey []string 117 } 118 tests := []struct { 119 name string 120 args args 121 want *containerv1.Container 122 wantErr bool 123 }{ 124 { 125 name: "nil", 126 wantErr: true, 127 }, 128 { 129 name: "empty container", 130 args: args{ 131 container: &containerv1.Container{}, 132 }, 133 wantErr: true, 134 }, 135 { 136 name: "empty container headers", 137 args: args{ 138 container: &containerv1.Container{ 139 Headers: &containerv1.Header{}, 140 }, 141 }, 142 wantErr: true, 143 }, 144 // --------------------------------------------------------------------- 145 { 146 name: "valid", 147 args: args{ 148 container: &containerv1.Container{ 149 Headers: &containerv1.Header{}, 150 Raw: []byte{0x01, 0x02, 0x03, 0x04}, 151 }, 152 peersPublicKey: []string{ 153 "v2.sk.AuSjVpMZben6n9fXiaDj8bMjSvhcZ9n7c82VOt7v9_UBzZJaMLamkQUFAVp_9frpAg", 154 "v2.sk.A0V1xCxGNtVAE9EVhaKi-pIADhd1in8xV_FI5Y0oHSHLAkew9gDAqiALSd6VgvBCbQ", 155 }, 156 }, 157 wantErr: false, 158 }, 159 } 160 for _, tt := range tests { 161 t.Run(tt.name, func(t *testing.T) { 162 adapter := New() 163 _, err := adapter.SealWithPSK(rand.Reader, tt.args.container, psk, tt.args.peersPublicKey...) 164 if (err != nil) != tt.wantErr { 165 t.Errorf("Seal() error = %v, wantErr %v", err, tt.wantErr) 166 return 167 } 168 }) 169 } 170 } 171 172 // ----------------------------------------------------------------------------- 173 174 func Test_Seal_Unseal(t *testing.T) { 175 adapter := New() 176 177 pubKey, privKey, err := adapter.GenerateKey() 178 assert.NoError(t, err) 179 180 input := &containerv1.Container{ 181 Headers: &containerv1.Header{ 182 ContentEncoding: "gzip", 183 ContentType: "application/vnd.harp.v1.Bundle", 184 }, 185 Raw: []byte{0x00, 0x00}, 186 } 187 188 sealed, err := adapter.Seal(rand.Reader, input, pubKey) 189 if err != nil { 190 t.Fatalf("unable to seal container: %v", err) 191 } 192 193 unsealed, err := adapter.Unseal(sealed, memguard.NewBufferFromBytes([]byte(privKey))) 194 if err != nil { 195 t.Fatalf("unable to unseal container: %v", err) 196 } 197 198 if diff := cmp.Diff(unsealed, input, ignoreOpts...); diff != "" { 199 t.Errorf("Seal/Unseal()\n-got/+want\ndiff %s", diff) 200 } 201 } 202 203 func Test_Seal_Unseal_WithPSK(t *testing.T) { 204 psk := memguard.NewBufferRandom(64) 205 adapter := New() 206 207 pubKey, privKey, err := adapter.GenerateKey() 208 assert.NoError(t, err) 209 210 input := &containerv1.Container{ 211 Headers: &containerv1.Header{ 212 ContentEncoding: "gzip", 213 ContentType: "application/vnd.harp.v1.Bundle", 214 }, 215 Raw: []byte{0x00, 0x00}, 216 } 217 218 sealed, err := adapter.SealWithPSK(rand.Reader, input, psk, pubKey) 219 if err != nil { 220 t.Fatalf("unable to seal container: %v", err) 221 } 222 223 unsealed, err := adapter.UnsealWithPSK(sealed, memguard.NewBufferFromBytes([]byte(privKey)), psk) 224 if err != nil { 225 t.Fatalf("unable to unseal container: %v", err) 226 } 227 228 if diff := cmp.Diff(unsealed, input, ignoreOpts...); diff != "" { 229 t.Errorf("Seal/Unseal()\n-got/+want\ndiff %s", diff) 230 } 231 } 232 233 func Test_Seal_Fuzz(t *testing.T) { 234 adapter := New() 235 236 // Making sure the function never panics 237 for i := 0; i < 500; i++ { 238 f := fuzz.New() 239 240 // Prepare arguments 241 var ( 242 publicKey string 243 ) 244 input := containerv1.Container{ 245 Headers: &containerv1.Header{}, 246 Raw: []byte{0x00, 0x00}, 247 } 248 249 f.Fuzz(&input.Headers) 250 f.Fuzz(&input.Raw) 251 f.Fuzz(&publicKey) 252 253 // Execute 254 adapter.Seal(rand.Reader, &input, publicKey) 255 } 256 } 257 258 // -----------------------------------------------------------------------------. 259 func benchmarkSeal(container *containerv1.Container, peersPublicKeys []string, b *testing.B) { 260 adapter := New() 261 for n := 0; n < b.N; n++ { 262 _, err := adapter.Seal(rand.Reader, container, peersPublicKeys...) 263 if err != nil { 264 b.Fatal(err) 265 } 266 } 267 } 268 269 func Benchmark_Seal(b *testing.B) { 270 publicKey, _, err := New().GenerateKey() 271 assert.NoError(b, err) 272 273 input := &containerv1.Container{ 274 Headers: &containerv1.Header{ 275 ContentEncoding: "gzip", 276 ContentType: "application/vnd.harp.v1.Bundle", 277 }, 278 Raw: make([]byte, 1024), 279 } 280 281 benchmarkSeal(input, []string{publicKey}, b) 282 }