github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/s3crypto/decryption_client_v2_test.go (about) 1 //go:build go1.7 2 // +build go1.7 3 4 package s3crypto_test 5 6 import ( 7 "bytes" 8 "encoding/hex" 9 "fmt" 10 "io/ioutil" 11 "net/http" 12 "net/http/httptest" 13 "strings" 14 "testing" 15 16 "github.com/aavshr/aws-sdk-go/aws" 17 "github.com/aavshr/aws-sdk-go/aws/request" 18 "github.com/aavshr/aws-sdk-go/awstesting/unit" 19 "github.com/aavshr/aws-sdk-go/service/kms" 20 "github.com/aavshr/aws-sdk-go/service/s3" 21 "github.com/aavshr/aws-sdk-go/service/s3/s3crypto" 22 ) 23 24 func TestDecryptionClientV2_CheckDeprecatedFeatures(t *testing.T) { 25 // AES/GCM/NoPadding with kms+context => allowed 26 builder := s3crypto.AESGCMContentCipherBuilderV2(s3crypto.NewKMSContextKeyGenerator(kms.New(unit.Session), "cmkID", s3crypto.MaterialDescription{})) 27 _, err := s3crypto.NewEncryptionClientV2(unit.Session, builder) 28 if err != nil { 29 t.Errorf("expected no error, got %v", err) 30 } 31 32 // AES/GCM/NoPadding with kms => not allowed 33 builder = s3crypto.AESGCMContentCipherBuilder(s3crypto.NewKMSKeyGenerator(kms.New(unit.Session), "cmkID")) 34 _, err = s3crypto.NewEncryptionClientV2(unit.Session, builder) 35 if err == nil { 36 t.Error("expected error, but got nil") 37 } 38 39 // AES/CBC/PKCS5Padding with kms => not allowed 40 builder = s3crypto.AESCBCContentCipherBuilder(s3crypto.NewKMSKeyGenerator(kms.New(unit.Session), "cmkID"), s3crypto.NewPKCS7Padder(128)) 41 _, err = s3crypto.NewEncryptionClientV2(unit.Session, builder) 42 if err == nil { 43 t.Error("expected error, but got nil") 44 } 45 } 46 47 func TestDecryptionClientV2_GetObject(t *testing.T) { 48 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 49 fmt.Fprintln(w, fmt.Sprintf("%s%s%s", `{"KeyId":"test-key-id","Plaintext":"`, "hJUv7S6K2cHF64boS9ixHX0TZAjBZLT4ZpEO4XxkGnY=", `"}`)) 50 })) 51 defer ts.Close() 52 53 kmsClient := kms.New(unit.Session.Copy(&aws.Config{Endpoint: &ts.URL})) 54 55 cr := s3crypto.NewCryptoRegistry() 56 if err := s3crypto.RegisterKMSContextWrapWithAnyCMK(cr, kmsClient); err != nil { 57 t.Fatalf("expected no error, got %v", err) 58 } 59 if err := s3crypto.RegisterAESGCMContentCipher(cr); err != nil { 60 t.Fatalf("expected no error, got %v", err) 61 } 62 63 c, err := s3crypto.NewDecryptionClientV2(unit.Session.Copy(), cr) 64 if err != nil { 65 t.Fatalf("expected no error, got %v", err) 66 } 67 68 input := &s3.GetObjectInput{ 69 Bucket: aws.String("test"), 70 Key: aws.String("test"), 71 } 72 73 req, out := c.GetObjectRequest(input) 74 req.Handlers.Send.Clear() 75 req.Handlers.Send.PushBack(func(r *request.Request) { 76 b, err := hex.DecodeString("6b134eb7a353131de92faff64f594b2794e3544e31776cca26fe3bbeeffc68742d1007234f11c6670522602326868e29f37e9d2678f1614ec1a2418009b9772100929aadbed9a21a") 77 if err != nil { 78 t.Errorf("expected no error, but received %v", err) 79 } 80 81 r.HTTPResponse = &http.Response{ 82 StatusCode: 200, 83 Header: http.Header{ 84 http.CanonicalHeaderKey("x-amz-meta-x-amz-key-v2"): []string{"PsuclPnlo2O0MQoov6kL1TBlaZG6oyNwWuAqmAgq7g8b9ZeeORi3VTMg624FU9jx"}, 85 http.CanonicalHeaderKey("x-amz-meta-x-amz-iv"): []string{"dqqlq2dRVSQ5hFRb"}, 86 http.CanonicalHeaderKey("x-amz-meta-x-amz-matdesc"): []string{`{"aws:x-amz-cek-alg":"AES/GCM/NoPadding"}`}, 87 http.CanonicalHeaderKey("x-amz-meta-x-amz-wrap-alg"): []string{s3crypto.KMSContextWrap}, 88 http.CanonicalHeaderKey("x-amz-meta-x-amz-cek-alg"): []string{"AES/GCM/NoPadding"}, 89 }, 90 Body: ioutil.NopCloser(bytes.NewBuffer(b)), 91 } 92 }) 93 err = req.Send() 94 if err != nil { 95 t.Fatalf("expected no error, got %v", err) 96 } 97 98 actual, err := ioutil.ReadAll(out.Body) 99 if err != nil { 100 t.Fatalf("expected no error, got %v", err) 101 } 102 103 expected, err := hex.DecodeString("af150d7156bf5b3f5c461e5c6ac820acc5a33aab7085d920666c250ff251209d5a4029b3bd78250fab6e11aed52fae948d407056a9519b68") 104 if err != nil { 105 t.Fatalf("expected no error, got %v", err) 106 } 107 108 if bytes.Compare(expected, actual) != 0 { 109 t.Fatalf("expected content to match but it did not") 110 } 111 } 112 113 func TestDecryptionClientV2_GetObject_V1Interop_KMS_AESCBC(t *testing.T) { 114 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 115 fmt.Fprintln(w, fmt.Sprintf("%s%s%s", `{"KeyId":"test-key-id","Plaintext":"`, "7ItX9CTGNWWegC62RlaNu6EJ3+J9yGO7yAqDNU4CdeA=", `"}`)) 116 })) 117 defer ts.Close() 118 119 kmsClient := kms.New(unit.Session.Copy(&aws.Config{Endpoint: &ts.URL})) 120 121 cr := s3crypto.NewCryptoRegistry() 122 if err := s3crypto.RegisterKMSWrapWithAnyCMK(cr, kmsClient); err != nil { 123 t.Fatalf("expected no error, got %v", err) 124 } 125 if err := s3crypto.RegisterAESCBCContentCipher(cr, s3crypto.AESCBCPadder); err != nil { 126 t.Fatalf("expected no error, got %v", err) 127 } 128 129 c, err := s3crypto.NewDecryptionClientV2(unit.Session.Copy(), cr) 130 if err != nil { 131 t.Fatalf("expected no error, got %v", err) 132 } 133 134 input := &s3.GetObjectInput{ 135 Bucket: aws.String("test"), 136 Key: aws.String("test"), 137 } 138 139 req, out := c.GetObjectRequest(input) 140 req.Handlers.Send.Clear() 141 req.Handlers.Send.PushBack(func(r *request.Request) { 142 b, err := hex.DecodeString("6f4f413a357a3c3a12289442fb835c5e4ecc8db1d86d3d1eab906ce07e1ad772180b2e9ec49c3fc667d8aceea8c46da6bb9738251a8e36241a473ad820f99c701906bac1f48578d5392e928889bbb1d9") 143 if err != nil { 144 t.Errorf("expected no error, but received %v", err) 145 } 146 147 r.HTTPResponse = &http.Response{ 148 StatusCode: 200, 149 Header: http.Header{ 150 http.CanonicalHeaderKey("x-amz-meta-x-amz-key-v2"): []string{"/nJlgMtxMNk2ErKLLrLp3H7A7aQyJcJOClE2ldAIIFNZU4OhUMc1mMCHdIEC8fby"}, 151 http.CanonicalHeaderKey("x-amz-meta-x-amz-iv"): []string{"adO9U7pcEHxUTaguIkho9g=="}, 152 http.CanonicalHeaderKey("x-amz-meta-x-amz-matdesc"): []string{`{"kms_cmk_id":"test-key-id"}`}, 153 http.CanonicalHeaderKey("x-amz-meta-x-amz-wrap-alg"): []string{s3crypto.KMSWrap}, 154 http.CanonicalHeaderKey("x-amz-meta-x-amz-cek-alg"): []string{"AES/CBC/PKCS5Padding"}, 155 }, 156 Body: ioutil.NopCloser(bytes.NewBuffer(b)), 157 } 158 }) 159 err = req.Send() 160 if err != nil { 161 t.Fatalf("expected no error, got %v", err) 162 } 163 164 actual, err := ioutil.ReadAll(out.Body) 165 if err != nil { 166 t.Fatalf("expected no error, got %v", err) 167 } 168 169 expected, err := hex.DecodeString("a716e018ffecf4bb94d4352082af4662612d9c225efed6f389bf1f6f0447a9bce80cc712d7e66ee5e1c086af38e607ead351fd2c1a0247878e693ada73bd580b") 170 if err != nil { 171 t.Fatalf("expected no error, got %v", err) 172 } 173 174 if bytes.Compare(expected, actual) != 0 { 175 t.Fatalf("expected content to match but it did not") 176 } 177 } 178 179 func TestDecryptionClientV2_GetObject_V1Interop_KMS_AESGCM(t *testing.T) { 180 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 181 fmt.Fprintln(w, fmt.Sprintf("%s%s%s", `{"KeyId":"test-key-id","Plaintext":"`, "Hrjrkkt/vQwMYtqvK6+MiXh3xiMvviL1Ks7w2mgsJgU=", `"}`)) 182 })) 183 defer ts.Close() 184 185 kmsClient := kms.New(unit.Session.Copy(&aws.Config{Endpoint: &ts.URL})) 186 187 cr := s3crypto.NewCryptoRegistry() 188 if err := s3crypto.RegisterKMSWrapWithAnyCMK(cr, kmsClient); err != nil { 189 t.Fatalf("expected no error, got %v", err) 190 } 191 if err := s3crypto.RegisterAESGCMContentCipher(cr); err != nil { 192 t.Fatalf("expected no error, got %v", err) 193 } 194 195 c, err := s3crypto.NewDecryptionClientV2(unit.Session.Copy(), cr) 196 if err != nil { 197 t.Fatalf("expected no error, got %v", err) 198 } 199 200 input := &s3.GetObjectInput{ 201 Bucket: aws.String("test"), 202 Key: aws.String("test"), 203 } 204 205 req, out := c.GetObjectRequest(input) 206 req.Handlers.Send.Clear() 207 req.Handlers.Send.PushBack(func(r *request.Request) { 208 b, err := hex.DecodeString("6370a90b9a118301c2160c23a90d96146761276acdcfa92e6cbcb783abdc2e1813891506d6850754ef87ed2ac3bf570dd5c9da9492b7769ae1e639d073d688bd284815404ce2648a") 209 if err != nil { 210 t.Errorf("expected no error, but received %v", err) 211 } 212 213 r.HTTPResponse = &http.Response{ 214 StatusCode: 200, 215 Header: http.Header{ 216 http.CanonicalHeaderKey("x-amz-meta-x-amz-key-v2"): []string{"/7tu/RFXZU1UFwRzzf11IdF3b1wBxBZhnUMjVYHKKr5DjAHS602GvXt4zYcx/MJo"}, 217 http.CanonicalHeaderKey("x-amz-meta-x-amz-iv"): []string{"8Rlvyy8AoYj8v579"}, 218 http.CanonicalHeaderKey("x-amz-meta-x-amz-matdesc"): []string{`{"kms_cmk_id":"test-key-id"}`}, 219 http.CanonicalHeaderKey("x-amz-meta-x-amz-wrap-alg"): []string{s3crypto.KMSWrap}, 220 http.CanonicalHeaderKey("x-amz-meta-x-amz-cek-alg"): []string{"AES/GCM/NoPadding"}, 221 }, 222 Body: ioutil.NopCloser(bytes.NewBuffer(b)), 223 } 224 }) 225 err = req.Send() 226 if err != nil { 227 t.Fatalf("expected no error, got %v", err) 228 } 229 230 actual, err := ioutil.ReadAll(out.Body) 231 if err != nil { 232 t.Fatalf("expected no error, got %v", err) 233 } 234 235 expected, err := hex.DecodeString("75f6805afa7d7be4f56c5906adc27a5959158bf4af6e7c7e12bda3458300f6b1c8daaf9a5949f7a6bdbb8a9c072de05bf0541633421f42f8") 236 if err != nil { 237 t.Fatalf("expected no error, got %v", err) 238 } 239 240 if bytes.Compare(expected, actual) != 0 { 241 t.Fatalf("expected content to match but it did not") 242 } 243 } 244 245 func TestDecryptionClientV2_GetObject_OnlyDecryptsRegisteredAlgorithms(t *testing.T) { 246 dataHandler := func(r *request.Request) { 247 b, err := hex.DecodeString("1bd0271b25951fdef3dbe51a9b7af85f66b311e091aa10a346655068f657b9da9acc0843ea0522b0d1ae4a25a31b13605dd1ac5d002db8965d9d4652fd602693") 248 if err != nil { 249 t.Errorf("expected no error, but received %v", err) 250 } 251 252 r.HTTPResponse = &http.Response{ 253 StatusCode: 200, 254 Header: http.Header{ 255 http.CanonicalHeaderKey("x-amz-meta-x-amz-key-v2"): []string{"gNuYjzkLTzfhOcIX9h1l8jApWcAAQqzlryOE166kdDojaHH/+7cCqR5HU8Bpxmij"}, 256 http.CanonicalHeaderKey("x-amz-meta-x-amz-iv"): []string{"Vmauu+TMEgaXa26ObqpARA=="}, 257 http.CanonicalHeaderKey("x-amz-meta-x-amz-matdesc"): []string{`{"kms_cmk_id":"test-key-id"}`}, 258 http.CanonicalHeaderKey("x-amz-meta-x-amz-wrap-alg"): []string{s3crypto.KMSWrap}, 259 http.CanonicalHeaderKey("x-amz-meta-x-amz-cek-alg"): []string{"AES/CBC/PKCS5Padding"}, 260 }, 261 Body: ioutil.NopCloser(bytes.NewBuffer(b)), 262 } 263 } 264 265 cases := map[string]struct { 266 Client *s3crypto.DecryptionClientV2 267 WantErr string 268 }{ 269 "unsupported wrap": { 270 Client: func() *s3crypto.DecryptionClientV2 { 271 cr := s3crypto.NewCryptoRegistry() 272 if err := s3crypto.RegisterKMSContextWrapWithAnyCMK(cr, kms.New(unit.Session.Copy())); err != nil { 273 t.Fatalf("expected no error, got %v", err) 274 } 275 if err := s3crypto.RegisterAESGCMContentCipher(cr); err != nil { 276 t.Fatalf("expected no error, got %v", err) 277 } 278 279 c, err := s3crypto.NewDecryptionClientV2(unit.Session.Copy(), cr) 280 if err != nil { 281 t.Fatalf("expected no error, got %v", err) 282 } 283 return c 284 }(), 285 WantErr: "wrap algorithm isn't supported, kms", 286 }, 287 "unsupported cek": { 288 Client: func() *s3crypto.DecryptionClientV2 { 289 cr := s3crypto.NewCryptoRegistry() 290 if err := s3crypto.RegisterKMSWrapWithAnyCMK(cr, kms.New(unit.Session.Copy())); err != nil { 291 t.Fatalf("expected no error, got %v", err) 292 } 293 if err := s3crypto.RegisterAESGCMContentCipher(cr); err != nil { 294 t.Fatalf("expected no error, got %v", err) 295 } 296 c, err := s3crypto.NewDecryptionClientV2(unit.Session.Copy(), cr) 297 if err != nil { 298 t.Fatalf("expected no error, got %v", err) 299 } 300 return c 301 }(), 302 WantErr: "cek algorithm isn't supported, AES/CBC/PKCS5Padding", 303 }, 304 } 305 306 for name, tt := range cases { 307 t.Run(name, func(t *testing.T) { 308 input := &s3.GetObjectInput{ 309 Bucket: aws.String("test"), 310 Key: aws.String("test"), 311 } 312 req, _ := tt.Client.GetObjectRequest(input) 313 req.Handlers.Send.Clear() 314 req.Handlers.Send.PushBack(dataHandler) 315 err := req.Send() 316 if err == nil { 317 t.Fatalf("expected error, got none") 318 } 319 if e, a := tt.WantErr, err.Error(); !strings.Contains(a, e) { 320 t.Errorf("expected %v, got %v", e, a) 321 } 322 }) 323 } 324 } 325 326 func TestDecryptionClientV2_CheckValidCryptoRegistry(t *testing.T) { 327 cr := s3crypto.NewCryptoRegistry() 328 _, err := s3crypto.NewDecryptionClientV2(unit.Session.Copy(), cr) 329 if err == nil { 330 t.Fatal("expected error, got none") 331 } 332 if e, a := "at least one key wrapping algorithms must be provided", err.Error(); !strings.Contains(a, e) { 333 t.Fatalf("expected %v, got %v", e, a) 334 } 335 }