aws-sdk-s3 1.75.0 → 1.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/aws-sdk-s3.rb +1 -1
- data/lib/aws-sdk-s3/bucket.rb +2 -2
- data/lib/aws-sdk-s3/client.rb +791 -505
- data/lib/aws-sdk-s3/encryption.rb +2 -0
- data/lib/aws-sdk-s3/encryption/client.rb +11 -0
- data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +52 -28
- data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +41 -5
- data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +5 -5
- data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +32 -3
- data/lib/aws-sdk-s3/encryption/utils.rb +23 -0
- data/lib/aws-sdk-s3/encryptionV2/client.rb +198 -22
- data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +40 -12
- data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +77 -10
- data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +2 -0
- data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +7 -4
- data/lib/aws-sdk-s3/encryptionV2/errors.rb +24 -0
- data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +2 -0
- data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +2 -0
- data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +2 -0
- data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +2 -0
- data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +90 -20
- data/lib/aws-sdk-s3/encryptionV2/materials.rb +2 -0
- data/lib/aws-sdk-s3/encryptionV2/utils.rb +2 -15
- data/lib/aws-sdk-s3/encryption_v2.rb +4 -1
- data/lib/aws-sdk-s3/multipart_upload_part.rb +5 -5
- data/lib/aws-sdk-s3/object.rb +10 -9
- data/lib/aws-sdk-s3/object_summary.rb +23 -7
- data/lib/aws-sdk-s3/object_version.rb +2 -2
- data/lib/aws-sdk-s3/presigner.rb +2 -2
- data/lib/aws-sdk-s3/types.rb +63 -26
- metadata +2 -2
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'base64'
|
2
4
|
|
3
5
|
module Aws
|
@@ -5,6 +7,7 @@ module Aws
|
|
5
7
|
module EncryptionV2
|
6
8
|
# @api private
|
7
9
|
class DecryptHandler < Seahorse::Client::Handler
|
10
|
+
@@warned_response_target_proc = false
|
8
11
|
|
9
12
|
V1_ENVELOPE_KEYS = %w(
|
10
13
|
x-amz-key
|
@@ -38,9 +41,22 @@ module Aws
|
|
38
41
|
AES/CBC/PKCS7Padding
|
39
42
|
)
|
40
43
|
|
44
|
+
AUTH_REQUIRED_CEK_ALGS = %w(AES/GCM/NoPadding)
|
45
|
+
|
41
46
|
def call(context)
|
42
47
|
attach_http_event_listeners(context)
|
43
48
|
apply_cse_user_agent(context)
|
49
|
+
|
50
|
+
if context[:response_target].is_a?(Proc) && !@@warned_response_target_proc
|
51
|
+
@@warned_response_target_proc = true
|
52
|
+
warn(':response_target is a Proc, or a block was provided. ' \
|
53
|
+
'Read the entire object to the ' \
|
54
|
+
'end before you start using the decrypted data. This is to ' \
|
55
|
+
'verify that the object has not been modified since it ' \
|
56
|
+
'was encrypted.')
|
57
|
+
|
58
|
+
end
|
59
|
+
|
44
60
|
@handler.call(context)
|
45
61
|
end
|
46
62
|
|
@@ -71,11 +87,11 @@ module Aws
|
|
71
87
|
end
|
72
88
|
|
73
89
|
def decryption_cipher(context)
|
74
|
-
if envelope = get_encryption_envelope(context)
|
90
|
+
if (envelope = get_encryption_envelope(context))
|
75
91
|
cipher = context[:encryption][:cipher_provider]
|
76
92
|
.decryption_cipher(
|
77
93
|
envelope,
|
78
|
-
|
94
|
+
context[:encryption]
|
79
95
|
)
|
80
96
|
[cipher, envelope]
|
81
97
|
else
|
@@ -145,10 +161,6 @@ module Aws
|
|
145
161
|
envelope
|
146
162
|
end
|
147
163
|
|
148
|
-
# When the x-amz-meta-x-amz-tag-len header is present, it indicates
|
149
|
-
# that the body of this object has a trailing auth tag. The header
|
150
|
-
# indicates the length of that tag.
|
151
|
-
#
|
152
164
|
# This method fetches the tag from the end of the object by
|
153
165
|
# making a GET Object w/range request. This auth tag is used
|
154
166
|
# to initialize the cipher, and the decrypter truncates the
|
@@ -160,8 +172,7 @@ module Aws
|
|
160
172
|
end
|
161
173
|
http_resp = context.http_response
|
162
174
|
content_length = http_resp.headers['content-length'].to_i
|
163
|
-
auth_tag_length = envelope
|
164
|
-
auth_tag_length = auth_tag_length.to_i / 8
|
175
|
+
auth_tag_length = auth_tag_length(envelope)
|
165
176
|
|
166
177
|
auth_tag = context.client.get_object(
|
167
178
|
bucket: context.params[:bucket],
|
@@ -181,14 +192,31 @@ module Aws
|
|
181
192
|
end
|
182
193
|
|
183
194
|
def body_contains_auth_tag?(envelope)
|
184
|
-
|
195
|
+
AUTH_REQUIRED_CEK_ALGS.include?(envelope['x-amz-cek-alg'])
|
196
|
+
end
|
197
|
+
|
198
|
+
# Determine the auth tag length from the algorithm
|
199
|
+
# Validate it against the value provided in the x-amz-tag-len
|
200
|
+
# Return the tag length in bytes
|
201
|
+
def auth_tag_length(envelope)
|
202
|
+
tag_length =
|
203
|
+
case envelope['x-amz-cek-alg']
|
204
|
+
when 'AES/GCM/NoPadding' then AES_GCM_TAG_LEN_BYTES
|
205
|
+
else
|
206
|
+
raise ArgumentError, 'Unsupported cek-alg: ' \
|
207
|
+
"#{envelope['x-amz-cek-alg']}"
|
208
|
+
end
|
209
|
+
if (tag_length * 8) != envelope['x-amz-tag-len'].to_i
|
210
|
+
raise Errors::DecryptionError, 'x-amz-tag-len does not match expected'
|
211
|
+
end
|
212
|
+
tag_length
|
185
213
|
end
|
186
214
|
|
187
215
|
def apply_cse_user_agent(context)
|
188
216
|
if context.config.user_agent_suffix.nil?
|
189
|
-
context.config.user_agent_suffix =
|
190
|
-
elsif !context.config.user_agent_suffix.include?
|
191
|
-
context.config.user_agent_suffix +=
|
217
|
+
context.config.user_agent_suffix = EC_USER_AGENT
|
218
|
+
elsif !context.config.user_agent_suffix.include? EC_USER_AGENT
|
219
|
+
context.config.user_agent_suffix += " #{EC_USER_AGENT}"
|
192
220
|
end
|
193
221
|
end
|
194
222
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'base64'
|
2
4
|
|
3
5
|
module Aws
|
@@ -8,27 +10,36 @@ module Aws
|
|
8
10
|
|
9
11
|
def initialize(options = {})
|
10
12
|
@key_provider = options[:key_provider]
|
13
|
+
@key_wrap_schema = validate_key_wrap(
|
14
|
+
options[:key_wrap_schema],
|
15
|
+
@key_provider.encryption_materials.key
|
16
|
+
)
|
17
|
+
@content_encryption_schema = validate_cek(
|
18
|
+
options[:content_encryption_schema]
|
19
|
+
)
|
11
20
|
end
|
12
21
|
|
13
22
|
# @return [Array<Hash,Cipher>] Creates an returns a new encryption
|
14
23
|
# envelope and encryption cipher.
|
15
24
|
def encryption_cipher(options = {})
|
25
|
+
validate_options(options)
|
16
26
|
cipher = Utils.aes_encryption_cipher(:GCM)
|
17
|
-
cek_alg = 'AES/GCM/NoPadding'
|
18
27
|
if @key_provider.encryption_materials.key.is_a? OpenSSL::PKey::RSA
|
19
|
-
|
20
|
-
|
28
|
+
enc_key = encode64(
|
29
|
+
encrypt_rsa(envelope_key(cipher), @content_encryption_schema)
|
30
|
+
)
|
21
31
|
else
|
22
|
-
|
23
|
-
|
32
|
+
enc_key = encode64(
|
33
|
+
encrypt_aes_gcm(envelope_key(cipher), @content_encryption_schema)
|
34
|
+
)
|
24
35
|
end
|
25
36
|
envelope = {
|
26
37
|
'x-amz-key-v2' => enc_key,
|
27
|
-
'x-amz-cek-alg' =>
|
28
|
-
'x-amz-tag-len' =>
|
29
|
-
'x-amz-wrap-alg' =>
|
38
|
+
'x-amz-cek-alg' => @content_encryption_schema,
|
39
|
+
'x-amz-tag-len' => (AES_GCM_TAG_LEN_BYTES * 8).to_s,
|
40
|
+
'x-amz-wrap-alg' => @key_wrap_schema,
|
30
41
|
'x-amz-iv' => encode64(envelope_iv(cipher)),
|
31
|
-
'x-amz-matdesc' => materials_description
|
42
|
+
'x-amz-matdesc' => materials_description
|
32
43
|
}
|
33
44
|
cipher.auth_data = '' # auth_data must be set after key and iv
|
34
45
|
[envelope, cipher]
|
@@ -37,8 +48,12 @@ module Aws
|
|
37
48
|
# @return [Cipher] Given an encryption envelope, returns a
|
38
49
|
# decryption cipher.
|
39
50
|
def decryption_cipher(envelope, options = {})
|
51
|
+
validate_options(options)
|
40
52
|
master_key = @key_provider.key_for(envelope['x-amz-matdesc'])
|
41
53
|
if envelope.key? 'x-amz-key'
|
54
|
+
unless options[:security_profile] == :v2_and_legacy
|
55
|
+
raise Errors::LegacyDecryptionError
|
56
|
+
end
|
42
57
|
# Support for decryption of legacy objects
|
43
58
|
key = Utils.decrypt(master_key, decode64(envelope['x-amz-key']))
|
44
59
|
iv = decode64(envelope['x-amz-iv'])
|
@@ -51,13 +66,26 @@ module Aws
|
|
51
66
|
key =
|
52
67
|
case envelope['x-amz-wrap-alg']
|
53
68
|
when 'AES/GCM'
|
69
|
+
if master_key.is_a? OpenSSL::PKey::RSA
|
70
|
+
raise ArgumentError, 'Key mismatch - Client is configured' \
|
71
|
+
' with an RSA key and the x-amz-wrap-alg is AES/GCM.'
|
72
|
+
end
|
54
73
|
Utils.decrypt_aes_gcm(master_key,
|
55
74
|
decode64(envelope['x-amz-key-v2']),
|
56
75
|
envelope['x-amz-cek-alg'])
|
57
76
|
when 'RSA-OAEP-SHA1'
|
77
|
+
unless master_key.is_a? OpenSSL::PKey::RSA
|
78
|
+
raise ArgumentError, 'Key mismatch - Client is configured' \
|
79
|
+
' with an AES key and the x-amz-wrap-alg is RSA-OAEP-SHA1.'
|
80
|
+
end
|
58
81
|
key, cek_alg = Utils.decrypt_rsa(master_key, decode64(envelope['x-amz-key-v2']))
|
59
|
-
raise Errors::
|
82
|
+
raise Errors::CEKAlgMismatchError unless cek_alg == envelope['x-amz-cek-alg']
|
60
83
|
key
|
84
|
+
when 'kms+context'
|
85
|
+
raise ArgumentError, 'Key mismatch - Client is configured' \
|
86
|
+
' with a user provided key and the x-amz-wrap-alg is' \
|
87
|
+
' kms+context. Please configure the client with the' \
|
88
|
+
' required kms_key_id'
|
61
89
|
else
|
62
90
|
raise ArgumentError, 'Unsupported wrap-alg: ' \
|
63
91
|
"#{envelope['x-amz-wrap-alg']}"
|
@@ -69,6 +97,39 @@ module Aws
|
|
69
97
|
|
70
98
|
private
|
71
99
|
|
100
|
+
# Validate that the key_wrap_schema
|
101
|
+
# is valid, supported and matches the provided key.
|
102
|
+
# Returns the string version for the x-amz-key-wrap-alg
|
103
|
+
def validate_key_wrap(key_wrap_schema, key)
|
104
|
+
if key.is_a? OpenSSL::PKey::RSA
|
105
|
+
unless key_wrap_schema == :rsa_oaep_sha1
|
106
|
+
raise ArgumentError, ':key_wrap_schema must be set to :rsa_oaep_sha1 for RSA keys.'
|
107
|
+
end
|
108
|
+
else
|
109
|
+
unless key_wrap_schema == :aes_gcm
|
110
|
+
raise ArgumentError, ':key_wrap_schema must be set to :aes_gcm for AES keys.'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
case key_wrap_schema
|
115
|
+
when :rsa_oaep_sha1 then 'RSA-OAEP-SHA1'
|
116
|
+
when :aes_gcm then 'AES/GCM'
|
117
|
+
when :kms_context
|
118
|
+
raise ArgumentError, 'A kms_key_id is required when using :kms_context.'
|
119
|
+
else
|
120
|
+
raise ArgumentError, "Unsupported key_wrap_schema: #{key_wrap_schema}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def validate_cek(content_encryption_schema)
|
125
|
+
case content_encryption_schema
|
126
|
+
when :aes_gcm_no_padding
|
127
|
+
"AES/GCM/NoPadding"
|
128
|
+
else
|
129
|
+
raise ArgumentError, "Unsupported content_encryption_schema: #{content_encryption_schema}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
72
133
|
def envelope_key(cipher)
|
73
134
|
cipher.key = cipher.random_key
|
74
135
|
end
|
@@ -97,6 +158,12 @@ module Aws
|
|
97
158
|
Base64.decode64(str)
|
98
159
|
end
|
99
160
|
|
161
|
+
def validate_options(options)
|
162
|
+
if !options[:kms_encryption_context].nil?
|
163
|
+
raise ArgumentError, 'Cannot provide :kms_encryption_context ' \
|
164
|
+
'with non KMS client.'
|
165
|
+
end
|
166
|
+
end
|
100
167
|
end
|
101
168
|
end
|
102
169
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'base64'
|
2
4
|
|
3
5
|
module Aws
|
@@ -45,7 +47,8 @@ module Aws
|
|
45
47
|
context.params[:metadata] ||= {}
|
46
48
|
context.params[:metadata]['x-amz-unencrypted-content-length'] = io.size
|
47
49
|
if context.params.delete(:content_md5)
|
48
|
-
raise ArgumentError, 'content_md5
|
50
|
+
raise ArgumentError, 'Setting content_md5 on client side '\
|
51
|
+
'encrypted objects is deprecated.'
|
49
52
|
end
|
50
53
|
context.http_response.on_headers do
|
51
54
|
context.params[:body].close
|
@@ -54,9 +57,9 @@ module Aws
|
|
54
57
|
|
55
58
|
def apply_cse_user_agent(context)
|
56
59
|
if context.config.user_agent_suffix.nil?
|
57
|
-
context.config.user_agent_suffix =
|
58
|
-
elsif !context.config.user_agent_suffix.include?
|
59
|
-
context.config.user_agent_suffix +=
|
60
|
+
context.config.user_agent_suffix = EC_USER_AGENT
|
61
|
+
elsif !context.config.user_agent_suffix.include? EC_USER_AGENT
|
62
|
+
context.config.user_agent_suffix += " #{EC_USER_AGENT}"
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
@@ -1,12 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws
|
2
4
|
module S3
|
3
5
|
module EncryptionV2
|
4
6
|
module Errors
|
5
7
|
|
8
|
+
# Generic DecryptionError
|
6
9
|
class DecryptionError < RuntimeError; end
|
7
10
|
|
8
11
|
class EncryptionError < RuntimeError; end
|
9
12
|
|
13
|
+
# Raised when attempting to decrypt a legacy (V1) encrypted object
|
14
|
+
# when using a security_profile that does not support it.
|
15
|
+
class LegacyDecryptionError < DecryptionError
|
16
|
+
def initialize(*args)
|
17
|
+
msg = 'The requested object is ' \
|
18
|
+
'encrypted with V1 encryption schemas that have been disabled ' \
|
19
|
+
'by client configuration security_profile = :v2. Retry with ' \
|
20
|
+
':v2_and_legacy or re-encrypt the object.'
|
21
|
+
super(msg)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CEKAlgMismatchError < DecryptionError
|
26
|
+
def initialize(*args)
|
27
|
+
msg = 'The content encryption algorithm used at encryption time ' \
|
28
|
+
'does not match the algorithm stored for decryption time. ' \
|
29
|
+
'The object may be altered or corrupted.'
|
30
|
+
super(msg)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
10
34
|
end
|
11
35
|
end
|
12
36
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'base64'
|
2
4
|
|
3
5
|
module Aws
|
@@ -7,15 +9,21 @@ module Aws
|
|
7
9
|
class KmsCipherProvider
|
8
10
|
|
9
11
|
def initialize(options = {})
|
10
|
-
@kms_key_id = options[:kms_key_id]
|
12
|
+
@kms_key_id = validate_kms_key(options[:kms_key_id])
|
11
13
|
@kms_client = options[:kms_client]
|
14
|
+
@key_wrap_schema = validate_key_wrap(
|
15
|
+
options[:key_wrap_schema]
|
16
|
+
)
|
17
|
+
@content_encryption_schema = validate_cek(
|
18
|
+
options[:content_encryption_schema]
|
19
|
+
)
|
12
20
|
end
|
13
21
|
|
14
22
|
# @return [Array<Hash,Cipher>] Creates and returns a new encryption
|
15
23
|
# envelope and encryption cipher.
|
16
24
|
def encryption_cipher(options = {})
|
17
|
-
|
18
|
-
encryption_context = build_encryption_context(
|
25
|
+
validate_key_for_encryption
|
26
|
+
encryption_context = build_encryption_context(@content_encryption_schema, options)
|
19
27
|
key_data = @kms_client.generate_data_key(
|
20
28
|
key_id: @kms_key_id,
|
21
29
|
encryption_context: encryption_context,
|
@@ -26,9 +34,9 @@ module Aws
|
|
26
34
|
envelope = {
|
27
35
|
'x-amz-key-v2' => encode64(key_data.ciphertext_blob),
|
28
36
|
'x-amz-iv' => encode64(cipher.iv = cipher.random_iv),
|
29
|
-
'x-amz-cek-alg' =>
|
30
|
-
'x-amz-tag-len' =>
|
31
|
-
'x-amz-wrap-alg' =>
|
37
|
+
'x-amz-cek-alg' => @content_encryption_schema,
|
38
|
+
'x-amz-tag-len' => (AES_GCM_TAG_LEN_BYTES * 8).to_s,
|
39
|
+
'x-amz-wrap-alg' => @key_wrap_schema,
|
32
40
|
'x-amz-matdesc' => Json.dump(encryption_context)
|
33
41
|
}
|
34
42
|
cipher.auth_data = '' # auth_data must be set after key and iv
|
@@ -37,27 +45,45 @@ module Aws
|
|
37
45
|
|
38
46
|
# @return [Cipher] Given an encryption envelope, returns a
|
39
47
|
# decryption cipher.
|
40
|
-
def decryption_cipher(envelope, options={})
|
48
|
+
def decryption_cipher(envelope, options = {})
|
41
49
|
encryption_context = Json.load(envelope['x-amz-matdesc'])
|
42
|
-
cek_alg = envelope['x-amz-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
cek_alg = envelope['x-amz-cek-alg']
|
51
|
+
|
52
|
+
case envelope['x-amz-wrap-alg']
|
53
|
+
when 'kms'
|
54
|
+
unless options[:security_profile] == :v2_and_legacy
|
55
|
+
raise Errors::LegacyDecryptionError
|
56
|
+
end
|
57
|
+
when 'kms+context'
|
58
|
+
if cek_alg != encryption_context['aws:x-amz-cek-alg']
|
59
|
+
raise Errors::CEKAlgMismatchError
|
60
|
+
end
|
48
61
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
62
|
+
if encryption_context != build_encryption_context(cek_alg, options)
|
63
|
+
raise Errors::DecryptionError, 'Value of encryption context from'\
|
64
|
+
' envelope does not match the provided encryption context'
|
65
|
+
end
|
66
|
+
when 'AES/GCM'
|
67
|
+
raise ArgumentError, 'Key mismatch - Client is configured' \
|
68
|
+
' with a KMS key and the x-amz-wrap-alg is AES/GCM.'
|
69
|
+
when 'RSA-OAEP-SHA1'
|
70
|
+
raise ArgumentError, 'Key mismatch - Client is configured' \
|
71
|
+
' with a KMS key and the x-amz-wrap-alg is RSA-OAEP-SHA1.'
|
72
|
+
else
|
73
|
+
raise ArgumentError, 'Unsupported wrap-alg: ' \
|
74
|
+
"#{envelope['x-amz-wrap-alg']}"
|
53
75
|
end
|
54
76
|
|
55
|
-
|
77
|
+
any_cmk_mode = false || options[:kms_allow_decrypt_with_any_cmk]
|
78
|
+
decrypt_options = {
|
56
79
|
ciphertext_blob: decode64(envelope['x-amz-key-v2']),
|
57
80
|
encryption_context: encryption_context
|
58
|
-
|
59
|
-
|
81
|
+
}
|
82
|
+
unless any_cmk_mode
|
83
|
+
decrypt_options[:key_id] = @kms_key_id
|
84
|
+
end
|
60
85
|
|
86
|
+
key = @kms_client.decrypt(decrypt_options).plaintext
|
61
87
|
iv = decode64(envelope['x-amz-iv'])
|
62
88
|
block_mode =
|
63
89
|
case cek_alg
|
@@ -77,9 +103,46 @@ module Aws
|
|
77
103
|
|
78
104
|
private
|
79
105
|
|
106
|
+
def validate_key_wrap(key_wrap_schema)
|
107
|
+
case key_wrap_schema
|
108
|
+
when :kms_context then 'kms+context'
|
109
|
+
else
|
110
|
+
raise ArgumentError, "Unsupported key_wrap_schema: #{key_wrap_schema}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def validate_cek(content_encryption_schema)
|
115
|
+
case content_encryption_schema
|
116
|
+
when :aes_gcm_no_padding
|
117
|
+
"AES/GCM/NoPadding"
|
118
|
+
else
|
119
|
+
raise ArgumentError, "Unsupported content_encryption_schema: #{content_encryption_schema}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def validate_kms_key(kms_key_id)
|
124
|
+
if kms_key_id.nil? || kms_key_id.length.zero?
|
125
|
+
raise ArgumentError, 'KMS CMK ID was not specified. ' \
|
126
|
+
'Please specify a CMK ID, ' \
|
127
|
+
'or set kms_key_id: :kms_allow_decrypt_with_any_cmk to use ' \
|
128
|
+
'any valid CMK from the object.'
|
129
|
+
end
|
130
|
+
|
131
|
+
if kms_key_id.is_a?(Symbol) && kms_key_id != :kms_allow_decrypt_with_any_cmk
|
132
|
+
raise ArgumentError, 'kms_key_id must be a valid KMS CMK or be ' \
|
133
|
+
'set to :kms_allow_decrypt_with_any_cmk'
|
134
|
+
end
|
135
|
+
kms_key_id
|
136
|
+
end
|
137
|
+
|
80
138
|
def build_encryption_context(cek_alg, options = {})
|
81
139
|
kms_context = (options[:kms_encryption_context] || {})
|
82
140
|
.each_with_object({}) { |(k, v), h| h[k.to_s] = v }
|
141
|
+
if kms_context.include? 'aws:x-amz-cek-alg'
|
142
|
+
raise ArgumentError, 'Conflict in reserved KMS Encryption Context ' \
|
143
|
+
'key aws:x-amz-cek-alg. This value is reserved for the S3 ' \
|
144
|
+
'Encryption Client and cannot be set by the user.'
|
145
|
+
end
|
83
146
|
{
|
84
147
|
'aws:x-amz-cek-alg' => cek_alg
|
85
148
|
}.merge(kms_context)
|
@@ -93,6 +156,13 @@ module Aws
|
|
93
156
|
Base64.decode64(str)
|
94
157
|
end
|
95
158
|
|
159
|
+
def validate_key_for_encryption
|
160
|
+
if @kms_key_id == :kms_allow_decrypt_with_any_cmk
|
161
|
+
raise ArgumentError, 'Unable to encrypt/write objects with '\
|
162
|
+
'kms_key_id = :kms_allow_decrypt_with_any_cmk. Provide ' \
|
163
|
+
'a valid kms_key_id on client construction.'
|
164
|
+
end
|
165
|
+
end
|
96
166
|
end
|
97
167
|
end
|
98
168
|
end
|