diff --git a/go.mod b/go.mod index dc58c086..9fba2782 100644 --- a/go.mod +++ b/go.mod @@ -62,6 +62,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/mattn/go-ieproxy v0.0.0-20190805055040-f9202b1cfdeb // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/s3ext/go.mod b/s3ext/go.mod index 970411dc..eabf5e45 100644 --- a/s3ext/go.mod +++ b/s3ext/go.mod @@ -2,7 +2,6 @@ module github.com/aws/aws-sdk-go require ( github.com/jmespath/go-jmespath v0.4.0 - github.com/pkg/errors v0.9.1 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b ) diff --git a/s3ext/go.sum b/s3ext/go.sum index 9f573631..ea27481a 100644 --- a/s3ext/go.sum +++ b/s3ext/go.sum @@ -1,8 +1,10 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -14,7 +16,10 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/s3ext/service/s3/s3crypto/decryption_client.go b/s3ext/service/s3/s3crypto/decryption_client.go deleted file mode 100644 index 5911b349..00000000 --- a/s3ext/service/s3/s3crypto/decryption_client.go +++ /dev/null @@ -1,126 +0,0 @@ -package s3crypto - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/kms" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" -) - -// WrapEntry is builder that return a proper key decrypter and error -type WrapEntry func(Envelope) (CipherDataDecrypter, error) - -// CEKEntry is a builder that returns a proper content decrypter and error -type CEKEntry func(CipherData) (ContentCipher, error) - -// DecryptionClient is an S3 crypto client. The decryption client -// will handle all get object requests from Amazon S3. -// Supported key wrapping algorithms: -// *AWS KMS -// -// Supported content ciphers: -// * AES/GCM -// * AES/CBC -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -type DecryptionClient struct { - S3Client s3iface.S3API - // LoadStrategy is used to load the metadata either from the metadata of the object - // or from a separate file in s3. - // - // Defaults to our default load strategy. - LoadStrategy LoadStrategy - - WrapRegistry map[string]WrapEntry - CEKRegistry map[string]CEKEntry - PadderRegistry map[string]Padder -} - -// NewDecryptionClient instantiates a new S3 crypto client -// -// Example: -// sess := session.Must(session.NewSession()) -// svc := s3crypto.NewDecryptionClient(sess, func(svc *s3crypto.DecryptionClient{ -// // Custom client options here -// })) -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func NewDecryptionClient(prov client.ConfigProvider, options ...func(*DecryptionClient)) *DecryptionClient { - s3client := s3.New(prov) - - s3client.Handlers.Build.PushBack(func(r *request.Request) { - request.AddToUserAgent(r, "S3CryptoV1n") - }) - - kmsClient := kms.New(prov) - client := &DecryptionClient{ - S3Client: s3client, - LoadStrategy: defaultV2LoadStrategy{ - client: s3client, - }, - WrapRegistry: map[string]WrapEntry{ - KMSWrap: NewKMSWrapEntry(kmsClient), - KMSContextWrap: newKMSContextWrapEntryWithAnyCMK(kmsClient), - }, - CEKRegistry: map[string]CEKEntry{ - AESGCMNoPadding: newAESGCMContentCipher, - AESCBC + "/" + AESCBCPadder.Name(): newAESCBCContentCipher, - }, - PadderRegistry: map[string]Padder{ - AESCBC + "/" + AESCBCPadder.Name(): AESCBCPadder, - NoPadder.Name(): NoPadder, - }, - } - for _, option := range options { - option(client) - } - - return client -} - -// GetObjectRequest will make a request to s3 and retrieve the object. In this process -// decryption will be done. The SDK only supports V2 reads of KMS and GCM. -// -// Example: -// sess := session.Must(session.NewSession()) -// svc := s3crypto.NewDecryptionClient(sess) -// req, out := svc.GetObjectRequest(&s3.GetObjectInput { -// Key: aws.String("testKey"), -// Bucket: aws.String("testBucket"), -// }) -// err := req.Send() -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func (c *DecryptionClient) GetObjectRequest(input *s3.GetObjectInput) (*request.Request, *s3.GetObjectOutput) { - return getObjectRequest(c.getClientOptions(), input) -} - -// GetObject is a wrapper for GetObjectRequest -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func (c *DecryptionClient) GetObject(input *s3.GetObjectInput) (*s3.GetObjectOutput, error) { - return getObject(c.getClientOptions(), input) -} - -// GetObjectWithContext is a wrapper for GetObjectRequest with the additional -// context, and request options support. -// -// GetObjectWithContext is the same as GetObject with the additional support for -// Context input parameters. The Context must not be nil. A nil Context will -// cause a panic. Use the Context to add deadlining, timeouts, etc. In the future -// this may create sub-contexts for individual underlying requests. -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func (c *DecryptionClient) GetObjectWithContext(ctx aws.Context, input *s3.GetObjectInput, opts ...request.Option) (*s3.GetObjectOutput, error) { - return getObjectWithContext(c.getClientOptions(), ctx, input, opts...) -} - -func (c *DecryptionClient) getClientOptions() DecryptionClientOptions { - return DecryptionClientOptions{ - S3Client: c.S3Client, - LoadStrategy: c.LoadStrategy, - CryptoRegistry: initCryptoRegistryFrom(c.WrapRegistry, c.CEKRegistry, c.PadderRegistry), - } -} diff --git a/s3ext/service/s3/s3crypto/kms_context_key_handler.go b/s3ext/service/s3/s3crypto/kms_context_key_handler.go deleted file mode 100644 index 86f3572f..00000000 --- a/s3ext/service/s3/s3crypto/kms_context_key_handler.go +++ /dev/null @@ -1,199 +0,0 @@ -package s3crypto - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/kms" - "github.com/aws/aws-sdk-go/service/kms/kmsiface" -) - -const ( - // KMSContextWrap is a constant used during decryption to build a kms+context key handler - KMSContextWrap = "kms+context" - kmsAWSCEKContextKey = "aws:" + cekAlgorithmHeader - - kmsReservedKeyConflictErrMsg = "conflict in reserved KMS Encryption Context key %s. This value is reserved for the S3 Encryption Client and cannot be set by the user" - kmsMismatchCEKAlg = "the content encryption algorithm used at encryption time does not match the algorithm stored for decryption time. The object may be altered or corrupted" -) - -// NewKMSContextKeyGenerator builds a new kms+context key provider using the customer key ID and material -// description. -// -// Example: -// sess := session.Must(session.NewSession()) -// cmkID := "KMS Key ARN" -// var matdesc s3crypto.MaterialDescription -// handler := s3crypto.NewKMSContextKeyGenerator(kms.New(sess), cmkID, matdesc) -func NewKMSContextKeyGenerator(client kmsiface.KMSAPI, cmkID string, matdesc MaterialDescription) CipherDataGeneratorWithCEKAlg { - return newKMSContextKeyHandler(client, cmkID, matdesc) -} - -// RegisterKMSContextWrapWithCMK registers the kms+context wrapping algorithm to the given WrapRegistry. The wrapper -// will be configured to only call KMS Decrypt using the provided CMK. -// -// Example: -// cr := s3crypto.NewCryptoRegistry() -// if err := RegisterKMSContextWrapWithCMK(); err != nil { -// panic(err) // handle error -// } -func RegisterKMSContextWrapWithCMK(registry *CryptoRegistry, client kmsiface.KMSAPI, cmkID string) error { - if registry == nil { - return errNilCryptoRegistry - } - return registry.AddWrap(KMSContextWrap, newKMSContextWrapEntryWithCMK(client, cmkID)) -} - -// RegisterKMSContextWrapWithAnyCMK registers the kms+context wrapping algorithm to the given WrapRegistry. The wrapper -// will be configured to call KMS decrypt without providing a CMK. -// -// Example: -// sess := session.Must(session.NewSession()) -// cr := s3crypto.NewCryptoRegistry() -// if err := s3crypto.RegisterKMSContextWrapWithAnyCMK(cr, kms.New(sess)); err != nil { -// panic(err) // handle error -// } -func RegisterKMSContextWrapWithAnyCMK(registry *CryptoRegistry, client kmsiface.KMSAPI) error { - if registry == nil { - return errNilCryptoRegistry - } - return registry.AddWrap(KMSContextWrap, newKMSContextWrapEntryWithAnyCMK(client)) -} - -// newKMSContextWrapEntryWithCMK builds returns a new kms+context key provider and its decrypt handler. -// The returned handler will be configured to calls KMS Decrypt API without specifying a specific KMS CMK. -func newKMSContextWrapEntryWithCMK(kmsClient kmsiface.KMSAPI, cmkID string) WrapEntry { - // These values are read only making them thread safe - kp := &kmsContextKeyHandler{ - kms: kmsClient, - cmkID: &cmkID, - } - - return kp.decryptHandler -} - -// newKMSContextWrapEntryWithAnyCMK builds returns a new kms+context key provider and its decrypt handler. -// The returned handler will be configured to calls KMS Decrypt API without specifying a specific KMS CMK. -func newKMSContextWrapEntryWithAnyCMK(kmsClient kmsiface.KMSAPI) WrapEntry { - // These values are read only making them thread safe - kp := &kmsContextKeyHandler{ - kms: kmsClient, - } - - return kp.decryptHandler -} - -// kmsContextKeyHandler wraps the kmsKeyHandler to explicitly make this type incompatible with the v1 client -// by not exposing the old interface implementations. -type kmsContextKeyHandler struct { - kms kmsiface.KMSAPI - cmkID *string - - CipherData -} - -func (kp *kmsContextKeyHandler) isAWSFixture() bool { - return true -} - -func newKMSContextKeyHandler(client kmsiface.KMSAPI, cmkID string, matdesc MaterialDescription) *kmsContextKeyHandler { - kp := &kmsContextKeyHandler{ - kms: client, - cmkID: &cmkID, - } - - if matdesc == nil { - matdesc = MaterialDescription{} - } - - kp.CipherData.WrapAlgorithm = KMSContextWrap - kp.CipherData.MaterialDescription = matdesc - - return kp -} - -func (kp *kmsContextKeyHandler) GenerateCipherDataWithCEKAlg(ctx aws.Context, keySize int, ivSize int, cekAlgorithm string) (CipherData, error) { - cd := kp.CipherData.Clone() - - if len(cekAlgorithm) == 0 { - return CipherData{}, fmt.Errorf("cek algorithm identifier must not be empty") - } - - if _, ok := cd.MaterialDescription[kmsAWSCEKContextKey]; ok { - return CipherData{}, fmt.Errorf(kmsReservedKeyConflictErrMsg, kmsAWSCEKContextKey) - } - cd.MaterialDescription[kmsAWSCEKContextKey] = &cekAlgorithm - - out, err := kp.kms.GenerateDataKeyWithContext(ctx, - &kms.GenerateDataKeyInput{ - EncryptionContext: cd.MaterialDescription, - KeyId: kp.cmkID, - KeySpec: aws.String("AES_256"), - }) - if err != nil { - return CipherData{}, err - } - - iv, err := generateBytes(ivSize) - if err != nil { - return CipherData{}, err - } - - cd.Key = out.Plaintext - cd.IV = iv - cd.EncryptedKey = out.CiphertextBlob - - return cd, nil -} - -// decryptHandler initializes a KMS keyprovider with a material description. This -// is used with Decrypting kms content, due to the cmkID being in the material description. -func (kp kmsContextKeyHandler) decryptHandler(env Envelope) (CipherDataDecrypter, error) { - if env.WrapAlg != KMSContextWrap { - return nil, fmt.Errorf("%s value `%s` did not match the expected algorithm `%s` for this handler", cekAlgorithmHeader, env.WrapAlg, KMSContextWrap) - } - - m := MaterialDescription{} - err := m.decodeDescription([]byte(env.MatDesc)) - if err != nil { - return nil, err - } - - if v, ok := m[kmsAWSCEKContextKey]; !ok { - return nil, fmt.Errorf("required key %v is missing from encryption context", kmsAWSCEKContextKey) - } else if v == nil || *v != env.CEKAlg { - return nil, fmt.Errorf(kmsMismatchCEKAlg) - } - - kp.MaterialDescription = m - kp.WrapAlgorithm = KMSContextWrap - - return &kp, nil -} - -// DecryptKey makes a call to KMS to decrypt the key. -func (kp *kmsContextKeyHandler) DecryptKey(key []byte) ([]byte, error) { - return kp.DecryptKeyWithContext(aws.BackgroundContext(), key) -} - -// DecryptKeyWithContext makes a call to KMS to decrypt the key with request context. -func (kp *kmsContextKeyHandler) DecryptKeyWithContext(ctx aws.Context, key []byte) ([]byte, error) { - out, err := kp.kms.DecryptWithContext(ctx, - &kms.DecryptInput{ - KeyId: kp.cmkID, // will be nil and not serialized if created with the AnyCMK constructor - EncryptionContext: kp.MaterialDescription, - CiphertextBlob: key, - GrantTokens: []*string{}, - }) - if err != nil { - return nil, err - } - return out.Plaintext, nil -} - -var ( - _ CipherDataGeneratorWithCEKAlg = (*kmsContextKeyHandler)(nil) - _ CipherDataDecrypter = (*kmsContextKeyHandler)(nil) - _ CipherDataDecrypterWithContext = (*kmsContextKeyHandler)(nil) - _ awsFixture = (*kmsContextKeyHandler)(nil) -) diff --git a/s3ext/service/s3/s3crypto/kms_key_handler.go b/s3ext/service/s3/s3crypto/kms_key_handler.go deleted file mode 100644 index 44d40f12..00000000 --- a/s3ext/service/s3/s3crypto/kms_key_handler.go +++ /dev/null @@ -1,232 +0,0 @@ -package s3crypto - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/kms" - "github.com/aws/aws-sdk-go/service/kms/kmsiface" -) - -const ( - // KMSWrap is a constant used during decryption to build a KMS key handler. - KMSWrap = "kms" -) - -// kmsKeyHandler will make calls to KMS to get the masterkey -type kmsKeyHandler struct { - kms kmsiface.KMSAPI - cmkID *string - - // useProvidedCMK is toggled when using `kms` key wrapper with V2 client - useProvidedCMK bool - - CipherData -} - -// NewKMSKeyGenerator builds a new KMS key provider using the customer key ID and material -// description. -// -// Example: -// sess := session.Must(session.NewSession()) -// cmkID := "arn to key" -// matdesc := s3crypto.MaterialDescription{} -// handler := s3crypto.NewKMSKeyGenerator(kms.New(sess), cmkID) -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func NewKMSKeyGenerator(kmsClient kmsiface.KMSAPI, cmkID string) CipherDataGenerator { - return NewKMSKeyGeneratorWithMatDesc(kmsClient, cmkID, MaterialDescription{}) -} - -func newKMSKeyHandler(client kmsiface.KMSAPI, cmkID string, matdesc MaterialDescription) *kmsKeyHandler { - // These values are read only making them thread safe - kp := &kmsKeyHandler{ - kms: client, - cmkID: &cmkID, - } - - if matdesc == nil { - matdesc = MaterialDescription{} - } - - matdesc["kms_cmk_id"] = &cmkID - - kp.CipherData.WrapAlgorithm = KMSWrap - kp.CipherData.MaterialDescription = matdesc - - return kp -} - -// NewKMSKeyGeneratorWithMatDesc builds a new KMS key provider using the customer key ID and material -// description. -// -// Example: -// sess := session.Must(session.NewSession()) -// cmkID := "arn to key" -// matdesc := s3crypto.MaterialDescription{} -// handler := s3crypto.NewKMSKeyGeneratorWithMatDesc(kms.New(sess), cmkID, matdesc) -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func NewKMSKeyGeneratorWithMatDesc(kmsClient kmsiface.KMSAPI, cmkID string, matdesc MaterialDescription) CipherDataGenerator { - return newKMSKeyHandler(kmsClient, cmkID, matdesc) -} - -// NewKMSWrapEntry builds returns a new KMS key provider and its decrypt handler. -// -// Example: -// sess := session.Must(session.NewSession()) -// customKMSClient := kms.New(sess) -// decryptHandler := s3crypto.NewKMSWrapEntry(customKMSClient) -// -// svc := s3crypto.NewDecryptionClient(sess, func(svc *s3crypto.DecryptionClient) { -// svc.WrapRegistry[s3crypto.KMSWrap] = decryptHandler -// })) -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func NewKMSWrapEntry(kmsClient kmsiface.KMSAPI) WrapEntry { - kp := newKMSWrapEntry(kmsClient) - return kp.decryptHandler -} - -// RegisterKMSWrapWithCMK registers the `kms` wrapping algorithm to the given WrapRegistry. The wrapper will be -// configured to call KMS Decrypt with the provided CMK. -// -// Example: -// sess := session.Must(session.NewSession()) -// cr := s3crypto.NewCryptoRegistry() -// if err := s3crypto.RegisterKMSWrapWithCMK(cr, kms.New(sess), "cmkId"); err != nil { -// panic(err) // handle error -// } -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func RegisterKMSWrapWithCMK(registry *CryptoRegistry, client kmsiface.KMSAPI, cmkID string) error { - if registry == nil { - return errNilCryptoRegistry - } - return registry.AddWrap(KMSWrap, newKMSWrapEntryWithCMK(client, cmkID)) -} - -// RegisterKMSWrapWithAnyCMK registers the `kms` wrapping algorithm to the given WrapRegistry. The wrapper will be -// configured to call KMS Decrypt without providing a CMK. -// -// Example: -// sess := session.Must(session.NewSession()) -// cr := s3crypto.NewCryptoRegistry() -// if err := s3crypto.RegisterKMSWrapWithAnyCMK(cr, kms.New(sess)); err != nil { -// panic(err) // handle error -// } -// -// deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information. -func RegisterKMSWrapWithAnyCMK(registry *CryptoRegistry, client kmsiface.KMSAPI) error { - if registry == nil { - return errNilCryptoRegistry - } - return registry.AddWrap(KMSWrap, NewKMSWrapEntry(client)) -} - -// newKMSWrapEntryWithCMK builds returns a new KMS key provider and its decrypt handler. The wrap entry will be configured -// to only attempt to decrypt the data key using the provided CMK. -func newKMSWrapEntryWithCMK(kmsClient kmsiface.KMSAPI, cmkID string) WrapEntry { - kp := newKMSWrapEntry(kmsClient) - kp.useProvidedCMK = true - kp.cmkID = &cmkID - return kp.decryptHandler -} - -func newKMSWrapEntry(kmsClient kmsiface.KMSAPI) *kmsKeyHandler { - // These values are read only making them thread safe - kp := &kmsKeyHandler{ - kms: kmsClient, - } - - return kp -} - -// decryptHandler initializes a KMS keyprovider with a material description. This -// is used with Decrypting kms content, due to the cmkID being in the material description. -func (kp kmsKeyHandler) decryptHandler(env Envelope) (CipherDataDecrypter, error) { - m := MaterialDescription{} - err := m.decodeDescription([]byte(env.MatDesc)) - if err != nil { - return nil, err - } - - _, ok := m["kms_cmk_id"] - if !ok { - return nil, awserr.New("MissingCMKIDError", "Material description is missing CMK ID", nil) - } - - kp.CipherData.MaterialDescription = m - kp.WrapAlgorithm = KMSWrap - - return &kp, nil -} - -// DecryptKey makes a call to KMS to decrypt the key. -func (kp *kmsKeyHandler) DecryptKey(key []byte) ([]byte, error) { - return kp.DecryptKeyWithContext(aws.BackgroundContext(), key) -} - -// DecryptKeyWithContext makes a call to KMS to decrypt the key with request context. -func (kp *kmsKeyHandler) DecryptKeyWithContext(ctx aws.Context, key []byte) ([]byte, error) { - in := &kms.DecryptInput{ - EncryptionContext: kp.MaterialDescription, - CiphertextBlob: key, - GrantTokens: []*string{}, - } - - // useProvidedCMK will be true if a constructor was used with the new V2 client - if kp.useProvidedCMK { - in.KeyId = kp.cmkID - } - - out, err := kp.kms.DecryptWithContext(ctx, in) - if err != nil { - return nil, err - } - return out.Plaintext, nil -} - -// GenerateCipherData makes a call to KMS to generate a data key, Upon making -// the call, it also sets the encrypted key. -func (kp *kmsKeyHandler) GenerateCipherData(keySize, ivSize int) (CipherData, error) { - return kp.GenerateCipherDataWithContext(aws.BackgroundContext(), keySize, ivSize) -} - -// GenerateCipherDataWithContext makes a call to KMS to generate a data key, -// Upon making the call, it also sets the encrypted key. -func (kp *kmsKeyHandler) GenerateCipherDataWithContext(ctx aws.Context, keySize, ivSize int) (CipherData, error) { - cd := kp.CipherData.Clone() - - out, err := kp.kms.GenerateDataKeyWithContext(ctx, - &kms.GenerateDataKeyInput{ - EncryptionContext: cd.MaterialDescription, - KeyId: kp.cmkID, - KeySpec: aws.String("AES_256"), - }) - if err != nil { - return CipherData{}, err - } - - iv, err := generateBytes(ivSize) - if err != nil { - return CipherData{}, err - } - - cd.Key = out.Plaintext - cd.IV = iv - cd.EncryptedKey = out.CiphertextBlob - - return cd, nil -} - -func (kp kmsKeyHandler) isAWSFixture() bool { - return true -} - -var ( - _ CipherDataGenerator = (*kmsKeyHandler)(nil) - _ CipherDataGeneratorWithContext = (*kmsKeyHandler)(nil) - _ CipherDataDecrypter = (*kmsKeyHandler)(nil) - _ CipherDataDecrypterWithContext = (*kmsKeyHandler)(nil) - _ awsFixture = (*kmsKeyHandler)(nil) -) diff --git a/s3ext/service/s3/s3crypto/migrations_test.go b/s3ext/service/s3/s3crypto/migrations_test.go deleted file mode 100644 index b4b353bc..00000000 --- a/s3ext/service/s3/s3crypto/migrations_test.go +++ /dev/null @@ -1,205 +0,0 @@ -package s3crypto_test - -import ( - "bytes" - "fmt" - "io/ioutil" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/kms" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3crypto" -) - -// ExampleNewEncryptionClientV2_migration00 provides a migration example for how users can migrate from the V1 -// encryption client to the V2 encryption client. This example demonstrates how an application using the `kms` key wrap -// algorithm with `AES/CBC/PKCS5Padding` can migrate their application to `kms+context` key wrapping with -// `AES/GCM/NoPadding` content encryption. -func ExampleNewEncryptionClientV2_migration00() { - sess := session.Must(session.NewSession()) - kmsClient := kms.New(sess) - cmkID := "1234abcd-12ab-34cd-56ef-1234567890ab" - - // Usage of NewKMSKeyGenerator (kms) key wrapping algorithm must be migrated to NewKMSContextKeyGenerator (kms+context) key wrapping algorithm - // - // cipherDataGenerator := s3crypto.NewKMSKeyGenerator(kmsClient, cmkID) - cipherDataGenerator := s3crypto.NewKMSContextKeyGenerator(kmsClient, cmkID, s3crypto.MaterialDescription{}) - - // Usage of AESCBCContentCipherBuilder (AES/CBC/PKCS5Padding) must be migrated to AESGCMContentCipherBuilder (AES/GCM/NoPadding) - // - // contentCipherBuilder := s3crypto.AESCBCContentCipherBuilder(cipherDataGenerator, s3crypto.AESCBCPadder) - contentCipherBuilder := s3crypto.AESGCMContentCipherBuilderV2(cipherDataGenerator) - - // Construction of an encryption client should be done using NewEncryptionClientV2 - // - // encryptionClient := s3crypto.NewEncryptionClient(sess, contentCipherBuilder) - encryptionClient, err := s3crypto.NewEncryptionClientV2(sess, contentCipherBuilder) - if err != nil { - fmt.Printf("failed to construct encryption client: %v", err) - return - } - - _, err = encryptionClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String("your_bucket"), - Key: aws.String("your_key"), - Body: bytes.NewReader([]byte("your content")), - }) - if err != nil { - fmt.Printf("put object error: %v\n", err) - return - } - fmt.Println("put object completed") -} - -// ExampleNewEncryptionClientV2_migration01 provides a more advanced migration example for how users can -// migrate from the V1 encryption client to the V2 encryption client using more complex client construction. -func ExampleNewEncryptionClientV2_migration01() { - sess := session.Must(session.NewSession()) - kmsClient := kms.New(sess) - cmkID := "1234abcd-12ab-34cd-56ef-1234567890ab" - - cipherDataGenerator := s3crypto.NewKMSContextKeyGenerator(kmsClient, cmkID, s3crypto.MaterialDescription{}) - - contentCipherBuilder := s3crypto.AESGCMContentCipherBuilderV2(cipherDataGenerator) - - // Overriding of the encryption client options is possible by passing in functional arguments that override the - // provided EncryptionClientOptions. - // - // encryptionClient := s3crypto.NewEncryptionClient(cipherDataGenerator, contentCipherBuilder, func(o *s3crypto.EncryptionClient) { - // o.S3Client = s3.New(sess, &aws.Config{Region: aws.String("us-west-2")}), - // }) - encryptionClient, err := s3crypto.NewEncryptionClientV2(sess, contentCipherBuilder, func(o *s3crypto.EncryptionClientOptions) { - o.S3Client = s3.New(sess, &aws.Config{Region: aws.String("us-west-2")}) - }) - if err != nil { - fmt.Printf("failed to construct encryption client: %v", err) - return - } - - _, err = encryptionClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String("your_bucket"), - Key: aws.String("your_key"), - Body: bytes.NewReader([]byte("your content")), - }) - if err != nil { - fmt.Printf("put object error: %v\n", err) - return - } - fmt.Println("put object completed") -} - -// ExampleNewDecryptionClientV2_migration00 provides a migration example for how users can migrate -// from the V1 Decryption Clients to the V2 Decryption Clients. -func ExampleNewDecryptionClientV2_migration00() { - sess := session.Must(session.NewSession()) - - // Construction of an decryption client must be done using NewDecryptionClientV2 - // The V2 decryption client is able to decrypt object encrypted by the V1 client. - // - // decryptionClient := s3crypto.NewDecryptionClient(sess) - - // The V2 decryption client requires you to explicitly register the key wrap algorithms and content encryption algorithms - // that you want to explicitly support decryption for. - registry := s3crypto.NewCryptoRegistry() - - kmsClient := kms.New(sess) - - // If you need support for unwrapping data keys wrapped using the `kms` wrap algorithm you can use RegisterKMSWrapWithAnyCMK. - // Alternatively you may use RegisterKMSWrapWithCMK if you wish to limit KMS decrypt calls to a specific CMK. - if err := s3crypto.RegisterKMSWrapWithAnyCMK(registry, kmsClient); err != nil { - fmt.Printf("error: %v", err) - return - } - - // For unwrapping data keys wrapped using the new `kms+context` key wrap algorithm you can use RegisterKMSContextWrapWithAnyCMK. - // Alternatively you may use RegisterKMSWrapWithCMK if you wish to limit KMS decrypt calls to a specific CMK. - if err := s3crypto.RegisterKMSContextWrapWithAnyCMK(registry, kmsClient); err != nil { - fmt.Printf("error: %v", err) - return - } - - // If you need to decrypt objects encrypted using the V1 AES/CBC/PCKS5Padding cipher you can do so with RegisterAESCBCContentCipher - if err := s3crypto.RegisterAESCBCContentCipher(registry, s3crypto.AESCBCPadder); err != nil { - fmt.Printf("error: %v", err) - return - } - - // For decrypting objects encrypted in V1 or V2 using AES/GCM/NoPadding cipher you can do so with RegisterAESGCMContentCipher. - if err := s3crypto.RegisterAESGCMContentCipher(registry); err != nil { - fmt.Printf("error: %v", err) - return - } - - // Instantiate a new decryption client, and provided the Wrap, cek, and Padder that have been registered - // with your desired algorithms. - decryptionClient, err := s3crypto.NewDecryptionClientV2(sess, registry) - if err != nil { - fmt.Printf("error: %v", err) - return - } - - getObject, err := decryptionClient.GetObject(&s3.GetObjectInput{ - Bucket: aws.String("your_bucket"), - Key: aws.String("your_key"), - }) - if err != nil { - fmt.Printf("get object error: %v\n", err) - return - } - - _, err = ioutil.ReadAll(getObject.Body) - if err != nil { - fmt.Printf("error reading object: %v\n", err) - } - fmt.Println("get object completed") -} - -// ExampleNewDecryptionClientV2_migration01 provides a more advanced migration example for how users can -// migrate from the V1 decryption client to the V2 decryption client using more complex client construction. -func ExampleNewDecryptionClientV2_migration01() { - sess := session.Must(session.NewSession()) - - // Construction of an decryption client must be done using NewDecryptionClientV2 - // The V2 decryption client is able to decrypt object encrypted by the V1 client. - // - // decryptionClient := s3crypto.NewDecryptionClient(sess, func(o *s3crypto.DecryptionClient) { - // o.S3Client = s3.New(sess, &aws.Config{Region: aws.String("us-west-2")}) - //}) - registry := s3crypto.NewCryptoRegistry() - - kmsClient := kms.New(sess) - if err := s3crypto.RegisterKMSWrapWithAnyCMK(registry, kmsClient); err != nil { - fmt.Printf("error: %v", err) - return - } - - // If you need to decrypt objects encrypted using AES/GCM/NoPadding cipher you can do so with RegisterAESGCMContentCipher - if err := s3crypto.RegisterAESGCMContentCipher(registry); err != nil { - fmt.Printf("error: %v", err) - return - } - - decryptionClient, err := s3crypto.NewDecryptionClientV2(sess, registry, func(o *s3crypto.DecryptionClientOptions) { - o.S3Client = s3.New(sess, &aws.Config{Region: aws.String("us-west-2")}) - }) - if err != nil { - fmt.Printf("error: %v", err) - return - } - - getObject, err := decryptionClient.GetObject(&s3.GetObjectInput{ - Bucket: aws.String("your_bucket"), - Key: aws.String("your_key"), - }) - if err != nil { - fmt.Printf("get object error: %v\n", err) - return - } - - _, err = ioutil.ReadAll(getObject.Body) - if err != nil { - fmt.Printf("error reading object: %v\n", err) - } - fmt.Println("get object completed") -} diff --git a/s3ext/service/s3/s3crypto/mock_test.go b/s3ext/service/s3/s3crypto/mock_test.go deleted file mode 100644 index fa110af0..00000000 --- a/s3ext/service/s3/s3crypto/mock_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package s3crypto - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/kms/kmsiface" -) - -type mockGenerator struct{} - -func (m mockGenerator) GenerateCipherData(keySize, ivSize int) (CipherData, error) { - cd := CipherData{ - Key: make([]byte, keySize), - IV: make([]byte, ivSize), - } - return cd, nil -} - -func (m mockGenerator) DecryptKey(key []byte) ([]byte, error) { - return make([]byte, 16), nil -} - -type mockGeneratorV2 struct{} - -func (m mockGeneratorV2) GenerateCipherDataWithCEKAlg(ctx aws.Context, keySize int, ivSize int, cekAlg string) (CipherData, error) { - cd := CipherData{ - Key: make([]byte, keySize), - IV: make([]byte, ivSize), - } - return cd, nil -} - -func (m mockGeneratorV2) DecryptKey(key []byte) ([]byte, error) { - return make([]byte, 16), nil -} - -func (m mockGeneratorV2) isEncryptionVersionCompatible(version clientVersion) error { - if version != v2ClientVersion { - return fmt.Errorf("mock error about version") - } - return nil -} - -type mockCipherBuilder struct { - generator CipherDataGenerator -} - -func (builder mockCipherBuilder) isEncryptionVersionCompatible(version clientVersion) error { - if version != v1ClientVersion { - return fmt.Errorf("mock error about version") - } - return nil -} - -func (builder mockCipherBuilder) ContentCipher() (ContentCipher, error) { - cd, err := builder.generator.GenerateCipherData(32, 16) - if err != nil { - return nil, err - } - return &mockContentCipher{cd}, nil -} - -type mockCipherBuilderV2 struct { - generator CipherDataGeneratorWithCEKAlg -} - -func (builder mockCipherBuilderV2) isEncryptionVersionCompatible(version clientVersion) error { - if version != v2ClientVersion { - return fmt.Errorf("mock error about version") - } - return nil -} - -func (builder mockCipherBuilderV2) ContentCipher() (ContentCipher, error) { - cd, err := builder.generator.GenerateCipherDataWithCEKAlg(aws.BackgroundContext(), 32, 16, "mock-cek-alg") - if err != nil { - return nil, err - } - return &mockContentCipher{cd}, nil -} - -type mockContentCipher struct { - cd CipherData -} - -func (cipher *mockContentCipher) GetCipherData() CipherData { - return cipher.cd -} - -func (cipher *mockContentCipher) EncryptContents(src io.Reader) (io.Reader, error) { - b, err := ioutil.ReadAll(src) - if err != nil { - return nil, err - } - size := len(b) - b = bytes.Repeat([]byte{1}, size) - return bytes.NewReader(b), nil -} - -func (cipher *mockContentCipher) DecryptContents(src io.ReadCloser) (io.ReadCloser, error) { - b, err := ioutil.ReadAll(src) - if err != nil { - return nil, err - } - size := len(b) - return ioutil.NopCloser(bytes.NewReader(make([]byte, size))), nil -} - -type mockKMS struct { - kmsiface.KMSAPI -} - -type mockPadder struct { -} - -func (m mockPadder) Pad(i []byte, i2 int) ([]byte, error) { - return i, nil -} - -func (m mockPadder) Unpad(i []byte) ([]byte, error) { - return i, nil -} - -func (m mockPadder) Name() string { - return "mockPadder" -}