aws-sigv4 1.8.0 → 1.12.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/VERSION +1 -1
- data/lib/aws-sigv4/asymmetric_credentials.rb +99 -0
- data/lib/aws-sigv4/request.rb +3 -3
- data/lib/aws-sigv4/signature.rb +3 -0
- data/lib/aws-sigv4/signer.rb +89 -172
- data/lib/aws-sigv4.rb +1 -0
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58318b8045877e5842f7c0793c856e30b6bba8425988a4929bca3aaaf64fcc06
|
4
|
+
data.tar.gz: c9de352d0dee1c35637e86d1d4a3a8817d3ee6a4c3595f8e86436cf216d0a35d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b22918d3e6a784f4198b9b3583b6ce34e492819ec401862333d29f7c456402fe10718f7e9f30479d5097b89b19d8030400647572ee7204b8729093b16290f3f2
|
7
|
+
data.tar.gz: c15f22f66888fa2bbe1822bd833c2bc87c216b3c082ba1961682e0dcd2f5c0f427c2126ffb04354a3ba2b47c5a3fb375ad2381be543021b089687f589a4565fd
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,41 @@
|
|
1
1
|
Unreleased Changes
|
2
2
|
------------------
|
3
3
|
|
4
|
+
1.12.1 (2025-06-10)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
* Issue - Only load required `cgi` modules for Ruby 3.5.
|
8
|
+
|
9
|
+
1.12.0 (2025-06-02)
|
10
|
+
------------------
|
11
|
+
|
12
|
+
* Feature - AWS SDK for Ruby no longer supports Ruby runtime versions 2.5 and 2.6.
|
13
|
+
|
14
|
+
1.11.0 (2025-01-10)
|
15
|
+
------------------
|
16
|
+
|
17
|
+
* Feature - Add RBS signature files to support static type checking
|
18
|
+
|
19
|
+
1.10.1 (2024-10-21)
|
20
|
+
------------------
|
21
|
+
|
22
|
+
* Issue - Fix sigv4a signing issue with derive_asymmetric_key for certain credentials.
|
23
|
+
|
24
|
+
1.10.0 (2024-09-17)
|
25
|
+
------------------
|
26
|
+
|
27
|
+
* Feature - Remove CRT `sigv4a` signing capability.
|
28
|
+
|
29
|
+
1.9.1 (2024-07-29)
|
30
|
+
------------------
|
31
|
+
|
32
|
+
* Issue - Add missing require of `pathname` to `Signer`.
|
33
|
+
|
34
|
+
1.9.0 (2024-07-23)
|
35
|
+
------------------
|
36
|
+
|
37
|
+
* Feature - Support `sigv4a` signing algorithm without `aws-crt`.
|
38
|
+
|
4
39
|
1.8.0 (2023-11-28)
|
5
40
|
------------------
|
6
41
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.12.1
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Sigv4
|
5
|
+
# To make it easier to support mixed mode, we have created an asymmetric
|
6
|
+
# key derivation mechanism. This module derives
|
7
|
+
# asymmetric keys from the current secret for use with
|
8
|
+
# Asymmetric signatures.
|
9
|
+
# @api private
|
10
|
+
module AsymmetricCredentials
|
11
|
+
|
12
|
+
N_MINUS_2 = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - 2
|
13
|
+
|
14
|
+
# @return [OpenSSL::PKey::EC, Hash]
|
15
|
+
def self.derive_asymmetric_key(access_key_id, secret_access_key)
|
16
|
+
check_openssl_support!
|
17
|
+
label = 'AWS4-ECDSA-P256-SHA256'
|
18
|
+
bit_len = 256
|
19
|
+
counter = 0x1
|
20
|
+
input_key = "AWS4A#{secret_access_key}"
|
21
|
+
d = 0 # d will end up being the private key
|
22
|
+
while true do
|
23
|
+
|
24
|
+
kdf_context = access_key_id.unpack('C*') + [counter].pack('C').unpack('C') #1 byte for counter
|
25
|
+
input = label.unpack('C*') + [0x00] + kdf_context + [bit_len].pack('L>').unpack('CCCC') # 4 bytes (change endianess)
|
26
|
+
k0 = OpenSSL::HMAC.digest("SHA256", input_key, ([0, 0, 0, 0x01] + input).pack('C*'))
|
27
|
+
c = be_bytes_to_num( k0.unpack('C*') )
|
28
|
+
if c <= N_MINUS_2
|
29
|
+
d = c + 1
|
30
|
+
break
|
31
|
+
elsif counter > 0xFF
|
32
|
+
raise 'Counter exceeded 1 byte - unable to get asym creds'
|
33
|
+
else
|
34
|
+
counter += 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# compute the public key
|
39
|
+
group = OpenSSL::PKey::EC::Group.new('prime256v1')
|
40
|
+
public_key = group.generator.mul(d)
|
41
|
+
|
42
|
+
ec = generate_ec(public_key, d)
|
43
|
+
|
44
|
+
# pk_x and pk_y are not needed for signature, but useful in verification/testing
|
45
|
+
pk_b = public_key.to_octet_string(:uncompressed).unpack('C*') # 0x04 byte followed by 2 32-byte integers
|
46
|
+
pk_x = be_bytes_to_num(pk_b[1,32])
|
47
|
+
pk_y = be_bytes_to_num(pk_b[33,32])
|
48
|
+
[ec, {ec: ec, public_key: public_key, pk_x: pk_x, pk_y: pk_y, d: d}]
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# @return [Number] The value of the bytes interpreted as a big-endian
|
54
|
+
# unsigned integer.
|
55
|
+
def self.be_bytes_to_num(bytes)
|
56
|
+
x = 0
|
57
|
+
bytes.each { |b| x = (x*256) + b }
|
58
|
+
x
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Array] value of the BigNumber as a big-endian unsigned byte array.
|
62
|
+
def self.bn_to_be_bytes(bn)
|
63
|
+
bytes = []
|
64
|
+
while bn > 0
|
65
|
+
bytes << (bn & 0xff)
|
66
|
+
bn = bn >> 8
|
67
|
+
end
|
68
|
+
bytes.reverse
|
69
|
+
end
|
70
|
+
|
71
|
+
# Prior to openssl3 we could directly set public and private key on EC
|
72
|
+
# However, openssl3 deprecated those methods and we must now construct
|
73
|
+
# a der with the keys and load the EC from it.
|
74
|
+
def self.generate_ec(public_key, d)
|
75
|
+
# format reversed from: OpenSSL::ASN1.decode_all(OpenSSL::PKey::EC.new.to_der)
|
76
|
+
asn1 = OpenSSL::ASN1::Sequence([
|
77
|
+
OpenSSL::ASN1::Integer(OpenSSL::BN.new(1)),
|
78
|
+
OpenSSL::ASN1::OctetString(bn_to_be_bytes(d).pack('C*')),
|
79
|
+
OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ObjectId("prime256v1")], 0, :CONTEXT_SPECIFIC),
|
80
|
+
OpenSSL::ASN1::ASN1Data.new(
|
81
|
+
[OpenSSL::ASN1::BitString(public_key.to_octet_string(:uncompressed))],
|
82
|
+
1, :CONTEXT_SPECIFIC
|
83
|
+
)
|
84
|
+
])
|
85
|
+
OpenSSL::PKey::EC.new(asn1.to_der)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.check_openssl_support!
|
89
|
+
return true unless defined?(JRUBY_VERSION)
|
90
|
+
|
91
|
+
# See: https://github.com/jruby/jruby-openssl/issues/306
|
92
|
+
# JRuby-openssl < 0.15 does not support OpenSSL::PKey::EC::Point#mul
|
93
|
+
return true if OpenSSL::PKey::EC::Point.instance_methods.include?(:mul)
|
94
|
+
|
95
|
+
raise 'Sigv4a Asymmetric Credential derivation requires jruby-openssl >= 0.15'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/aws-sigv4/request.rb
CHANGED
@@ -7,7 +7,7 @@ module Aws
|
|
7
7
|
class Request
|
8
8
|
|
9
9
|
# @option options [required, String] :http_method
|
10
|
-
# @option options [required,
|
10
|
+
# @option options [required, String, URI::HTTP, URI::HTTPS] :endpoint
|
11
11
|
# @option options [Hash<String,String>] :headers ({})
|
12
12
|
# @option options [String, IO] :body ('')
|
13
13
|
def initialize(options = {})
|
@@ -30,12 +30,12 @@ module Aws
|
|
30
30
|
@http_method
|
31
31
|
end
|
32
32
|
|
33
|
-
# @param [String, HTTP
|
33
|
+
# @param [String, URI::HTTP, URI::HTTPS] endpoint
|
34
34
|
def endpoint=(endpoint)
|
35
35
|
@endpoint = URI.parse(endpoint.to_s)
|
36
36
|
end
|
37
37
|
|
38
|
-
# @return [HTTP
|
38
|
+
# @return [URI::HTTP, URI::HTTPS]
|
39
39
|
def endpoint
|
40
40
|
@endpoint
|
41
41
|
end
|
data/lib/aws-sigv4/signature.rb
CHANGED
@@ -32,6 +32,9 @@ module Aws
|
|
32
32
|
# @return [String] For debugging purposes.
|
33
33
|
attr_accessor :content_sha256
|
34
34
|
|
35
|
+
# @return [String] For debugging purposes.
|
36
|
+
attr_accessor :signature
|
37
|
+
|
35
38
|
# @return [Hash] Internal data for debugging purposes.
|
36
39
|
attr_accessor :extra
|
37
40
|
end
|
data/lib/aws-sigv4/signer.rb
CHANGED
@@ -5,7 +5,9 @@ require 'tempfile'
|
|
5
5
|
require 'time'
|
6
6
|
require 'uri'
|
7
7
|
require 'set'
|
8
|
-
require
|
8
|
+
require "cgi/escape"
|
9
|
+
require "cgi/util" if RUBY_VERSION < "3.5"
|
10
|
+
require 'pathname'
|
9
11
|
require 'aws-eventstream'
|
10
12
|
|
11
13
|
module Aws
|
@@ -73,25 +75,18 @@ module Aws
|
|
73
75
|
# and `#session_token`.
|
74
76
|
#
|
75
77
|
class Signer
|
76
|
-
|
77
|
-
@@use_crt =
|
78
|
-
begin
|
79
|
-
require 'aws-crt'
|
80
|
-
true
|
81
|
-
rescue LoadError
|
82
|
-
false
|
83
|
-
end
|
84
|
-
|
85
78
|
# @overload initialize(service:, region:, access_key_id:, secret_access_key:, session_token:nil, **options)
|
86
79
|
# @param [String] :service The service signing name, e.g. 's3'.
|
87
|
-
# @param [String] :region The region name, e.g. 'us-east-1'.
|
80
|
+
# @param [String] :region The region name, e.g. 'us-east-1'. When signing
|
81
|
+
# with sigv4a, this should be a comma separated list of regions.
|
88
82
|
# @param [String] :access_key_id
|
89
83
|
# @param [String] :secret_access_key
|
90
84
|
# @param [String] :session_token (nil)
|
91
85
|
#
|
92
86
|
# @overload initialize(service:, region:, credentials:, **options)
|
93
87
|
# @param [String] :service The service signing name, e.g. 's3'.
|
94
|
-
# @param [String] :region The region name, e.g. 'us-east-1'.
|
88
|
+
# @param [String] :region The region name, e.g. 'us-east-1'. When signing
|
89
|
+
# with sigv4a, this should be a comma separated list of regions.
|
95
90
|
# @param [Credentials] :credentials Any object that responds to the following
|
96
91
|
# methods:
|
97
92
|
#
|
@@ -102,7 +97,8 @@ module Aws
|
|
102
97
|
#
|
103
98
|
# @overload initialize(service:, region:, credentials_provider:, **options)
|
104
99
|
# @param [String] :service The service signing name, e.g. 's3'.
|
105
|
-
# @param [String] :region The region name, e.g. 'us-east-1'.
|
100
|
+
# @param [String] :region The region name, e.g. 'us-east-1'. When signing
|
101
|
+
# with sigv4a, this should be a comma separated list of regions.
|
106
102
|
# @param [#credentials] :credentials_provider An object that responds
|
107
103
|
# to `#credentials`, returning an object that responds to the following
|
108
104
|
# methods:
|
@@ -127,8 +123,7 @@ module Aws
|
|
127
123
|
# every other AWS service as of late 2016.
|
128
124
|
#
|
129
125
|
# @option options [Symbol] :signing_algorithm (:sigv4) The
|
130
|
-
# algorithm to use for signing.
|
131
|
-
# `aws-crt` is available.
|
126
|
+
# algorithm to use for signing.
|
132
127
|
#
|
133
128
|
# @option options [Boolean] :omit_session_token (false)
|
134
129
|
# (Supported only when `aws-crt` is available) If `true`,
|
@@ -136,8 +131,8 @@ module Aws
|
|
136
131
|
# but is treated as "unsigned" and does not contribute
|
137
132
|
# to the authorization signature.
|
138
133
|
#
|
139
|
-
# @option options [Boolean] :normalize_path (true)
|
140
|
-
#
|
134
|
+
# @option options [Boolean] :normalize_path (true) When `true`, the
|
135
|
+
# uri paths will be normalized when building the canonical request.
|
141
136
|
def initialize(options = {})
|
142
137
|
@service = extract_service(options)
|
143
138
|
@region = extract_region(options)
|
@@ -151,19 +146,6 @@ module Aws
|
|
151
146
|
@signing_algorithm = options.fetch(:signing_algorithm, :sigv4)
|
152
147
|
@normalize_path = options.fetch(:normalize_path, true)
|
153
148
|
@omit_session_token = options.fetch(:omit_session_token, false)
|
154
|
-
|
155
|
-
if @signing_algorithm == :sigv4a && !Signer.use_crt?
|
156
|
-
raise ArgumentError, 'You are attempting to sign a' \
|
157
|
-
' request with sigv4a which requires the `aws-crt` gem.'\
|
158
|
-
' Please install the gem or add it to your gemfile.'
|
159
|
-
end
|
160
|
-
|
161
|
-
if @signing_algorithm == 'sigv4-s3express'.to_sym &&
|
162
|
-
Signer.use_crt? && Aws::Crt::GEM_VERSION <= '0.1.9'
|
163
|
-
raise ArgumentError,
|
164
|
-
'This version of aws-crt does not support S3 Express. Please
|
165
|
-
update this gem to at least version 0.2.0.'
|
166
|
-
end
|
167
149
|
end
|
168
150
|
|
169
151
|
# @return [String]
|
@@ -224,7 +206,7 @@ module Aws
|
|
224
206
|
# @option request [required, String] :http_method One of
|
225
207
|
# 'GET', 'HEAD', 'PUT', 'POST', 'PATCH', or 'DELETE'
|
226
208
|
#
|
227
|
-
# @option request [required, String, URI::
|
209
|
+
# @option request [required, String, URI::HTTP, URI::HTTPS] :url
|
228
210
|
# The request URI. Must be a valid HTTP or HTTPS URI.
|
229
211
|
#
|
230
212
|
# @option request [optional, Hash] :headers ({}) A hash of headers
|
@@ -239,13 +221,11 @@ module Aws
|
|
239
221
|
# a `#headers` method. The headers must be applied to your request.
|
240
222
|
#
|
241
223
|
def sign_request(request)
|
242
|
-
|
243
|
-
return crt_sign_request(request) if Signer.use_crt?
|
244
|
-
|
245
224
|
creds, _ = fetch_credentials
|
246
225
|
|
247
226
|
http_method = extract_http_method(request)
|
248
227
|
url = extract_url(request)
|
228
|
+
Signer.normalize_path(url) if @normalize_path
|
249
229
|
headers = downcase_headers(request[:headers])
|
250
230
|
|
251
231
|
datetime = headers['x-amz-date']
|
@@ -258,7 +238,7 @@ module Aws
|
|
258
238
|
sigv4_headers = {}
|
259
239
|
sigv4_headers['host'] = headers['host'] || host(url)
|
260
240
|
sigv4_headers['x-amz-date'] = datetime
|
261
|
-
if creds.session_token
|
241
|
+
if creds.session_token && !@omit_session_token
|
262
242
|
if @signing_algorithm == 'sigv4-s3express'.to_sym
|
263
243
|
sigv4_headers['x-amz-s3session-token'] = creds.session_token
|
264
244
|
else
|
@@ -268,26 +248,45 @@ module Aws
|
|
268
248
|
|
269
249
|
sigv4_headers['x-amz-content-sha256'] ||= content_sha256 if @apply_checksum_header
|
270
250
|
|
251
|
+
if @signing_algorithm == :sigv4a && @region && !@region.empty?
|
252
|
+
sigv4_headers['x-amz-region-set'] = @region
|
253
|
+
end
|
271
254
|
headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
|
272
255
|
|
256
|
+
algorithm = sts_algorithm
|
257
|
+
|
273
258
|
# compute signature parts
|
274
259
|
creq = canonical_request(http_method, url, headers, content_sha256)
|
275
|
-
sts = string_to_sign(datetime, creq)
|
276
|
-
|
260
|
+
sts = string_to_sign(datetime, creq, algorithm)
|
261
|
+
|
262
|
+
sig =
|
263
|
+
if @signing_algorithm == :sigv4a
|
264
|
+
asymmetric_signature(creds, sts)
|
265
|
+
else
|
266
|
+
signature(creds.secret_access_key, date, sts)
|
267
|
+
end
|
268
|
+
|
269
|
+
algorithm = sts_algorithm
|
277
270
|
|
278
271
|
# apply signature
|
279
272
|
sigv4_headers['authorization'] = [
|
280
|
-
"
|
273
|
+
"#{algorithm} Credential=#{credential(creds, date)}",
|
281
274
|
"SignedHeaders=#{signed_headers(headers)}",
|
282
275
|
"Signature=#{sig}",
|
283
276
|
].join(', ')
|
284
277
|
|
278
|
+
# skip signing the session token, but include it in the headers
|
279
|
+
if creds.session_token && @omit_session_token
|
280
|
+
sigv4_headers['x-amz-security-token'] = creds.session_token
|
281
|
+
end
|
282
|
+
|
285
283
|
# Returning the signature components.
|
286
284
|
Signature.new(
|
287
285
|
headers: sigv4_headers,
|
288
286
|
string_to_sign: sts,
|
289
287
|
canonical_request: creq,
|
290
|
-
content_sha256: content_sha256
|
288
|
+
content_sha256: content_sha256,
|
289
|
+
signature: sig
|
291
290
|
)
|
292
291
|
end
|
293
292
|
|
@@ -327,7 +326,6 @@ module Aws
|
|
327
326
|
# signature value (a binary string) used at ':chunk-signature' needs to converted to
|
328
327
|
# hex-encoded string using #unpack
|
329
328
|
def sign_event(prior_signature, payload, encoder)
|
330
|
-
# Note: CRT does not currently provide event stream signing, so we always use the ruby implementation.
|
331
329
|
creds, _ = fetch_credentials
|
332
330
|
time = Time.now
|
333
331
|
headers = {}
|
@@ -386,7 +384,7 @@ module Aws
|
|
386
384
|
# @option options [required, String] :http_method The HTTP request method,
|
387
385
|
# e.g. 'GET', 'HEAD', 'PUT', 'POST', 'PATCH', or 'DELETE'.
|
388
386
|
#
|
389
|
-
# @option options [required, String,
|
387
|
+
# @option options [required, String, URI::HTTP, URI::HTTPS] :url
|
390
388
|
# The URI to sign.
|
391
389
|
#
|
392
390
|
# @option options [Hash] :headers ({}) Headers that should
|
@@ -414,13 +412,11 @@ module Aws
|
|
414
412
|
# @return [HTTPS::URI, HTTP::URI]
|
415
413
|
#
|
416
414
|
def presign_url(options)
|
417
|
-
|
418
|
-
return crt_presign_url(options) if Signer.use_crt?
|
419
|
-
|
420
415
|
creds, expiration = fetch_credentials
|
421
416
|
|
422
417
|
http_method = extract_http_method(options)
|
423
418
|
url = extract_url(options)
|
419
|
+
Signer.normalize_path(url) if @normalize_path
|
424
420
|
|
425
421
|
headers = downcase_headers(options[:headers])
|
426
422
|
headers['host'] ||= host(url)
|
@@ -433,8 +429,10 @@ module Aws
|
|
433
429
|
content_sha256 ||= options[:body_digest]
|
434
430
|
content_sha256 ||= sha256_hexdigest(options[:body] || '')
|
435
431
|
|
432
|
+
algorithm = sts_algorithm
|
433
|
+
|
436
434
|
params = {}
|
437
|
-
params['X-Amz-Algorithm'] =
|
435
|
+
params['X-Amz-Algorithm'] = algorithm
|
438
436
|
params['X-Amz-Credential'] = credential(creds, date)
|
439
437
|
params['X-Amz-Date'] = datetime
|
440
438
|
params['X-Amz-Expires'] = presigned_url_expiration(options, expiration, Time.strptime(datetime, "%Y%m%dT%H%M%S%Z")).to_s
|
@@ -447,6 +445,10 @@ module Aws
|
|
447
445
|
end
|
448
446
|
params['X-Amz-SignedHeaders'] = signed_headers(headers)
|
449
447
|
|
448
|
+
if @signing_algorithm == :sigv4a && @region
|
449
|
+
params['X-Amz-Region-Set'] = @region
|
450
|
+
end
|
451
|
+
|
450
452
|
params = params.map do |key, value|
|
451
453
|
"#{uri_escape(key)}=#{uri_escape(value)}"
|
452
454
|
end.join('&')
|
@@ -458,13 +460,23 @@ module Aws
|
|
458
460
|
end
|
459
461
|
|
460
462
|
creq = canonical_request(http_method, url, headers, content_sha256)
|
461
|
-
sts = string_to_sign(datetime, creq)
|
462
|
-
|
463
|
+
sts = string_to_sign(datetime, creq, algorithm)
|
464
|
+
signature =
|
465
|
+
if @signing_algorithm == :sigv4a
|
466
|
+
asymmetric_signature(creds, sts)
|
467
|
+
else
|
468
|
+
signature(creds.secret_access_key, date, sts)
|
469
|
+
end
|
470
|
+
url.query += '&X-Amz-Signature=' + signature
|
463
471
|
url
|
464
472
|
end
|
465
473
|
|
466
474
|
private
|
467
475
|
|
476
|
+
def sts_algorithm
|
477
|
+
@signing_algorithm == :sigv4a ? 'AWS4-ECDSA-P256-SHA256' : 'AWS4-HMAC-SHA256'
|
478
|
+
end
|
479
|
+
|
468
480
|
def canonical_request(http_method, url, headers, content_sha256)
|
469
481
|
[
|
470
482
|
http_method,
|
@@ -476,9 +488,9 @@ module Aws
|
|
476
488
|
].join("\n")
|
477
489
|
end
|
478
490
|
|
479
|
-
def string_to_sign(datetime, canonical_request)
|
491
|
+
def string_to_sign(datetime, canonical_request, algorithm)
|
480
492
|
[
|
481
|
-
|
493
|
+
algorithm,
|
482
494
|
datetime,
|
483
495
|
credential_scope(datetime[0,8]),
|
484
496
|
sha256_hexdigest(canonical_request),
|
@@ -511,10 +523,10 @@ module Aws
|
|
511
523
|
def credential_scope(date)
|
512
524
|
[
|
513
525
|
date,
|
514
|
-
@region,
|
526
|
+
(@region unless @signing_algorithm == :sigv4a),
|
515
527
|
@service,
|
516
|
-
'aws4_request'
|
517
|
-
].join('/')
|
528
|
+
'aws4_request'
|
529
|
+
].compact.join('/')
|
518
530
|
end
|
519
531
|
|
520
532
|
def credential(credentials, date)
|
@@ -529,6 +541,16 @@ module Aws
|
|
529
541
|
hexhmac(k_credentials, string_to_sign)
|
530
542
|
end
|
531
543
|
|
544
|
+
def asymmetric_signature(creds, string_to_sign)
|
545
|
+
ec, _ = Aws::Sigv4::AsymmetricCredentials.derive_asymmetric_key(
|
546
|
+
creds.access_key_id, creds.secret_access_key
|
547
|
+
)
|
548
|
+
sts_digest = OpenSSL::Digest::SHA256.digest(string_to_sign)
|
549
|
+
s = ec.dsa_sign_asn1(sts_digest)
|
550
|
+
|
551
|
+
Digest.hexencode(s)
|
552
|
+
end
|
553
|
+
|
532
554
|
# Comparing to original signature v4 algorithm,
|
533
555
|
# returned signature is a binary string instread of
|
534
556
|
# hex-encoded string. (Since ':chunk-signature' requires
|
@@ -757,129 +779,12 @@ module Aws
|
|
757
779
|
end
|
758
780
|
end
|
759
781
|
|
760
|
-
### CRT Code
|
761
|
-
|
762
|
-
# the credentials used by CRT must be a
|
763
|
-
# CRT StaticCredentialsProvider object
|
764
|
-
def crt_fetch_credentials
|
765
|
-
creds, expiration = fetch_credentials
|
766
|
-
crt_creds = Aws::Crt::Auth::StaticCredentialsProvider.new(
|
767
|
-
creds.access_key_id,
|
768
|
-
creds.secret_access_key,
|
769
|
-
creds.session_token
|
770
|
-
)
|
771
|
-
[crt_creds, expiration]
|
772
|
-
end
|
773
|
-
|
774
|
-
def crt_sign_request(request)
|
775
|
-
creds, _ = crt_fetch_credentials
|
776
|
-
http_method = extract_http_method(request)
|
777
|
-
url = extract_url(request)
|
778
|
-
headers = downcase_headers(request[:headers])
|
779
|
-
|
780
|
-
datetime =
|
781
|
-
if headers.include? 'x-amz-date'
|
782
|
-
Time.parse(headers.delete('x-amz-date'))
|
783
|
-
end
|
784
|
-
|
785
|
-
content_sha256 = headers.delete('x-amz-content-sha256')
|
786
|
-
content_sha256 ||= sha256_hexdigest(request[:body] || '')
|
787
|
-
|
788
|
-
sigv4_headers = {}
|
789
|
-
sigv4_headers['host'] = headers['host'] || host(url)
|
790
|
-
|
791
|
-
# Modify the user-agent to add usage of crt-signer
|
792
|
-
# This should be temporary during developer preview only
|
793
|
-
if headers.include? 'user-agent'
|
794
|
-
headers['user-agent'] = "#{headers['user-agent']} crt-signer/#{@signing_algorithm}/#{Aws::Sigv4::VERSION}"
|
795
|
-
sigv4_headers['user-agent'] = headers['user-agent']
|
796
|
-
end
|
797
|
-
|
798
|
-
headers = headers.merge(sigv4_headers) # merge so we do not modify given headers hash
|
799
|
-
|
800
|
-
config = Aws::Crt::Auth::SigningConfig.new(
|
801
|
-
algorithm: @signing_algorithm,
|
802
|
-
signature_type: :http_request_headers,
|
803
|
-
region: @region,
|
804
|
-
service: @service,
|
805
|
-
date: datetime,
|
806
|
-
signed_body_value: content_sha256,
|
807
|
-
signed_body_header_type: @apply_checksum_header ?
|
808
|
-
:sbht_content_sha256 : :sbht_none,
|
809
|
-
credentials: creds,
|
810
|
-
unsigned_headers: @unsigned_headers,
|
811
|
-
use_double_uri_encode: @uri_escape_path,
|
812
|
-
should_normalize_uri_path: @normalize_path,
|
813
|
-
omit_session_token: @omit_session_token
|
814
|
-
)
|
815
|
-
http_request = Aws::Crt::Http::Message.new(
|
816
|
-
http_method, url.to_s, headers
|
817
|
-
)
|
818
|
-
signable = Aws::Crt::Auth::Signable.new(http_request)
|
819
|
-
|
820
|
-
signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable)
|
821
|
-
|
822
|
-
Signature.new(
|
823
|
-
headers: sigv4_headers.merge(
|
824
|
-
downcase_headers(signing_result[:headers])
|
825
|
-
),
|
826
|
-
string_to_sign: 'CRT_INTERNAL',
|
827
|
-
canonical_request: 'CRT_INTERNAL',
|
828
|
-
content_sha256: content_sha256,
|
829
|
-
extra: {config: config, signable: signable}
|
830
|
-
)
|
831
|
-
end
|
832
|
-
|
833
|
-
def crt_presign_url(options)
|
834
|
-
creds, expiration = crt_fetch_credentials
|
835
|
-
|
836
|
-
http_method = extract_http_method(options)
|
837
|
-
url = extract_url(options)
|
838
|
-
headers = downcase_headers(options[:headers])
|
839
|
-
headers['host'] ||= host(url)
|
840
|
-
|
841
|
-
datetime = Time.strptime(headers.delete('x-amz-date'), "%Y%m%dT%H%M%S%Z") if headers['x-amz-date']
|
842
|
-
datetime ||= (options[:time] || Time.now)
|
843
|
-
|
844
|
-
content_sha256 = headers.delete('x-amz-content-sha256')
|
845
|
-
content_sha256 ||= options[:body_digest]
|
846
|
-
content_sha256 ||= sha256_hexdigest(options[:body] || '')
|
847
|
-
|
848
|
-
config = Aws::Crt::Auth::SigningConfig.new(
|
849
|
-
algorithm: @signing_algorithm,
|
850
|
-
signature_type: :http_request_query_params,
|
851
|
-
region: @region,
|
852
|
-
service: @service,
|
853
|
-
date: datetime,
|
854
|
-
signed_body_value: content_sha256,
|
855
|
-
signed_body_header_type: @apply_checksum_header ?
|
856
|
-
:sbht_content_sha256 : :sbht_none,
|
857
|
-
credentials: creds,
|
858
|
-
unsigned_headers: @unsigned_headers,
|
859
|
-
use_double_uri_encode: @uri_escape_path,
|
860
|
-
should_normalize_uri_path: @normalize_path,
|
861
|
-
omit_session_token: @omit_session_token,
|
862
|
-
expiration_in_seconds: presigned_url_expiration(options, expiration, datetime)
|
863
|
-
)
|
864
|
-
http_request = Aws::Crt::Http::Message.new(
|
865
|
-
http_method, url.to_s, headers
|
866
|
-
)
|
867
|
-
signable = Aws::Crt::Auth::Signable.new(http_request)
|
868
|
-
|
869
|
-
signing_result = Aws::Crt::Auth::Signer.sign_request(config, signable, http_method, url.to_s)
|
870
|
-
url = URI.parse(signing_result[:path])
|
871
|
-
|
872
|
-
if options[:extra] && options[:extra].is_a?(Hash)
|
873
|
-
options[:extra][:config] = config
|
874
|
-
options[:extra][:signable] = signable
|
875
|
-
end
|
876
|
-
url
|
877
|
-
end
|
878
|
-
|
879
782
|
class << self
|
880
783
|
|
784
|
+
# Kept for backwards compatability
|
785
|
+
# Always return false since we are not using crt signing functionality
|
881
786
|
def use_crt?
|
882
|
-
|
787
|
+
false
|
883
788
|
end
|
884
789
|
|
885
790
|
# @api private
|
@@ -896,6 +801,18 @@ module Aws
|
|
896
801
|
end
|
897
802
|
end
|
898
803
|
|
804
|
+
# @api private
|
805
|
+
def normalize_path(uri)
|
806
|
+
normalized_path = Pathname.new(uri.path).cleanpath.to_s
|
807
|
+
# Pathname is probably not correct to use. Empty paths will
|
808
|
+
# resolve to "." and should be disregarded
|
809
|
+
normalized_path = '' if normalized_path == '.'
|
810
|
+
# Ensure trailing slashes are correctly preserved
|
811
|
+
if uri.path.end_with?('/') && !normalized_path.end_with?('/')
|
812
|
+
normalized_path << '/'
|
813
|
+
end
|
814
|
+
uri.path = normalized_path
|
815
|
+
end
|
899
816
|
end
|
900
817
|
end
|
901
818
|
end
|
data/lib/aws-sigv4.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-sigv4
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.12.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amazon Web Services
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: aws-eventstream
|
@@ -32,7 +31,6 @@ dependencies:
|
|
32
31
|
version: 1.0.2
|
33
32
|
description: Amazon Web Services Signature Version 4 signing library. Generates sigv4
|
34
33
|
signature for HTTP requests.
|
35
|
-
email:
|
36
34
|
executables: []
|
37
35
|
extensions: []
|
38
36
|
extra_rdoc_files: []
|
@@ -41,6 +39,7 @@ files:
|
|
41
39
|
- LICENSE.txt
|
42
40
|
- VERSION
|
43
41
|
- lib/aws-sigv4.rb
|
42
|
+
- lib/aws-sigv4/asymmetric_credentials.rb
|
44
43
|
- lib/aws-sigv4/credentials.rb
|
45
44
|
- lib/aws-sigv4/errors.rb
|
46
45
|
- lib/aws-sigv4/request.rb
|
@@ -52,7 +51,6 @@ licenses:
|
|
52
51
|
metadata:
|
53
52
|
source_code_uri: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sigv4
|
54
53
|
changelog_uri: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sigv4/CHANGELOG.md
|
55
|
-
post_install_message:
|
56
54
|
rdoc_options: []
|
57
55
|
require_paths:
|
58
56
|
- lib
|
@@ -60,15 +58,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
58
|
requirements:
|
61
59
|
- - ">="
|
62
60
|
- !ruby/object:Gem::Version
|
63
|
-
version: '2.
|
61
|
+
version: '2.7'
|
64
62
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
63
|
requirements:
|
66
64
|
- - ">="
|
67
65
|
- !ruby/object:Gem::Version
|
68
66
|
version: '0'
|
69
67
|
requirements: []
|
70
|
-
rubygems_version: 3.
|
71
|
-
signing_key:
|
68
|
+
rubygems_version: 3.6.7
|
72
69
|
specification_version: 4
|
73
70
|
summary: AWS Signature Version 4 library.
|
74
71
|
test_files: []
|