github.com/zntrio/harp/v2@v2.0.9/pkg/container/seal/v1/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 v1 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 name: "empty container with public keys", 85 args: args{ 86 container: &containerv1.Container{ 87 Headers: &containerv1.Header{}, 88 }, 89 peersPublicKey: []string{ 90 "v1.sk.qKXPnUP6-2Bb_4nYnmxOXyCdN4IV3AR5HooB33N3g2E", 91 "v1.sk.sYp90gC29yKfUUtr50pMR4Faf7c3d4-YX4xZsbwAs10", 92 }, 93 }, 94 wantErr: false, 95 }, 96 { 97 name: "valid container with public keys", 98 args: args{ 99 container: &containerv1.Container{ 100 Headers: &containerv1.Header{}, 101 Raw: memguard.NewBufferRandom(1024).Bytes(), 102 }, 103 peersPublicKey: []string{ 104 "v1.sk.qKXPnUP6-2Bb_4nYnmxOXyCdN4IV3AR5HooB33N3g2E", 105 "v1.sk.sYp90gC29yKfUUtr50pMR4Faf7c3d4-YX4xZsbwAs10", 106 }, 107 }, 108 wantErr: false, 109 }, 110 } 111 for _, tt := range tests { 112 t.Run(tt.name, func(t *testing.T) { 113 adapter := New() 114 _, err := adapter.Seal(rand.Reader, tt.args.container, tt.args.peersPublicKey...) 115 if (err != nil) != tt.wantErr { 116 t.Errorf("Seal() error = %v, wantErr %v", err, tt.wantErr) 117 return 118 } 119 }) 120 } 121 } 122 123 func TestSealWithPSK(t *testing.T) { 124 psk := memguard.NewBufferRandom(64) 125 126 type args struct { 127 container *containerv1.Container 128 peersPublicKey []string 129 } 130 tests := []struct { 131 name string 132 args args 133 want *containerv1.Container 134 wantErr bool 135 }{ 136 { 137 name: "nil", 138 wantErr: true, 139 }, 140 { 141 name: "empty container", 142 args: args{ 143 container: &containerv1.Container{}, 144 }, 145 wantErr: true, 146 }, 147 { 148 name: "empty container headers", 149 args: args{ 150 container: &containerv1.Container{ 151 Headers: &containerv1.Header{}, 152 }, 153 }, 154 wantErr: true, 155 }, 156 { 157 name: "empty container with public keys", 158 args: args{ 159 container: &containerv1.Container{ 160 Headers: &containerv1.Header{}, 161 }, 162 peersPublicKey: []string{ 163 "v1.sk.qKXPnUP6-2Bb_4nYnmxOXyCdN4IV3AR5HooB33N3g2E", 164 "v1.sk.sYp90gC29yKfUUtr50pMR4Faf7c3d4-YX4xZsbwAs10", 165 }, 166 }, 167 wantErr: false, 168 }, 169 { 170 name: "valid container with public keys", 171 args: args{ 172 container: &containerv1.Container{ 173 Headers: &containerv1.Header{}, 174 Raw: memguard.NewBufferRandom(1024).Bytes(), 175 }, 176 peersPublicKey: []string{ 177 "v1.sk.qKXPnUP6-2Bb_4nYnmxOXyCdN4IV3AR5HooB33N3g2E", 178 "v1.sk.sYp90gC29yKfUUtr50pMR4Faf7c3d4-YX4xZsbwAs10", 179 }, 180 }, 181 wantErr: false, 182 }, 183 } 184 for _, tt := range tests { 185 t.Run(tt.name, func(t *testing.T) { 186 adapter := New() 187 _, err := adapter.SealWithPSK(rand.Reader, tt.args.container, psk, tt.args.peersPublicKey...) 188 if (err != nil) != tt.wantErr { 189 t.Errorf("SealWithPSK() error = %v, wantErr %v", err, tt.wantErr) 190 return 191 } 192 }) 193 } 194 } 195 196 // ----------------------------------------------------------------------------- 197 198 func Test_Seal_Unseal(t *testing.T) { 199 adapter := New() 200 201 publicKey1, privateKey1, err := adapter.GenerateKey() 202 assert.NoError(t, err) 203 204 input := &containerv1.Container{ 205 Headers: &containerv1.Header{ 206 ContentEncoding: "gzip", 207 ContentType: "application/vnd.harp.v1.Bundle", 208 }, 209 Raw: memguard.NewBufferRandom(1024).Bytes(), 210 } 211 212 sealed, err := adapter.Seal(rand.Reader, input, publicKey1) 213 if err != nil { 214 t.Fatalf("unable to seal container: %v", err) 215 } 216 217 unsealed, err := adapter.Unseal(sealed, memguard.NewBufferFromBytes([]byte(privateKey1))) 218 if err != nil { 219 t.Fatalf("unable to unseal container: %v", err) 220 } 221 222 if diff := cmp.Diff(unsealed, input, ignoreOpts...); diff != "" { 223 t.Errorf("Seal/Unseal()\n-got/+want\ndiff %s", diff) 224 } 225 } 226 227 func Test_Seal_Unseal_WithPSK(t *testing.T) { 228 psk := memguard.NewBufferRandom(64) 229 adapter := New() 230 231 publicKey1, privateKey1, err := adapter.GenerateKey() 232 assert.NoError(t, err) 233 234 input := &containerv1.Container{ 235 Headers: &containerv1.Header{ 236 ContentEncoding: "gzip", 237 ContentType: "application/vnd.harp.v1.Bundle", 238 }, 239 Raw: memguard.NewBufferRandom(1024).Bytes(), 240 } 241 242 sealed, err := adapter.SealWithPSK(rand.Reader, input, psk, publicKey1) 243 if err != nil { 244 t.Fatalf("unable to seal container: %v", err) 245 } 246 247 unsealed, err := adapter.UnsealWithPSK(sealed, memguard.NewBufferFromBytes([]byte(privateKey1)), psk) 248 if err != nil { 249 t.Fatalf("unable to unseal container: %v", err) 250 } 251 252 if diff := cmp.Diff(unsealed, input, ignoreOpts...); diff != "" { 253 t.Errorf("Seal/Unseal()\n-got/+want\ndiff %s", diff) 254 } 255 } 256 257 func Test_Seal_Fuzz(t *testing.T) { 258 adapter := New() 259 260 // Making sure the function never panics 261 for i := 0; i < 500; i++ { 262 f := fuzz.New() 263 264 // Prepare arguments 265 var publicKey string 266 input := containerv1.Container{ 267 Headers: &containerv1.Header{}, 268 Raw: []byte{0x00, 0x00}, 269 } 270 271 f.Fuzz(&input.Headers) 272 f.Fuzz(&input.Raw) 273 f.Fuzz(&publicKey) 274 275 // Execute 276 adapter.Seal(rand.Reader, &input, publicKey) 277 } 278 } 279 280 func Test_UnSeal_Fuzz(t *testing.T) { 281 // Memguard buffer is excluded from fuzz for random race condition error 282 // investigation will be done in a separated thread. 283 identity := memguard.NewBufferRandom(32) 284 285 adapter := New() 286 287 // Making sure the function never panics 288 for i := 0; i < 500; i++ { 289 f := fuzz.New() 290 291 // Prepare arguments 292 input := containerv1.Container{ 293 Headers: &containerv1.Header{}, 294 Raw: []byte{0x00, 0x00}, 295 } 296 297 f.Fuzz(&input.Headers) 298 f.Fuzz(&input.Raw) 299 300 // Execute 301 adapter.Unseal(&input, identity) 302 } 303 } 304 305 // -----------------------------------------------------------------------------. 306 func benchmarkSeal(container *containerv1.Container, peersPublicKeys []string, b *testing.B) { 307 adapter := New() 308 for n := 0; n < b.N; n++ { 309 _, err := adapter.Seal(rand.Reader, container, peersPublicKeys...) 310 if err != nil { 311 b.Fatal(err) 312 } 313 } 314 } 315 316 func Benchmark_Seal(b *testing.B) { 317 publicKey, _, err := New().GenerateKey() 318 assert.NoError(b, err) 319 320 input := &containerv1.Container{ 321 Headers: &containerv1.Header{ 322 ContentEncoding: "gzip", 323 ContentType: "application/vnd.harp.v1.Bundle", 324 }, 325 Raw: make([]byte, 1024), 326 } 327 328 benchmarkSeal(input, []string{publicKey}, b) 329 }