Skip to content

Commit 1e84382

Browse files
author
awssdkgo
committed
Merge commit '12ff57a16373dda5a0c22eafdf0fa1c4c224f7c4' into release
* commit '12ff57a16373dda5a0c22eafdf0fa1c4c224f7c4': Updates to the Amazon S3 Encryption Client - This change includes fixes for issues that were reported by Sophie Schmieg from the Google ISE team, and for issues that were discovered by AWS Cryptography.
2 parents b811ea8 + 12ff57a commit 1e84382

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2483
-537
lines changed

CHANGELOG_PENDING.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
### SDK Features
2+
* `service/s3/s3crypto`: Updates to the Amazon S3 Encryption Client - This change includes fixes for issues that were reported by Sophie Schmieg from the Google ISE team, and for issues that were discovered by AWS Cryptography.
23

34
### SDK Enhancements
45

aws/csm/reporter_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func TestReportingMetrics(t *testing.T) {
183183
{
184184
"Type": "ApiCallAttempt",
185185
"SdkException": request.ErrCodeRequestError,
186-
"SdkExceptionMessage": request.ErrCodeRequestError+": sdk error",
186+
"SdkExceptionMessage": request.ErrCodeRequestError + ": sdk error",
187187
"HttpStatusCode": float64(500),
188188
},
189189
{

aws/ec2metadata/service.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const (
4141
enableTokenProviderHandlerName = "enableTokenProviderHandler"
4242

4343
// TTL constants
44-
defaultTTL = 21600 * time.Second
44+
defaultTTL = 21600 * time.Second
4545
ttlExpirationWindow = 30 * time.Second
4646
)
4747

service/s3/doc_custom.go

-13
Original file line numberDiff line numberDiff line change
@@ -104,19 +104,6 @@
104104
// content from S3. The Encryption and Decryption clients can be used concurrently
105105
// once the client is created.
106106
//
107-
// sess := session.Must(session.NewSession())
108-
//
109-
// // Create the decryption client.
110-
// svc := s3crypto.NewDecryptionClient(sess)
111-
//
112-
// // The object will be downloaded from S3 and decrypted locally. By metadata
113-
// // about the object's encryption will instruct the decryption client how
114-
// // decrypt the content of the object. By default KMS is used for keys.
115-
// result, err := svc.GetObject(&s3.GetObjectInput {
116-
// Bucket: aws.String(myBucket),
117-
// Key: aws.String(myKey),
118-
// })
119-
//
120107
// See the s3crypto package documentation for more information.
121108
// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/
122109
//

service/s3/s3crypto/aes_cbc_content_cipher.go

+48-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package s3crypto
22

33
import (
44
"io"
5-
"strings"
65
)
76

87
const (
@@ -15,18 +14,38 @@ type cbcContentCipherBuilder struct {
1514
padder Padder
1615
}
1716

18-
func (cbcContentCipherBuilder) isUsingDeprecatedFeatures() error {
19-
return errDeprecatedCipherBuilder
20-
}
21-
22-
// AESCBCContentCipherBuilder returns a new encryption only mode structure with a specific cipher
23-
// for the master key
17+
// AESCBCContentCipherBuilder returns a new encryption only AES/CBC mode structure using the provided padder. The provided cipher data generator
18+
// will be used to provide keys for content encryption.
2419
//
25-
// deprecated: This content cipher builder has been deprecated. Users should migrate to AESGCMContentCipherBuilder
20+
// 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.
2621
func AESCBCContentCipherBuilder(generator CipherDataGenerator, padder Padder) ContentCipherBuilder {
2722
return cbcContentCipherBuilder{generator: generator, padder: padder}
2823
}
2924

25+
// RegisterAESCBCContentCipher registers the AES/CBC cipher and padder with the provided CryptoRegistry.
26+
//
27+
// Example:
28+
// cr := s3crypto.NewCryptoRegistry()
29+
// if err := s3crypto.RegisterAESCBCContentCipher(cr, s3crypto.AESCBCPadder); err != nil {
30+
// panic(err) // handle error
31+
// }
32+
//
33+
// 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.
34+
func RegisterAESCBCContentCipher(registry *CryptoRegistry, padder Padder) error {
35+
if registry == nil {
36+
return errNilCryptoRegistry
37+
}
38+
name := AESCBC + "/" + padder.Name()
39+
err := registry.AddCEK(name, newAESCBCContentCipher)
40+
if err != nil {
41+
return err
42+
}
43+
if err := registry.AddPadder(name, padder); err != nil {
44+
return err
45+
}
46+
return nil
47+
}
48+
3049
func (builder cbcContentCipherBuilder) ContentCipher() (ContentCipher, error) {
3150
cd, err := builder.generator.GenerateCipherData(cbcKeySize, cbcNonceSize)
3251
if err != nil {
@@ -37,11 +56,22 @@ func (builder cbcContentCipherBuilder) ContentCipher() (ContentCipher, error) {
3756
return newAESCBCContentCipher(cd)
3857
}
3958

59+
func (builder cbcContentCipherBuilder) isAWSFixture() bool {
60+
return true
61+
}
62+
63+
func (cbcContentCipherBuilder) isEncryptionVersionCompatible(version clientVersion) error {
64+
if version != v1ClientVersion {
65+
return errDeprecatedIncompatibleCipherBuilder
66+
}
67+
return nil
68+
}
69+
4070
// newAESCBCContentCipher will create a new aes cbc content cipher. If the cipher data's
41-
// will set the CEK algorithm if it hasn't been set.
71+
// will set the cek algorithm if it hasn't been set.
4272
func newAESCBCContentCipher(cd CipherData) (ContentCipher, error) {
4373
if len(cd.CEKAlgorithm) == 0 {
44-
cd.CEKAlgorithm = strings.Join([]string{AESCBC, cd.Padder.Name()}, "/")
74+
cd.CEKAlgorithm = AESCBC + "/" + cd.Padder.Name()
4575
}
4676
cipher, err := newAESCBC(cd, cd.Padder)
4777
if err != nil {
@@ -77,3 +107,11 @@ func (cc *aesCBCContentCipher) DecryptContents(src io.ReadCloser) (io.ReadCloser
77107
func (cc aesCBCContentCipher) GetCipherData() CipherData {
78108
return cc.CipherData
79109
}
110+
111+
var (
112+
_ ContentCipherBuilder = (*cbcContentCipherBuilder)(nil)
113+
_ compatibleEncryptionFixture = (*cbcContentCipherBuilder)(nil)
114+
_ awsFixture = (*cbcContentCipherBuilder)(nil)
115+
116+
_ ContentCipher = (*aesCBCContentCipher)(nil)
117+
)
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
package s3crypto_test
1+
package s3crypto
22

33
import (
4+
"strings"
45
"testing"
5-
6-
"github.com/aws/aws-sdk-go/service/s3/s3crypto"
76
)
87

98
func TestAESCBCBuilder(t *testing.T) {
109
generator := mockGenerator{}
11-
builder := s3crypto.AESCBCContentCipherBuilder(generator, s3crypto.NoPadder)
10+
builder := AESCBCContentCipherBuilder(generator, NoPadder)
1211
if builder == nil {
1312
t.Fatal(builder)
1413
}
@@ -18,3 +17,64 @@ func TestAESCBCBuilder(t *testing.T) {
1817
t.Fatal(err)
1918
}
2019
}
20+
21+
func TestAesCBCContentCipher_isFixtureEncryptionCompatible(t *testing.T) {
22+
generator := mockGenerator{}
23+
builder := AESCBCContentCipherBuilder(generator, NoPadder)
24+
if builder == nil {
25+
t.Fatal("expected builder to not be nil")
26+
}
27+
28+
compatibility, ok := builder.(compatibleEncryptionFixture)
29+
if !ok {
30+
t.Fatal("expected builder to implement compatibleEncryptionFixture interface")
31+
}
32+
33+
if err := compatibility.isEncryptionVersionCompatible(v1ClientVersion); err != nil {
34+
t.Errorf("expected builder to be compatible with v1 client")
35+
}
36+
37+
if err := compatibility.isEncryptionVersionCompatible(v2ClientVersion); err == nil {
38+
t.Errorf("expected builder to not be compatible with v2 client")
39+
}
40+
}
41+
42+
func TestRegisterAESCBCContentCipher(t *testing.T) {
43+
cr := NewCryptoRegistry()
44+
padder := AESCBCPadder
45+
err := RegisterAESCBCContentCipher(cr, padder)
46+
if err != nil {
47+
t.Fatalf("expected no error, got %v", err)
48+
}
49+
50+
if v, ok := cr.GetCEK("AES/CBC/PKCS5Padding"); !ok {
51+
t.Fatal("expected cek algorithm handler to registered")
52+
} else if v == nil {
53+
t.Fatal("expected non-nil cek handler to be registered")
54+
}
55+
56+
if v, ok := cr.GetPadder("AES/CBC/PKCS5Padding"); !ok {
57+
t.Fatal("expected padder to be registered")
58+
} else if v != padder {
59+
t.Fatal("padder did not match provided value")
60+
}
61+
62+
// try to register padder again
63+
err = RegisterAESCBCContentCipher(cr, padder)
64+
if err == nil {
65+
t.Fatal("expected error, got none")
66+
} else if !strings.Contains(err.Error(), "duplicate cek registry entry") {
67+
t.Errorf("expected duplicate cek entry, got %v", err)
68+
}
69+
70+
// try to regster padder with cek removed but padder entry still present
71+
if _, ok := cr.RemoveCEK("AES/CBC/PKCS5Padding"); !ok {
72+
t.Fatalf("expected value to be removed")
73+
}
74+
err = RegisterAESCBCContentCipher(cr, padder)
75+
if err == nil {
76+
t.Fatal("expected error, got none")
77+
} else if !strings.Contains(err.Error(), "duplicate padder registry entry") {
78+
t.Errorf("expected duplicate padder entry, got %v", err)
79+
}
80+
}

service/s3/s3crypto/aes_gcm_content_cipher.go

+119-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package s3crypto
22

33
import (
4+
"fmt"
45
"io"
56

67
"github.com/aws/aws-sdk-go/aws"
@@ -11,21 +12,62 @@ const (
1112
gcmNonceSize = 12
1213
)
1314

14-
type gcmContentCipherBuilder struct {
15-
generator CipherDataGenerator
15+
// AESGCMContentCipherBuilder returns a new encryption only AES/GCM mode structure with a specific cipher data generator
16+
// that will provide keys to be used for content encryption.
17+
//
18+
// Note: This uses the Go stdlib AEAD implementation for AES/GCM. Due to this objects to be encrypted or decrypted
19+
// will be fully loaded into memory before encryption or decryption can occur. Caution must be taken to avoid memory
20+
// allocation failures.
21+
//
22+
// 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.
23+
func AESGCMContentCipherBuilder(generator CipherDataGenerator) ContentCipherBuilder {
24+
return gcmContentCipherBuilder{generator}
25+
}
26+
27+
// AESGCMContentCipherBuilderV2 returns a new encryption only AES/GCM mode structure with a specific cipher data generator
28+
// that will provide keys to be used for content encryption. This type is compatible with the V2 encryption client.
29+
//
30+
// Note: This uses the Go stdlib AEAD implementation for AES/GCM. Due to this objects to be encrypted or decrypted
31+
// will be fully loaded into memory before encryption or decryption can occur. Caution must be taken to avoid memory
32+
// allocation failures.
33+
func AESGCMContentCipherBuilderV2(generator CipherDataGeneratorWithCEKAlg) ContentCipherBuilder {
34+
return gcmContentCipherBuilderV2{generator}
1635
}
1736

18-
func (builder gcmContentCipherBuilder) isUsingDeprecatedFeatures() error {
19-
if feature, ok := builder.generator.(deprecatedFeatures); ok {
20-
return feature.isUsingDeprecatedFeatures()
37+
// RegisterAESGCMContentCipher registers the AES/GCM content cipher algorithm with the provided CryptoRegistry.
38+
//
39+
// Example:
40+
// cr := s3crypto.NewCryptoRegistry()
41+
// if err := s3crypto.RegisterAESGCMContentCipher(cr); err != nil {
42+
// panic(err) // handle error
43+
// }
44+
//
45+
func RegisterAESGCMContentCipher(registry *CryptoRegistry) error {
46+
if registry == nil {
47+
return errNilCryptoRegistry
48+
}
49+
50+
err := registry.AddCEK(AESGCMNoPadding, newAESGCMContentCipher)
51+
if err != nil {
52+
return err
53+
}
54+
55+
// NoPadder is generic but required by this algorithm, so if it is already registered and is the expected implementation
56+
// don't error.
57+
padderName := NoPadder.Name()
58+
if v, ok := registry.GetPadder(padderName); !ok {
59+
if err := registry.AddPadder(padderName, NoPadder); err != nil {
60+
return err
61+
}
62+
} else if _, ok := v.(noPadder); !ok {
63+
return fmt.Errorf("%s is already registred but does not match expected type %T", padderName, NoPadder)
2164
}
2265
return nil
2366
}
2467

25-
// AESGCMContentCipherBuilder returns a new encryption only mode structure with a specific cipher
26-
// for the master key
27-
func AESGCMContentCipherBuilder(generator CipherDataGenerator) ContentCipherBuilder {
28-
return gcmContentCipherBuilder{generator}
68+
// gcmContentCipherBuilder is a AES/GCM content cipher to be used with the V1 client CipherDataGenerator interface
69+
type gcmContentCipherBuilder struct {
70+
generator CipherDataGenerator
2971
}
3072

3173
func (builder gcmContentCipherBuilder) ContentCipher() (ContentCipher, error) {
@@ -37,10 +79,6 @@ func (builder gcmContentCipherBuilder) ContentCipherWithContext(ctx aws.Context)
3779
var err error
3880

3981
switch v := builder.generator.(type) {
40-
case CipherDataGeneratorWithCEKAlgWithContext:
41-
cd, err = v.GenerateCipherDataWithCEKAlgWithContext(ctx, gcmKeySize, gcmNonceSize, AESGCMNoPadding)
42-
case CipherDataGeneratorWithCEKAlg:
43-
cd, err = v.GenerateCipherDataWithCEKAlg(gcmKeySize, gcmNonceSize, AESGCMNoPadding)
4482
case CipherDataGeneratorWithContext:
4583
cd, err = v.GenerateCipherDataWithContext(ctx, gcmKeySize, gcmNonceSize)
4684
default:
@@ -53,6 +91,52 @@ func (builder gcmContentCipherBuilder) ContentCipherWithContext(ctx aws.Context)
5391
return newAESGCMContentCipher(cd)
5492
}
5593

94+
// isFixtureEncryptionCompatible will ensure that this type may only be used with the V1 client
95+
func (builder gcmContentCipherBuilder) isEncryptionVersionCompatible(version clientVersion) error {
96+
if version != v1ClientVersion {
97+
return errDeprecatedIncompatibleCipherBuilder
98+
}
99+
return nil
100+
}
101+
102+
func (builder gcmContentCipherBuilder) isAWSFixture() bool {
103+
return true
104+
}
105+
106+
// gcmContentCipherBuilderV2 return a new builder for encryption content using AES/GCM/NoPadding. This type is meant
107+
// to be used with key wrapping implementations that allow the cek algorithm to be provided when calling the
108+
// cipher data generator.
109+
type gcmContentCipherBuilderV2 struct {
110+
generator CipherDataGeneratorWithCEKAlg
111+
}
112+
113+
func (builder gcmContentCipherBuilderV2) ContentCipher() (ContentCipher, error) {
114+
return builder.ContentCipherWithContext(aws.BackgroundContext())
115+
}
116+
117+
func (builder gcmContentCipherBuilderV2) ContentCipherWithContext(ctx aws.Context) (ContentCipher, error) {
118+
cd, err := builder.generator.GenerateCipherDataWithCEKAlg(ctx, gcmKeySize, gcmNonceSize, AESGCMNoPadding)
119+
if err != nil {
120+
return nil, err
121+
}
122+
123+
return newAESGCMContentCipher(cd)
124+
}
125+
126+
// isFixtureEncryptionCompatible will ensure that this type may only be used with the V2 client
127+
func (builder gcmContentCipherBuilderV2) isEncryptionVersionCompatible(version clientVersion) error {
128+
if version != v2ClientVersion {
129+
return errDeprecatedIncompatibleCipherBuilder
130+
}
131+
return nil
132+
}
133+
134+
// isAWSFixture will return whether this type was constructed with an AWS provided CipherDataGenerator
135+
func (builder gcmContentCipherBuilderV2) isAWSFixture() bool {
136+
v, ok := builder.generator.(awsFixture)
137+
return ok && v.isAWSFixture()
138+
}
139+
56140
func newAESGCMContentCipher(cd CipherData) (ContentCipher, error) {
57141
cd.CEKAlgorithm = AESGCMNoPadding
58142
cd.TagLength = "128"
@@ -91,3 +175,25 @@ func (cc *aesGCMContentCipher) DecryptContents(src io.ReadCloser) (io.ReadCloser
91175
func (cc aesGCMContentCipher) GetCipherData() CipherData {
92176
return cc.CipherData
93177
}
178+
179+
// assert ContentCipherBuilder implementations
180+
var (
181+
_ ContentCipherBuilder = (*gcmContentCipherBuilder)(nil)
182+
_ ContentCipherBuilder = (*gcmContentCipherBuilderV2)(nil)
183+
)
184+
185+
// assert ContentCipherBuilderWithContext implementations
186+
var (
187+
_ ContentCipherBuilderWithContext = (*gcmContentCipherBuilder)(nil)
188+
_ ContentCipherBuilderWithContext = (*gcmContentCipherBuilderV2)(nil)
189+
)
190+
191+
// assert ContentCipher implementations
192+
var (
193+
_ ContentCipher = (*aesGCMContentCipher)(nil)
194+
)
195+
196+
// assert awsFixture implementations
197+
var (
198+
_ awsFixture = (*gcmContentCipherBuilderV2)(nil)
199+
)

0 commit comments

Comments
 (0)