aws-sdk-s3 1.61.2 → 1.83.1

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 (94) hide show
  1. checksums.yaml +5 -5
  2. data/lib/aws-sdk-s3.rb +5 -2
  3. data/lib/aws-sdk-s3/arn/access_point_arn.rb +62 -0
  4. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +71 -0
  5. data/lib/aws-sdk-s3/bucket.rb +61 -10
  6. data/lib/aws-sdk-s3/bucket_acl.rb +7 -0
  7. data/lib/aws-sdk-s3/bucket_cors.rb +15 -2
  8. data/lib/aws-sdk-s3/bucket_lifecycle.rb +14 -1
  9. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +14 -1
  10. data/lib/aws-sdk-s3/bucket_logging.rb +7 -0
  11. data/lib/aws-sdk-s3/bucket_notification.rb +7 -0
  12. data/lib/aws-sdk-s3/bucket_policy.rb +14 -1
  13. data/lib/aws-sdk-s3/bucket_region_cache.rb +2 -0
  14. data/lib/aws-sdk-s3/bucket_request_payment.rb +7 -0
  15. data/lib/aws-sdk-s3/bucket_tagging.rb +14 -1
  16. data/lib/aws-sdk-s3/bucket_versioning.rb +17 -0
  17. data/lib/aws-sdk-s3/bucket_website.rb +18 -3
  18. data/lib/aws-sdk-s3/client.rb +2521 -1187
  19. data/lib/aws-sdk-s3/client_api.rb +188 -18
  20. data/lib/aws-sdk-s3/customizations.rb +3 -0
  21. data/lib/aws-sdk-s3/customizations/bucket.rb +11 -4
  22. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
  23. data/lib/aws-sdk-s3/customizations/object.rb +23 -5
  24. data/lib/aws-sdk-s3/customizations/object_summary.rb +5 -0
  25. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
  26. data/lib/aws-sdk-s3/encryption.rb +4 -0
  27. data/lib/aws-sdk-s3/encryption/client.rb +18 -5
  28. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +72 -26
  29. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +43 -5
  30. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
  31. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +13 -2
  32. data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
  33. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +2 -0
  34. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +11 -3
  35. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
  36. data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
  37. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +34 -3
  38. data/lib/aws-sdk-s3/encryption/materials.rb +8 -6
  39. data/lib/aws-sdk-s3/encryption/utils.rb +25 -0
  40. data/lib/aws-sdk-s3/encryptionV2/client.rb +566 -0
  41. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +226 -0
  42. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +170 -0
  43. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +40 -0
  44. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +69 -0
  45. data/lib/aws-sdk-s3/encryptionV2/errors.rb +37 -0
  46. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +58 -0
  47. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +37 -0
  48. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +73 -0
  49. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +31 -0
  50. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +169 -0
  51. data/lib/aws-sdk-s3/encryptionV2/materials.rb +60 -0
  52. data/lib/aws-sdk-s3/encryptionV2/utils.rb +103 -0
  53. data/lib/aws-sdk-s3/encryption_v2.rb +23 -0
  54. data/lib/aws-sdk-s3/errors.rb +2 -0
  55. data/lib/aws-sdk-s3/event_streams.rb +7 -0
  56. data/lib/aws-sdk-s3/file_downloader.rb +10 -8
  57. data/lib/aws-sdk-s3/file_part.rb +2 -0
  58. data/lib/aws-sdk-s3/file_uploader.rb +14 -1
  59. data/lib/aws-sdk-s3/legacy_signer.rb +2 -0
  60. data/lib/aws-sdk-s3/multipart_file_uploader.rb +39 -2
  61. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +3 -1
  62. data/lib/aws-sdk-s3/multipart_upload.rb +18 -1
  63. data/lib/aws-sdk-s3/multipart_upload_error.rb +2 -0
  64. data/lib/aws-sdk-s3/multipart_upload_part.rb +66 -7
  65. data/lib/aws-sdk-s3/object.rb +174 -23
  66. data/lib/aws-sdk-s3/object_acl.rb +15 -0
  67. data/lib/aws-sdk-s3/object_copier.rb +2 -0
  68. data/lib/aws-sdk-s3/object_multipart_copier.rb +2 -0
  69. data/lib/aws-sdk-s3/object_summary.rb +185 -20
  70. data/lib/aws-sdk-s3/object_version.rb +44 -4
  71. data/lib/aws-sdk-s3/plugins/accelerate.rb +29 -38
  72. data/lib/aws-sdk-s3/plugins/arn.rb +187 -0
  73. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +2 -2
  74. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +3 -1
  75. data/lib/aws-sdk-s3/plugins/dualstack.rb +5 -1
  76. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +3 -4
  77. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +2 -0
  78. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +11 -3
  79. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +3 -1
  80. data/lib/aws-sdk-s3/plugins/location_constraint.rb +2 -0
  81. data/lib/aws-sdk-s3/plugins/md5s.rb +26 -25
  82. data/lib/aws-sdk-s3/plugins/redirects.rb +2 -0
  83. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
  84. data/lib/aws-sdk-s3/plugins/s3_signer.rb +31 -7
  85. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +3 -1
  86. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +118 -0
  87. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -0
  88. data/lib/aws-sdk-s3/presigned_post.rb +68 -32
  89. data/lib/aws-sdk-s3/presigner.rb +102 -34
  90. data/lib/aws-sdk-s3/resource.rb +4 -2
  91. data/lib/aws-sdk-s3/types.rb +2016 -256
  92. data/lib/aws-sdk-s3/waiters.rb +2 -0
  93. metadata +23 -6
  94. data/lib/aws-sdk-s3/plugins/bucket_arn.rb +0 -211
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # utility classes
2
4
  require 'aws-sdk-s3/bucket_region_cache'
3
5
  require 'aws-sdk-s3/encryption'
6
+ require 'aws-sdk-s3/encryption_v2'
4
7
  require 'aws-sdk-s3/file_part'
5
8
  require 'aws-sdk-s3/file_uploader'
6
9
  require 'aws-sdk-s3/file_downloader'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
 
3
5
  module Aws
@@ -5,16 +7,17 @@ module Aws
5
7
  class Bucket
6
8
  # Save the old initialize method so that we can call 'super'.
7
9
  old_initialize = instance_method(:initialize)
10
+ # Make the method redefinable
11
+ alias_method :initialize, :initialize
8
12
  # Define a new initialize method that extracts out a bucket ARN.
9
13
  define_method(:initialize) do |*args|
10
14
  old_initialize.bind(self).call(*args)
11
- bucket_name, region, arn = Plugins::BucketARN.resolve_arn!(
15
+ resolved_region, arn = Plugins::ARN.resolve_arn!(
12
16
  name,
13
17
  client.config.region,
14
18
  client.config.s3_use_arn_region
15
19
  )
16
- @name = bucket_name
17
- @client.config.region = region
20
+ @resolved_region = resolved_region
18
21
  @arn = arn
19
22
  end
20
23
 
@@ -98,7 +101,11 @@ module Aws
98
101
  if options[:virtual_host]
99
102
  "http://#{name}"
100
103
  elsif @arn
101
- Plugins::BucketARN.resolve_url!(URI.parse(s3_bucket_url), @arn).to_s
104
+ Plugins::ARN.resolve_url!(
105
+ client.config.endpoint.dup,
106
+ @arn,
107
+ @resolved_region
108
+ ).to_s
102
109
  else
103
110
  s3_bucket_url
104
111
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  class MultipartUpload
@@ -1,8 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  class Object
4
6
  alias size content_length
5
7
 
8
+ # Make the method redefinable
9
+ alias_method :copy_from, :copy_from
10
+
6
11
  # Copies another object to this object. Use `multipart_copy: true`
7
12
  # for large objects. This is required for objects that exceed 5GB.
8
13
  #
@@ -25,7 +30,8 @@ module Aws
25
30
  #
26
31
  # @option options [Integer] :content_length Only used when
27
32
  # `:multipart_copy` is `true`. Passing this options avoids a HEAD
28
- # request to query the source object size.
33
+ # request to query the source object size. Raises an `ArgumentError` if
34
+ # this option is provided when `:multipart_copy` is `false` or not set.
29
35
  #
30
36
  # @option options [S3::Client] :copy_source_client Only used when
31
37
  # `:multipart_copy` is `true` and the source object is in a
@@ -276,8 +282,8 @@ module Aws
276
282
  # # small files are uploaded in a single API call
277
283
  # obj.upload_file('/path/to/file')
278
284
  #
279
- # Files larger than `:multipart_threshold` are uploaded using the
280
- # Amazon S3 multipart upload APIs.
285
+ # Files larger than or equal to `:multipart_threshold` are uploaded
286
+ # using the Amazon S3 multipart upload APIs.
281
287
  #
282
288
  # # large files are automatically split into parts
283
289
  # # and the parts are uploaded in parallel
@@ -290,6 +296,14 @@ module Aws
290
296
  # etag = response.etag
291
297
  # end
292
298
  #
299
+ # You can provide a callback to monitor progress of the upload:
300
+ #
301
+ # # bytes and totals are each an array with 1 entry per part
302
+ # progress = Proc.new do |bytes, totals|
303
+ # puts bytes.map.with_index { |b, i| "Part #{i+1}: #{b} / #{totals[i]}"}.join(' ') + "Total: #{100.0 * bytes.sum / totals.sum }%" }
304
+ # end
305
+ # obj.upload_file('/path/to/file')
306
+ #
293
307
  # @param [String, Pathname, File, Tempfile] source A file on the local
294
308
  # file system that will be uploaded as this object. This can either be
295
309
  # a String or Pathname to the file, an open File object, or an open
@@ -299,13 +313,18 @@ module Aws
299
313
  # will be empty.
300
314
  #
301
315
  # @option options [Integer] :multipart_threshold (15728640) Files larger
302
- # than `:multipart_threshold` are uploaded using the S3 multipart APIs.
316
+ # than or equal to `:multipart_threshold` are uploaded using the S3
317
+ # multipart APIs.
303
318
  # Default threshold is 15MB.
304
319
  #
305
320
  # @option options [Integer] :thread_count (10) The number of parallel
306
321
  # multipart uploads. This option is not used if the file is smaller than
307
322
  # `:multipart_threshold`.
308
323
  #
324
+ # @option options [Proc] :progress_callback
325
+ # A Proc that will be called when each chunk of the upload is sent.
326
+ # It will be invoked with [bytes_read], [total_sizes]
327
+ #
309
328
  # @raise [MultipartUploadError] If an object is being uploaded in
310
329
  # parts, and the upload can not be completed, then the upload is
311
330
  # aborted and this error is raised. The raised error has a `#errors`
@@ -314,7 +333,6 @@ module Aws
314
333
  #
315
334
  # @return [Boolean] Returns `true` when the object is uploaded
316
335
  # without any errors.
317
- #
318
336
  def upload_file(source, options = {})
319
337
  uploading_options = options.dup
320
338
  uploader = FileUploader.new(
@@ -1,9 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  class ObjectSummary
4
6
 
5
7
  alias content_length size
6
8
 
9
+ # Make the method redefinable
10
+ alias_method :copy_from, :copy_from
11
+
7
12
  # @param (see Object#copy_from)
8
13
  # @options (see Object#copy_from)
9
14
  # @return (see Object#copy_from)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Aws::S3::Types::ListObjectVersionsOutput
2
4
 
3
5
  # TODO : Remove this customization once the resource code
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aws-sdk-s3/encryption/client'
2
4
  require 'aws-sdk-s3/encryption/decrypt_handler'
3
5
  require 'aws-sdk-s3/encryption/default_cipher_provider'
@@ -15,5 +17,7 @@ require 'aws-sdk-s3/encryption/default_key_provider'
15
17
  module Aws
16
18
  module S3
17
19
  module Encryption; end
20
+ AES_GCM_TAG_LEN_BYTES = 16
21
+ EC_USER_AGENT = 'S3CryptoV1n'
18
22
  end
19
23
  end
@@ -1,8 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
 
3
5
  module Aws
4
6
  module S3
5
7
 
8
+ # [MAINTENANCE MODE] There is a new version of the Encryption Client.
9
+ # AWS strongly recommends upgrading to the {Aws::S3::EncryptionV2::Client},
10
+ # which provides updated data security best practices.
11
+ # See documentation for {Aws::S3::EncryptionV2::Client}.
6
12
  # Provides an encryption client that encrypts and decrypts data client-side,
7
13
  # storing the encrypted data in Amazon S3.
8
14
  #
@@ -181,7 +187,7 @@ module Aws
181
187
 
182
188
  extend Deprecations
183
189
  extend Forwardable
184
- def_delegators :@client, :config, :delete_object, :head_object
190
+ def_delegators :@client, :config, :delete_object, :head_object, :build_request
185
191
 
186
192
  # Creates a new encryption client. You must provide one of the following
187
193
  # options:
@@ -227,6 +233,13 @@ module Aws
227
233
  @envelope_location = extract_location(options)
228
234
  @instruction_file_suffix = extract_suffix(options)
229
235
  end
236
+ deprecated :initialize,
237
+ message:
238
+ '[MAINTENANCE MODE] This version of the S3 Encryption client is currently in maintenance mode. ' \
239
+ 'AWS strongly recommends upgrading to the Aws::S3::EncryptionV2::Client, ' \
240
+ 'which provides updated data security best practices. ' \
241
+ 'See documentation for Aws::S3::EncryptionV2::Client.'
242
+
230
243
 
231
244
  # @return [S3::Client]
232
245
  attr_reader :client
@@ -331,7 +344,7 @@ module Aws
331
344
  elsif options[:encryption_key]
332
345
  DefaultKeyProvider.new(options)
333
346
  else
334
- msg = "you must pass a :kms_key_id, :key_provider, or :encryption_key"
347
+ msg = 'you must pass a :kms_key_id, :key_provider, or :encryption_key'
335
348
  raise ArgumentError, msg
336
349
  end
337
350
  end
@@ -351,8 +364,8 @@ module Aws
351
364
  if [:metadata, :instruction_file].include?(location)
352
365
  location
353
366
  else
354
- msg = ":envelope_location must be :metadata or :instruction_file "
355
- msg << "got #{location.inspect}"
367
+ msg = ':envelope_location must be :metadata or :instruction_file '\
368
+ "got #{location.inspect}"
356
369
  raise ArgumentError, msg
357
370
  end
358
371
  end
@@ -362,7 +375,7 @@ module Aws
362
375
  if String === suffix
363
376
  suffix
364
377
  else
365
- msg = ":instruction_file_suffix must be a String"
378
+ msg = ':instruction_file_suffix must be a String'
366
379
  raise ArgumentError, msg
367
380
  end
368
381
  end
@@ -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 Encryption
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
@@ -20,7 +23,17 @@ module Aws
20
23
  x-amz-matdesc
21
24
  )
22
25
 
23
- POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS + V2_ENVELOPE_KEYS).uniq
26
+ V2_OPTIONAL_KEYS = %w(x-amz-tag-len)
27
+
28
+ POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS +
29
+ V2_ENVELOPE_KEYS + V2_OPTIONAL_KEYS).uniq
30
+
31
+ POSSIBLE_WRAPPING_FORMATS = %w(
32
+ AES/GCM
33
+ kms
34
+ kms+context
35
+ RSA-OAEP-SHA1
36
+ )
24
37
 
25
38
  POSSIBLE_ENCRYPTION_FORMATS = %w(
26
39
  AES/GCM/NoPadding
@@ -28,8 +41,21 @@ module Aws
28
41
  AES/CBC/PKCS7Padding
29
42
  )
30
43
 
44
+ AUTH_REQUIRED_CEK_ALGS = %w(AES/GCM/NoPadding)
45
+
31
46
  def call(context)
32
47
  attach_http_event_listeners(context)
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
+ end
58
+
33
59
  @handler.call(context)
34
60
  end
35
61
 
@@ -38,9 +64,9 @@ module Aws
38
64
  def attach_http_event_listeners(context)
39
65
 
40
66
  context.http_response.on_headers(200) do
41
- cipher = decryption_cipher(context)
42
- decrypter = body_contains_auth_tag?(context) ?
43
- authenticated_decrypter(context, cipher) :
67
+ cipher, envelope = decryption_cipher(context)
68
+ decrypter = body_contains_auth_tag?(envelope) ?
69
+ authenticated_decrypter(context, cipher, envelope) :
44
70
  IODecrypter.new(cipher, context.http_response.body)
45
71
  context.http_response.body = decrypter
46
72
  end
@@ -60,8 +86,13 @@ module Aws
60
86
  end
61
87
 
62
88
  def decryption_cipher(context)
63
- if envelope = get_encryption_envelope(context)
64
- context[:encryption][:cipher_provider].decryption_cipher(envelope)
89
+ if (envelope = get_encryption_envelope(context))
90
+ cipher = context[:encryption][:cipher_provider]
91
+ .decryption_cipher(
92
+ envelope,
93
+ context[:encryption]
94
+ )
95
+ [cipher, envelope]
65
96
  else
66
97
  raise Errors::DecryptionError, "unable to locate encryption envelope"
67
98
  end
@@ -97,13 +128,12 @@ module Aws
97
128
  end
98
129
 
99
130
  def extract_envelope(hash)
131
+ return nil unless hash
100
132
  return v1_envelope(hash) if hash.key?('x-amz-key')
101
133
  return v2_envelope(hash) if hash.key?('x-amz-key-v2')
102
134
  if hash.keys.any? { |key| key.match(/^x-amz-key-(.+)$/) }
103
135
  msg = "unsupported envelope encryption version #{$1}"
104
136
  raise Errors::DecryptionError, msg
105
- else
106
- nil # no envelope found
107
137
  end
108
138
  end
109
139
 
@@ -117,39 +147,31 @@ module Aws
117
147
  msg = "unsupported content encrypting key (cek) format: #{alg}"
118
148
  raise Errors::DecryptionError, msg
119
149
  end
120
- unless envelope['x-amz-wrap-alg'] == 'kms'
121
- # possible to support
122
- # RSA/ECB/OAEPWithSHA-256AndMGF1Padding
150
+ unless POSSIBLE_WRAPPING_FORMATS.include? envelope['x-amz-wrap-alg']
123
151
  alg = envelope['x-amz-wrap-alg'].inspect
124
152
  msg = "unsupported key wrapping algorithm: #{alg}"
125
153
  raise Errors::DecryptionError, msg
126
154
  end
127
- unless V2_ENVELOPE_KEYS.sort == envelope.keys.sort
155
+ unless (missing_keys = V2_ENVELOPE_KEYS - envelope.keys).empty?
128
156
  msg = "incomplete v2 encryption envelope:\n"
129
- msg += " expected: #{V2_ENVELOPE_KEYS.join(',')}\n"
130
- msg += " got: #{envelope_keys.join(', ')}"
157
+ msg += " missing: #{missing_keys.join(',')}\n"
131
158
  raise Errors::DecryptionError, msg
132
159
  end
133
160
  envelope
134
161
  end
135
162
 
136
- # When the x-amz-meta-x-amz-tag-len header is present, it indicates
137
- # that the body of this object has a trailing auth tag. The header
138
- # indicates the length of that tag.
139
- #
140
163
  # This method fetches the tag from the end of the object by
141
164
  # making a GET Object w/range request. This auth tag is used
142
165
  # to initialize the cipher, and the decrypter truncates the
143
166
  # auth tag from the body when writing the final bytes.
144
- def authenticated_decrypter(context, cipher)
167
+ def authenticated_decrypter(context, cipher, envelope)
145
168
  if RUBY_VERSION.match(/1.9/)
146
- raise "authenticated decryption not supported by OpeenSSL in Ruby version ~> 1.9"
169
+ raise "authenticated decryption not supported by OpenSSL in Ruby version ~> 1.9"
147
170
  raise Aws::Errors::NonSupportedRubyVersionError, msg
148
171
  end
149
172
  http_resp = context.http_response
150
173
  content_length = http_resp.headers['content-length'].to_i
151
- auth_tag_length = http_resp.headers['x-amz-meta-x-amz-tag-len']
152
- auth_tag_length = auth_tag_length.to_i / 8
174
+ auth_tag_length = auth_tag_length(envelope)
153
175
 
154
176
  auth_tag = context.client.get_object(
155
177
  bucket: context.params[:bucket],
@@ -161,16 +183,40 @@ module Aws
161
183
  cipher.auth_data = ''
162
184
 
163
185
  # The encrypted object contains both the cipher text
164
- # plus a trailing auth tag. This decrypter will the body
165
- # expect for the trailing auth tag.
186
+ # plus a trailing auth tag.
166
187
  IOAuthDecrypter.new(
167
188
  io: http_resp.body,
168
189
  encrypted_content_length: content_length - auth_tag_length,
169
190
  cipher: cipher)
170
191
  end
171
192
 
172
- def body_contains_auth_tag?(context)
173
- context.http_response.headers['x-amz-meta-x-amz-tag-len']
193
+ def body_contains_auth_tag?(envelope)
194
+ AUTH_REQUIRED_CEK_ALGS.include?(envelope['x-amz-cek-alg'])
195
+ end
196
+
197
+ # Determine the auth tag length from the algorithm
198
+ # Validate it against the value provided in the x-amz-tag-len
199
+ # Return the tag length in bytes
200
+ def auth_tag_length(envelope)
201
+ tag_length =
202
+ case envelope['x-amz-cek-alg']
203
+ when 'AES/GCM/NoPadding' then AES_GCM_TAG_LEN_BYTES
204
+ else
205
+ raise ArgumentError, 'Unsupported cek-alg: ' \
206
+ "#{envelope['x-amz-cek-alg']}"
207
+ end
208
+ if (tag_length * 8) != envelope['x-amz-tag-len'].to_i
209
+ raise Errors::DecryptionError, 'x-amz-tag-len does not match expected'
210
+ end
211
+ tag_length
212
+ end
213
+
214
+ def apply_cse_user_agent(context)
215
+ if context.config.user_agent_suffix.nil?
216
+ context.config.user_agent_suffix = EC_USER_AGENT
217
+ elsif !context.config.user_agent_suffix.include? EC_USER_AGENT
218
+ context.config.user_agent_suffix += " #{EC_USER_AGENT}"
219
+ end
174
220
  end
175
221
 
176
222
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'base64'
2
4
 
3
5
  module Aws
@@ -24,11 +26,48 @@ module Aws
24
26
 
25
27
  # @return [Cipher] Given an encryption envelope, returns a
26
28
  # decryption cipher.
27
- def decryption_cipher(envelope)
29
+ def decryption_cipher(envelope, options = {})
28
30
  master_key = @key_provider.key_for(envelope['x-amz-matdesc'])
29
- key = Utils.decrypt(master_key, decode64(envelope['x-amz-key']))
30
- iv = decode64(envelope['x-amz-iv'])
31
- Utils.aes_decryption_cipher(:CBC, key, iv)
31
+ if envelope.key? 'x-amz-key'
32
+ # Support for decryption of legacy objects
33
+ key = Utils.decrypt(master_key, decode64(envelope['x-amz-key']))
34
+ iv = decode64(envelope['x-amz-iv'])
35
+ Utils.aes_decryption_cipher(:CBC, key, iv)
36
+ else
37
+ if envelope['x-amz-cek-alg'] != 'AES/GCM/NoPadding'
38
+ raise ArgumentError, 'Unsupported cek-alg: ' \
39
+ "#{envelope['x-amz-cek-alg']}"
40
+ end
41
+ key =
42
+ case envelope['x-amz-wrap-alg']
43
+ when 'AES/GCM'
44
+ if master_key.is_a? OpenSSL::PKey::RSA
45
+ raise ArgumentError, 'Key mismatch - Client is configured' \
46
+ ' with an RSA key and the x-amz-wrap-alg is AES/GCM.'
47
+ end
48
+ Utils.decrypt_aes_gcm(master_key,
49
+ decode64(envelope['x-amz-key-v2']),
50
+ envelope['x-amz-cek-alg'])
51
+ when 'RSA-OAEP-SHA1'
52
+ unless master_key.is_a? OpenSSL::PKey::RSA
53
+ raise ArgumentError, 'Key mismatch - Client is configured' \
54
+ ' with an AES key and the x-amz-wrap-alg is RSA-OAEP-SHA1.'
55
+ end
56
+ key, cek_alg = Utils.decrypt_rsa(master_key, decode64(envelope['x-amz-key-v2']))
57
+ raise Errors::DecryptionError unless cek_alg == envelope['x-amz-cek-alg']
58
+ key
59
+ when 'kms+context'
60
+ raise ArgumentError, 'Key mismatch - Client is configured' \
61
+ ' with a user provided key and the x-amz-wrap-alg is' \
62
+ ' kms+context. Please configure the client with the' \
63
+ ' required kms_key_id'
64
+ else
65
+ raise ArgumentError, 'Unsupported wrap-alg: ' \
66
+ "#{envelope['x-amz-wrap-alg']}"
67
+ end
68
+ iv = decode64(envelope['x-amz-iv'])
69
+ Utils.aes_decryption_cipher(:GCM, key, iv)
70
+ end
32
71
  end
33
72
 
34
73
  private
@@ -56,7 +95,6 @@ module Aws
56
95
  def decode64(str)
57
96
  Base64.decode64(str)
58
97
  end
59
-
60
98
  end
61
99
  end
62
100
  end