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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aws-sdk-s3.rb +1 -1
  3. data/lib/aws-sdk-s3/bucket.rb +2 -2
  4. data/lib/aws-sdk-s3/client.rb +791 -505
  5. data/lib/aws-sdk-s3/encryption.rb +2 -0
  6. data/lib/aws-sdk-s3/encryption/client.rb +11 -0
  7. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +52 -28
  8. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +41 -5
  9. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +5 -5
  10. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +32 -3
  11. data/lib/aws-sdk-s3/encryption/utils.rb +23 -0
  12. data/lib/aws-sdk-s3/encryptionV2/client.rb +198 -22
  13. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +40 -12
  14. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +77 -10
  15. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +2 -0
  16. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +7 -4
  17. data/lib/aws-sdk-s3/encryptionV2/errors.rb +24 -0
  18. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +2 -0
  19. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +2 -0
  20. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +2 -0
  21. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +2 -0
  22. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +90 -20
  23. data/lib/aws-sdk-s3/encryptionV2/materials.rb +2 -0
  24. data/lib/aws-sdk-s3/encryptionV2/utils.rb +2 -15
  25. data/lib/aws-sdk-s3/encryption_v2.rb +4 -1
  26. data/lib/aws-sdk-s3/multipart_upload_part.rb +5 -5
  27. data/lib/aws-sdk-s3/object.rb +10 -9
  28. data/lib/aws-sdk-s3/object_summary.rb +23 -7
  29. data/lib/aws-sdk-s3/object_version.rb +2 -2
  30. data/lib/aws-sdk-s3/presigner.rb +2 -2
  31. data/lib/aws-sdk-s3/types.rb +63 -26
  32. 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
- kms_encryption_context: context[:encryption][:kms_encryption_context]
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['x-amz-tag-len']
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
- envelope.include? 'x-amz-tag-len'
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 = 'CSE_V2'
190
- elsif !context.config.user_agent_suffix.include? 'CSE_V2'
191
- context.config.user_agent_suffix += ' CSE_V2'
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
- wrap_alg = 'RSA-OAEP-SHA1'
20
- enc_key = encode64(encrypt_rsa(envelope_key(cipher), cek_alg))
28
+ enc_key = encode64(
29
+ encrypt_rsa(envelope_key(cipher), @content_encryption_schema)
30
+ )
21
31
  else
22
- wrap_alg = 'AES/GCM'
23
- enc_key = encode64(encrypt_aes_gcm(envelope_key(cipher), cek_alg))
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' => cek_alg,
28
- 'x-amz-tag-len' => 16 * 8,
29
- 'x-amz-wrap-alg' => 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::DecryptionError unless cek_alg == envelope['x-amz-cek-alg']
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
  module Aws
2
4
  module S3
3
5
  module EncryptionV2
@@ -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 is not supported'
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 = 'CSE_V2'
58
- elsif !context.config.user_agent_suffix.include? 'CSE_V2'
59
- context.config.user_agent_suffix += ' CSE_V2'
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
  module Aws
2
4
  module S3
3
5
  module EncryptionV2
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module EncryptionV2
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'stringio'
2
4
  require 'tempfile'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module EncryptionV2
@@ -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
- cek_alg = 'AES/GCM/NoPadding'
18
- encryption_context = build_encryption_context(cek_alg, options)
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' => cek_alg,
30
- 'x-amz-tag-len' => 16 * 8,
31
- 'x-amz-wrap-alg' => 'kms+context',
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-wrap-alg'] == 'kms+context' ?
43
- encryption_context['aws:x-amz-cek-alg'] : envelope['x-amz-cek-alg']
44
- if cek_alg != envelope['x-amz-cek-alg']
45
- raise Errors::DecryptionError, 'Value of cek-alg from envelope'\
46
- ' does not match the value in the encryption context'
47
- end
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
- if envelope['x-amz-wrap-alg'] == 'kms+context' &&
50
- encryption_context != build_encryption_context(cek_alg, options)
51
- raise Errors::DecryptionError, 'Value of encryption context from'\
52
- ' envelope does not match the provided encryption context'
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
- key = @kms_client.decrypt(
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
- ).plaintext
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