aws-sdk-resources 2.11.561 → 2.11.562

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aws-sdk-resources/services/s3.rb +1 -0
  3. data/lib/aws-sdk-resources/services/s3/encryption.rb +3 -0
  4. data/lib/aws-sdk-resources/services/s3/encryption/client.rb +24 -7
  5. data/lib/aws-sdk-resources/services/s3/encryption/decrypt_handler.rb +65 -25
  6. data/lib/aws-sdk-resources/services/s3/encryption/default_cipher_provider.rb +43 -5
  7. data/lib/aws-sdk-resources/services/s3/encryption/default_key_provider.rb +2 -0
  8. data/lib/aws-sdk-resources/services/s3/encryption/encrypt_handler.rb +13 -2
  9. data/lib/aws-sdk-resources/services/s3/encryption/errors.rb +2 -0
  10. data/lib/aws-sdk-resources/services/s3/encryption/io_auth_decrypter.rb +2 -0
  11. data/lib/aws-sdk-resources/services/s3/encryption/io_decrypter.rb +8 -1
  12. data/lib/aws-sdk-resources/services/s3/encryption/io_encrypter.rb +2 -0
  13. data/lib/aws-sdk-resources/services/s3/encryption/key_provider.rb +2 -0
  14. data/lib/aws-sdk-resources/services/s3/encryption/kms_cipher_provider.rb +36 -3
  15. data/lib/aws-sdk-resources/services/s3/encryption/materials.rb +8 -6
  16. data/lib/aws-sdk-resources/services/s3/encryption/utils.rb +25 -0
  17. data/lib/aws-sdk-resources/services/s3/encryptionV2/client.rb +559 -0
  18. data/lib/aws-sdk-resources/services/s3/encryptionV2/decrypt_handler.rb +214 -0
  19. data/lib/aws-sdk-resources/services/s3/encryptionV2/default_cipher_provider.rb +170 -0
  20. data/lib/aws-sdk-resources/services/s3/encryptionV2/default_key_provider.rb +40 -0
  21. data/lib/aws-sdk-resources/services/s3/encryptionV2/encrypt_handler.rb +69 -0
  22. data/lib/aws-sdk-resources/services/s3/encryptionV2/errors.rb +37 -0
  23. data/lib/aws-sdk-resources/services/s3/encryptionV2/io_auth_decrypter.rb +58 -0
  24. data/lib/aws-sdk-resources/services/s3/encryptionV2/io_decrypter.rb +37 -0
  25. data/lib/aws-sdk-resources/services/s3/encryptionV2/io_encrypter.rb +73 -0
  26. data/lib/aws-sdk-resources/services/s3/encryptionV2/key_provider.rb +31 -0
  27. data/lib/aws-sdk-resources/services/s3/encryptionV2/kms_cipher_provider.rb +169 -0
  28. data/lib/aws-sdk-resources/services/s3/encryptionV2/materials.rb +60 -0
  29. data/lib/aws-sdk-resources/services/s3/encryptionV2/utils.rb +103 -0
  30. data/lib/aws-sdk-resources/services/s3/encryption_v2.rb +24 -0
  31. metadata +18 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f6cb647e78df5134e70a85eb69e16c3bb862b5fdb1c133a399931d522154798
4
- data.tar.gz: 60beb67956debde6bca7341893d5e471b709a3c57de18c4aeec00ab83c9f4dd7
3
+ metadata.gz: b6ac0e253aa72fe0c66930c23a50c0f1e944e79e500febf995d11aba32bc80a7
4
+ data.tar.gz: 8f60593f8927f98912a6655231a22cdfadc747e276d0f1ef277835f0a8dc3163
5
5
  SHA512:
6
- metadata.gz: 7c6ed565e5f5462775e10bba44765e2f2def629bd2451f137b1ec0d0fed6918d0c604db95b480ec5cbde59c2eeea58b860a8f3d3c88f3a74fb61a50c39c204ba
7
- data.tar.gz: 9f64cbd1f823f98c362098b6a7816ee4db6efdc26483ff13e3e563383a62be93ae830a0a8b54e68b1df4dcd0adccc17130d926316b473c12d9ef6e385fde129a
6
+ metadata.gz: c6d6b6eddfead95cc30c36f3d6d760353edcea6387d4213c2164d5b5afa063836cf24c929e9f1d9efa4f1ce8b0a1ca1d53b6376531d494c11e38cf0056f57ac2
7
+ data.tar.gz: 4df465e650e56888d180f7c9b3adea51f4be02b5b456eb971a4c8193948aa0dd6a67cec90bc35cc3bc0b654599dbc2365fad31247df232d2b637dea7e9575287
@@ -7,6 +7,7 @@ module Aws
7
7
  require 'aws-sdk-resources/services/s3/multipart_upload'
8
8
 
9
9
  autoload :Encryption, 'aws-sdk-resources/services/s3/encryption'
10
+ autoload :EncryptionV2, 'aws-sdk-resources/services/s3/encryption_v2'
10
11
  autoload :FilePart, 'aws-sdk-resources/services/s3/file_part'
11
12
  autoload :FileUploader, 'aws-sdk-resources/services/s3/file_uploader'
12
13
  autoload :FileDownloader, 'aws-sdk-resources/services/s3/file_downloader'
@@ -2,6 +2,9 @@ module Aws
2
2
  module S3
3
3
  module Encryption
4
4
 
5
+ AES_GCM_TAG_LEN_BYTES = 16
6
+ EC_USER_AGENT = 'S3CryptoV1n'
7
+
5
8
  autoload :Client, 'aws-sdk-resources/services/s3/encryption/client'
6
9
  autoload :DecryptHandler, 'aws-sdk-resources/services/s3/encryption/decrypt_handler'
7
10
  autoload :DefaultCipherProvider, 'aws-sdk-resources/services/s3/encryption/default_cipher_provider'
@@ -1,6 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
1
5
  module Aws
2
6
  module S3
3
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}.
4
12
  # Provides an encryption client that encrypts and decrypts data client-side,
5
13
  # storing the encrypted data in Amazon S3.
6
14
  #
@@ -26,7 +34,7 @@ module Aws
26
34
  # data client-side.
27
35
  #
28
36
  # One of the benefits of envelope encryption is that if your master key
29
- # is compromised, you have the option of jut re-encrypting the stored
37
+ # is compromised, you have the option of just re-encrypting the stored
30
38
  # envelope symmetric keys, instead of re-encrypting all of the
31
39
  # data in your account.
32
40
  #
@@ -178,15 +186,17 @@ module Aws
178
186
  class Client
179
187
 
180
188
  extend Deprecations
189
+ extend Forwardable
190
+ def_delegators :@client, :config, :delete_object, :head_object, :build_request
181
191
 
182
- # Creates a new encryption client. You must provide on of the following
192
+ # Creates a new encryption client. You must provide one of the following
183
193
  # options:
184
194
  #
185
195
  # * `:encryption_key`
186
196
  # * `:kms_key_id`
187
197
  # * `:key_provider`
188
198
  #
189
- # You may also pass any other options accepted by {S3::Client#initialize}.
199
+ # You may also pass any other options accepted by `Client#initialize`.
190
200
  #
191
201
  # @option options [S3::Client] :client A basic S3 client that is used
192
202
  # to make api calls. If a `:client` is not provided, a new {S3::Client}
@@ -223,6 +233,13 @@ module Aws
223
233
  @envelope_location = extract_location(options)
224
234
  @instruction_file_suffix = extract_suffix(options)
225
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
+
226
243
 
227
244
  # @return [S3::Client]
228
245
  attr_reader :client
@@ -327,7 +344,7 @@ module Aws
327
344
  elsif options[:encryption_key]
328
345
  DefaultKeyProvider.new(options)
329
346
  else
330
- 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'
331
348
  raise ArgumentError, msg
332
349
  end
333
350
  end
@@ -347,8 +364,8 @@ module Aws
347
364
  if [:metadata, :instruction_file].include?(location)
348
365
  location
349
366
  else
350
- msg = ":envelope_location must be :metadata or :instruction_file "
351
- msg << "got #{location.inspect}"
367
+ msg = ':envelope_location must be :metadata or :instruction_file '\
368
+ "got #{location.inspect}"
352
369
  raise ArgumentError, msg
353
370
  end
354
371
  end
@@ -358,7 +375,7 @@ module Aws
358
375
  if String === suffix
359
376
  suffix
360
377
  else
361
- msg = ":instruction_file_suffix must be a String"
378
+ msg = ':instruction_file_suffix must be a String'
362
379
  raise ArgumentError, msg
363
380
  end
364
381
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'base64'
2
4
 
3
5
  module Aws
@@ -20,15 +22,29 @@ module Aws
20
22
  x-amz-matdesc
21
23
  )
22
24
 
23
- POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS + V2_ENVELOPE_KEYS).uniq
25
+ V2_OPTIONAL_KEYS = %w(x-amz-tag-len)
26
+
27
+ POSSIBLE_ENVELOPE_KEYS = (V1_ENVELOPE_KEYS +
28
+ V2_ENVELOPE_KEYS + V2_OPTIONAL_KEYS).uniq
29
+
30
+ POSSIBLE_WRAPPING_FORMATS = %w(
31
+ AES/GCM
32
+ kms
33
+ kms+context
34
+ RSA-OAEP-SHA1
35
+ )
24
36
 
25
37
  POSSIBLE_ENCRYPTION_FORMATS = %w(
26
38
  AES/GCM/NoPadding
27
39
  AES/CBC/PKCS5Padding
40
+ AES/CBC/PKCS7Padding
28
41
  )
29
42
 
43
+ AUTH_REQUIRED_CEK_ALGS = %w(AES/GCM/NoPadding)
44
+
30
45
  def call(context)
31
46
  attach_http_event_listeners(context)
47
+ apply_cse_user_agent(context)
32
48
  @handler.call(context)
33
49
  end
34
50
 
@@ -37,9 +53,9 @@ module Aws
37
53
  def attach_http_event_listeners(context)
38
54
 
39
55
  context.http_response.on_headers(200) do
40
- cipher = decryption_cipher(context)
41
- decrypter = body_contains_auth_tag?(context) ?
42
- authenticated_decrypter(context, cipher) :
56
+ cipher, envelope = decryption_cipher(context)
57
+ decrypter = body_contains_auth_tag?(envelope) ?
58
+ authenticated_decrypter(context, cipher, envelope) :
43
59
  IODecrypter.new(cipher, context.http_response.body)
44
60
  context.http_response.body = decrypter
45
61
  end
@@ -60,7 +76,12 @@ module Aws
60
76
 
61
77
  def decryption_cipher(context)
62
78
  if envelope = get_encryption_envelope(context)
63
- context[:encryption][:cipher_provider].decryption_cipher(envelope)
79
+ cipher = context[:encryption][:cipher_provider]
80
+ .decryption_cipher(
81
+ envelope,
82
+ kms_encryption_context: context[:encryption][:kms_encryption_context]
83
+ )
84
+ [cipher, envelope]
64
85
  else
65
86
  raise Errors::DecryptionError, "unable to locate encryption envelope"
66
87
  end
@@ -96,13 +117,12 @@ module Aws
96
117
  end
97
118
 
98
119
  def extract_envelope(hash)
120
+ return nil unless hash
99
121
  return v1_envelope(hash) if hash.key?('x-amz-key')
100
122
  return v2_envelope(hash) if hash.key?('x-amz-key-v2')
101
123
  if hash.keys.any? { |key| key.match(/^x-amz-key-(.+)$/) }
102
124
  msg = "unsupported envelope encryption version #{$1}"
103
125
  raise Errors::DecryptionError, msg
104
- else
105
- nil # no envelope found
106
126
  end
107
127
  end
108
128
 
@@ -116,35 +136,31 @@ module Aws
116
136
  msg = "unsupported content encrypting key (cek) format: #{alg}"
117
137
  raise Errors::DecryptionError, msg
118
138
  end
119
- unless envelope['x-amz-wrap-alg'] == 'kms'
120
- # possible to support
121
- # RSA/ECB/OAEPWithSHA-256AndMGF1Padding
139
+ unless POSSIBLE_WRAPPING_FORMATS.include? envelope['x-amz-wrap-alg']
122
140
  alg = envelope['x-amz-wrap-alg'].inspect
123
141
  msg = "unsupported key wrapping algorithm: #{alg}"
124
142
  raise Errors::DecryptionError, msg
125
143
  end
126
- unless V2_ENVELOPE_KEYS.sort == envelope.keys.sort
144
+ unless (missing_keys = V2_ENVELOPE_KEYS - envelope.keys).empty?
127
145
  msg = "incomplete v2 encryption envelope:\n"
128
- msg += " expected: #{V2_ENVELOPE_KEYS.join(',')}\n"
129
- msg += " got: #{envelope_keys.join(', ')}"
146
+ msg += " missing: #{missing_keys.join(',')}\n"
130
147
  raise Errors::DecryptionError, msg
131
148
  end
132
149
  envelope
133
150
  end
134
151
 
135
- # When the x-amz-meta-x-amz-tag-len header is present, it indicates
136
- # that the body of this object has a trailing auth tag. The header
137
- # indicates the length of that tag.
138
- #
139
152
  # This method fetches the tag from the end of the object by
140
153
  # making a GET Object w/range request. This auth tag is used
141
154
  # to initialize the cipher, and the decrypter truncates the
142
155
  # auth tag from the body when writing the final bytes.
143
- def authenticated_decrypter(context, cipher)
156
+ def authenticated_decrypter(context, cipher, envelope)
157
+ if RUBY_VERSION.match(/1.9/)
158
+ raise "authenticated decryption not supported by OpenSSL in Ruby version ~> 1.9"
159
+ raise Aws::Errors::NonSupportedRubyVersionError, msg
160
+ end
144
161
  http_resp = context.http_response
145
162
  content_length = http_resp.headers['content-length'].to_i
146
- auth_tag_length = http_resp.headers['x-amz-meta-x-amz-tag-len']
147
- auth_tag_length = auth_tag_length.to_i / 8
163
+ auth_tag_length = auth_tag_length(envelope)
148
164
 
149
165
  auth_tag = context.client.get_object(
150
166
  bucket: context.params[:bucket],
@@ -156,16 +172,40 @@ module Aws
156
172
  cipher.auth_data = ''
157
173
 
158
174
  # The encrypted object contains both the cipher text
159
- # plus a trailing auth tag. This decrypter will the body
160
- # expect for the trailing auth tag.
161
- decrypter = IOAuthDecrypter.new(
175
+ # plus a trailing auth tag.
176
+ IOAuthDecrypter.new(
162
177
  io: http_resp.body,
163
178
  encrypted_content_length: content_length - auth_tag_length,
164
179
  cipher: cipher)
165
180
  end
166
181
 
167
- def body_contains_auth_tag?(context)
168
- context.http_response.headers['x-amz-meta-x-amz-tag-len']
182
+ def body_contains_auth_tag?(envelope)
183
+ AUTH_REQUIRED_CEK_ALGS.include?(envelope['x-amz-cek-alg'])
184
+ end
185
+
186
+ # Determine the auth tag length from the algorithm
187
+ # Validate it against the value provided in the x-amz-tag-len
188
+ # Return the tag length in bytes
189
+ def auth_tag_length(envelope)
190
+ tag_length =
191
+ case envelope['x-amz-cek-alg']
192
+ when 'AES/GCM/NoPadding' then AES_GCM_TAG_LEN_BYTES
193
+ else
194
+ raise ArgumentError, 'Unsupported cek-alg: ' \
195
+ "#{envelope['x-amz-cek-alg']}"
196
+ end
197
+ if (tag_length * 8) != envelope['x-amz-tag-len'].to_i
198
+ raise Errors::DecryptionError, 'x-amz-tag-len does not match expected'
199
+ end
200
+ tag_length
201
+ end
202
+
203
+ def apply_cse_user_agent(context)
204
+ if context.config.user_agent_suffix.nil?
205
+ context.config.user_agent_suffix = EC_USER_AGENT
206
+ elsif !context.config.user_agent_suffix.include? EC_USER_AGENT
207
+ context.config.user_agent_suffix += " #{EC_USER_AGENT}"
208
+ end
169
209
  end
170
210
 
171
211
  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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Encryption
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'base64'
2
4
 
3
5
  module Aws
@@ -10,6 +12,7 @@ module Aws
10
12
  envelope, cipher = context[:encryption][:cipher_provider].encryption_cipher
11
13
  apply_encryption_envelope(context, envelope, cipher)
12
14
  apply_encryption_cipher(context, cipher)
15
+ apply_cse_user_agent(context)
13
16
  @handler.call(context)
14
17
  end
15
18
 
@@ -36,14 +39,22 @@ module Aws
36
39
  context.params[:body] = IOEncrypter.new(cipher, io)
37
40
  context.params[:metadata] ||= {}
38
41
  context.params[:metadata]['x-amz-unencrypted-content-length'] = io.size
39
- if md5 = context.params.delete(:content_md5)
40
- context.params[:metadata]['x-amz-unencrypted-content-md5'] = md5
42
+ if context.params.delete(:content_md5)
43
+ warn('Setting content_md5 on client side encrypted objects is deprecated')
41
44
  end
42
45
  context.http_response.on_headers do
43
46
  context.params[:body].close
44
47
  end
45
48
  end
46
49
 
50
+ def apply_cse_user_agent(context)
51
+ if context.config.user_agent_suffix.nil?
52
+ context.config.user_agent_suffix = EC_USER_AGENT
53
+ elsif !context.config.user_agent_suffix.include? EC_USER_AGENT
54
+ context.config.user_agent_suffix += " #{EC_USER_AGENT}"
55
+ end
56
+ end
57
+
47
58
  end
48
59
  end
49
60
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Encryption
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Encryption
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Encryption
@@ -8,7 +10,8 @@ module Aws
8
10
  # @param [IO#write] io An IO-like object that responds to `#write`.
9
11
  def initialize(cipher, io)
10
12
  @cipher = cipher.clone
11
- @io = io
13
+ # Ensure that IO is reset between retries
14
+ @io = io.tap { |io| io.truncate(0) if io.respond_to?(:truncate) }
12
15
  end
13
16
 
14
17
  # @return [#write]
@@ -23,6 +26,10 @@ module Aws
23
26
  @io.write(@cipher.final)
24
27
  end
25
28
 
29
+ def size
30
+ @io.size
31
+ end
32
+
26
33
  end
27
34
  end
28
35
  end
@@ -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 Encryption