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  }