linzer 0.7.3 → 0.7.4
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 +11 -0
- data/lib/linzer/common.rb +24 -8
- data/lib/linzer/ecdsa.rb +2 -0
- data/lib/linzer/ed25519.rb +10 -0
- data/lib/linzer/hmac.rb +8 -0
- data/lib/linzer/jws.rb +6 -1
- data/lib/linzer/key.rb +29 -3
- data/lib/linzer/message/adapter/abstract.rb +16 -21
- data/lib/linzer/message/adapter/http_gem/request.rb +1 -1
- data/lib/linzer/message/adapter/net_http/request.rb +8 -8
- data/lib/linzer/message/adapter/net_http/response.rb +16 -6
- data/lib/linzer/message/adapter/rack/common.rb +10 -10
- data/lib/linzer/message/field/parser.rb +50 -0
- data/lib/linzer/message/field.rb +56 -0
- data/lib/linzer/rsa.rb +4 -5
- data/lib/linzer/rsa_pss.rb +12 -5
- data/lib/linzer/signature.rb +13 -6
- data/lib/linzer/signer.rb +9 -5
- data/lib/linzer/verifier.rb +3 -3
- data/lib/linzer/version.rb +1 -1
- data/lib/linzer.rb +6 -1
- data/lib/rack/auth/signature/helpers.rb +8 -1
- data/lib/rack/auth/signature.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ca1f4d456be7ceedda5bbe7cfd205e696689da336408324c6ec06ed10440d07
|
4
|
+
data.tar.gz: 1db3b82c5644c65b6037cb844bea963aa803dd4bf74c93673aac8473dc647d38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce767d2e1c8df88b72321e8fbb513a9dadadb6436a4cefe6caa1a873f82cd4332b4f676ca0f355170156175077af2f675dabb22fbcb16ec7984950ca826a307c
|
7
|
+
data.tar.gz: affedd0f107f8ae2e9073ceb007896e5de9b45d2b50086bec7ff9dc6e771d208cffa7edb1e12ff414771a13eecc2597f2559b0d9c68a1a2ddb1010732afa2663
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.7.4] - 2025-06-30
|
4
|
+
|
5
|
+
- Add validation routines on key instances before performing
|
6
|
+
signing and verifying operations. This will catch obvious errors
|
7
|
+
like trying to sign a request with a public key.
|
8
|
+
|
9
|
+
- Fix bug with incorrect signature generation and verification on
|
10
|
+
messages with HTTP field identifiers including parameters. Those
|
11
|
+
fields were not serialized correctly and messages were being signed
|
12
|
+
with incorrect signature base.
|
13
|
+
|
3
14
|
## [0.7.3] - 2025-06-01
|
4
15
|
|
5
16
|
- Fix broken retrieval of header names from Rack responses.
|
data/lib/linzer/common.rb
CHANGED
@@ -2,23 +2,39 @@
|
|
2
2
|
|
3
3
|
module Linzer
|
4
4
|
module Common
|
5
|
-
def signature_base(message,
|
6
|
-
signature_base =
|
7
|
-
|
8
|
-
|
5
|
+
def signature_base(message, serialized_components, parameters)
|
6
|
+
signature_base =
|
7
|
+
serialized_components.each_with_object(+"") do |component, base|
|
8
|
+
base << "%s\n" % signature_base_line(component, message)
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
Starry.serialize([Starry::InnerList.new(components, parameters)])
|
11
|
+
signature_base << signature_params_line(serialized_components, parameters)
|
12
12
|
|
13
|
-
signature_base << "\"@signature-params\": #{signature_params}"
|
14
13
|
signature_base
|
15
14
|
end
|
16
15
|
module_function :signature_base
|
17
16
|
|
17
|
+
def signature_base_line(component, message)
|
18
|
+
field_id = FieldId.new(field_name: component)
|
19
|
+
"%s: %s" % [field_id.serialize, message[field_id]]
|
20
|
+
end
|
21
|
+
module_function :signature_base_line
|
22
|
+
|
23
|
+
def signature_params_line(serialized_components, parameters)
|
24
|
+
identifiers = serialized_components.map { |c| Starry.parse_item(c) }
|
25
|
+
|
26
|
+
signature_params =
|
27
|
+
Starry.serialize([Starry::InnerList.new(identifiers, parameters)])
|
28
|
+
|
29
|
+
"%s: %s" % [Starry.serialize("@signature-params"), signature_params]
|
30
|
+
end
|
31
|
+
module_function :signature_params_line
|
32
|
+
|
18
33
|
private
|
19
34
|
|
20
35
|
def validate_components(message, components)
|
21
|
-
if components.include?("@signature-params")
|
36
|
+
if components.include?('"@signature-params"') ||
|
37
|
+
components.any? { |c| c.start_with?('"@signature-params"') }
|
22
38
|
raise Error.new "Invalid component in signature input"
|
23
39
|
end
|
24
40
|
|
data/lib/linzer/ecdsa.rb
CHANGED
@@ -9,10 +9,12 @@ module Linzer
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def sign(data)
|
12
|
+
validate_signing_key
|
12
13
|
decode_der_signature(material.sign(@params[:digest], data))
|
13
14
|
end
|
14
15
|
|
15
16
|
def verify(signature, data)
|
17
|
+
validate_verify_key
|
16
18
|
material.verify(@params[:digest], der_signature(signature), data)
|
17
19
|
end
|
18
20
|
|
data/lib/linzer/ed25519.rb
CHANGED
@@ -4,12 +4,22 @@ module Linzer
|
|
4
4
|
module Ed25519
|
5
5
|
class Key < Linzer::Key
|
6
6
|
def sign(data)
|
7
|
+
validate_signing_key
|
7
8
|
material.sign(nil, data)
|
8
9
|
end
|
9
10
|
|
10
11
|
def verify(signature, data)
|
12
|
+
validate_verify_key
|
11
13
|
material.verify(nil, signature, data)
|
12
14
|
end
|
15
|
+
|
16
|
+
def public?
|
17
|
+
has_pem_public?
|
18
|
+
end
|
19
|
+
|
20
|
+
def private?
|
21
|
+
has_pem_private?
|
22
|
+
end
|
13
23
|
end
|
14
24
|
end
|
15
25
|
end
|
data/lib/linzer/hmac.rb
CHANGED
data/lib/linzer/jws.rb
CHANGED
@@ -27,16 +27,21 @@ module Linzer
|
|
27
27
|
|
28
28
|
class Key < Linzer::Key
|
29
29
|
def sign(data)
|
30
|
-
|
30
|
+
validate_signing_key
|
31
31
|
algo = resolve_algorithm
|
32
32
|
algo.sign(data: data, signing_key: signing_key)
|
33
33
|
end
|
34
34
|
|
35
35
|
def verify(signature, data)
|
36
|
+
validate_verify_key
|
36
37
|
algo = resolve_algorithm
|
37
38
|
algo.verify(data: data, signature: signature, verification_key: verify_key)
|
38
39
|
end
|
39
40
|
|
41
|
+
def public?
|
42
|
+
!!verify_key
|
43
|
+
end
|
44
|
+
|
40
45
|
private
|
41
46
|
|
42
47
|
def resolve_algorithm
|
data/lib/linzer/key.rb
CHANGED
@@ -17,12 +17,20 @@ module Linzer
|
|
17
17
|
|
18
18
|
def sign(*args)
|
19
19
|
abstract_error = "Cannot sign data, \"#{self.class}\" is an abstract class."
|
20
|
-
raise Error
|
20
|
+
raise Error, abstract_error
|
21
21
|
end
|
22
22
|
|
23
23
|
def verify(*args)
|
24
24
|
abstract_error = "Cannot verify signature, \"#{self.class}\" is an abstract class."
|
25
|
-
raise Error
|
25
|
+
raise Error, abstract_error
|
26
|
+
end
|
27
|
+
|
28
|
+
def public?
|
29
|
+
material.public?
|
30
|
+
end
|
31
|
+
|
32
|
+
def private?
|
33
|
+
material.private?
|
26
34
|
end
|
27
35
|
|
28
36
|
private
|
@@ -34,7 +42,25 @@ module Linzer
|
|
34
42
|
def validate_digest
|
35
43
|
no_digest = !@params.key?(:digest) || @params[:digest].nil? || String(@params[:digest]).empty?
|
36
44
|
no_digest_error = "Invalid key definition, no digest algorithm was selected."
|
37
|
-
raise
|
45
|
+
raise Error, no_digest_error if no_digest
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_signing_key
|
49
|
+
raise SigningError, "Private key is needed!" unless private?
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_verify_key
|
53
|
+
raise VerifyError, "Public key is needed!" unless public?
|
54
|
+
end
|
55
|
+
|
56
|
+
def has_pem_public?
|
57
|
+
material.public_to_pem.match?(/^-----BEGIN PUBLIC KEY-----/)
|
58
|
+
end
|
59
|
+
|
60
|
+
def has_pem_private?
|
61
|
+
material.private_to_pem.match?(/^-----BEGIN PRIVATE KEY-----/)
|
62
|
+
rescue
|
63
|
+
false
|
38
64
|
end
|
39
65
|
end
|
40
66
|
end
|
@@ -26,15 +26,10 @@ module Linzer
|
|
26
26
|
!!self[f]
|
27
27
|
end
|
28
28
|
|
29
|
-
def [](
|
30
|
-
|
31
|
-
return nil if
|
32
|
-
|
33
|
-
if field_name.start_with?("@")
|
34
|
-
retrieve(name, :derived)
|
35
|
-
else
|
36
|
-
retrieve(name, :field)
|
37
|
-
end
|
29
|
+
def [](field)
|
30
|
+
field_id = field.is_a?(FieldId) ? field : parse_field_name(field)
|
31
|
+
return nil if field_id.nil? || field_id.item.nil?
|
32
|
+
retrieve(field_id.item, field_id.derived? ? :derived : :field)
|
38
33
|
end
|
39
34
|
|
40
35
|
def header(name)
|
@@ -48,13 +43,16 @@ module Linzer
|
|
48
43
|
private
|
49
44
|
|
50
45
|
def parse_field_name(field_name)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
46
|
+
field_id = FieldId.new(field_name: field_name)
|
47
|
+
component = field_id.item
|
48
|
+
|
49
|
+
return nil if component.nil?
|
50
|
+
|
51
|
+
# 2.2.9
|
52
|
+
invalid = "@status component identifier is invalid in a request message"
|
53
|
+
raise Error, invalid if request? && component.value == "@status"
|
54
|
+
|
55
|
+
field_id
|
58
56
|
end
|
59
57
|
|
60
58
|
def validate_attached_request(message)
|
@@ -73,7 +71,7 @@ module Linzer
|
|
73
71
|
value = name.value
|
74
72
|
|
75
73
|
# Section 2.2.8 of RFC 9421
|
76
|
-
return nil if has_name && value !=
|
74
|
+
return nil if has_name && value != "@query-param"
|
77
75
|
|
78
76
|
# No derived values come from trailers section
|
79
77
|
return nil if method == :derived && name.parameters["tr"]
|
@@ -141,10 +139,7 @@ module Linzer
|
|
141
139
|
end
|
142
140
|
|
143
141
|
def req(field, method)
|
144
|
-
|
145
|
-
when :derived then @attached_request["@#{field}"]
|
146
|
-
when :field then @attached_request[field.to_s]
|
147
|
-
end
|
142
|
+
attached_request? ? @attached_request[String(field)] : nil
|
148
143
|
end
|
149
144
|
end
|
150
145
|
end
|
@@ -25,14 +25,14 @@ module Linzer
|
|
25
25
|
|
26
26
|
def derived(name)
|
27
27
|
case name.value
|
28
|
-
when
|
29
|
-
when
|
30
|
-
when
|
31
|
-
when
|
32
|
-
when
|
33
|
-
when
|
34
|
-
when
|
35
|
-
when
|
28
|
+
when "@method" then @operation.method
|
29
|
+
when "@target-uri" then @operation.uri.to_s
|
30
|
+
when "@authority" then @operation.uri.authority.downcase
|
31
|
+
when "@scheme" then @operation.uri.scheme.downcase
|
32
|
+
when "@request-target" then @operation.uri.request_uri
|
33
|
+
when "@path" then @operation.uri.path
|
34
|
+
when "@query" then "?%s" % String(@operation.uri.query)
|
35
|
+
when "@query-param" then query_param(name)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -17,16 +17,26 @@ module Linzer
|
|
17
17
|
@operation[name]
|
18
18
|
end
|
19
19
|
|
20
|
-
# XXX: this implementation is incomplete, e.g.: ;tr parameter is not supported yet
|
21
|
-
def [](field_name)
|
22
|
-
return @operation.code.to_i if field_name == "@status"
|
23
|
-
@operation[field_name]
|
24
|
-
end
|
25
|
-
|
26
20
|
def attach!(signature)
|
27
21
|
signature.to_h.each { |h, v| @operation[h] = v }
|
28
22
|
@operation
|
29
23
|
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def derived(name)
|
28
|
+
case name.value
|
29
|
+
when "@status" then @operation.code.to_i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# XXX: this implementation is incomplete, e.g.: ;bs parameter is not supported yet
|
34
|
+
def field(name)
|
35
|
+
has_tr = name.parameters["tr"]
|
36
|
+
return nil if has_tr # Net::HTTP doesn't support trailers
|
37
|
+
value = @operation[name.value.to_s]
|
38
|
+
value.dup&.strip
|
39
|
+
end
|
30
40
|
end
|
31
41
|
end
|
32
42
|
end
|
@@ -6,14 +6,14 @@ module Linzer
|
|
6
6
|
module Rack
|
7
7
|
module Common
|
8
8
|
DERIVED_COMPONENT = {
|
9
|
-
method:
|
10
|
-
authority:
|
11
|
-
path:
|
12
|
-
status:
|
13
|
-
"target-uri"
|
14
|
-
scheme:
|
15
|
-
"request-target"
|
16
|
-
query:
|
9
|
+
"@method" => :request_method,
|
10
|
+
"@authority" => :authority,
|
11
|
+
"@path" => :path_info,
|
12
|
+
"@status" => :status,
|
13
|
+
"@target-uri" => :url,
|
14
|
+
"@scheme" => :scheme,
|
15
|
+
"@request-target" => :fullpath,
|
16
|
+
"@query" => :query_string
|
17
17
|
}.freeze
|
18
18
|
private_constant :DERIVED_COMPONENT
|
19
19
|
|
@@ -51,8 +51,8 @@ module Linzer
|
|
51
51
|
method = DERIVED_COMPONENT[name.value]
|
52
52
|
|
53
53
|
value = case name.value
|
54
|
-
when
|
55
|
-
when
|
54
|
+
when "@query" then derive(@operation, method)
|
55
|
+
when "@query-param" then query_param(name)
|
56
56
|
end
|
57
57
|
|
58
58
|
return nil if !method && !value
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Linzer
|
4
|
+
class Message
|
5
|
+
class Field
|
6
|
+
class Identifier
|
7
|
+
module Parser
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def parse(field_name)
|
11
|
+
case
|
12
|
+
when field_name.match?(/";/), field_name.start_with?('"')
|
13
|
+
Starry.parse_item(field_name)
|
14
|
+
when field_name.match?(/;/)
|
15
|
+
parse_unserialized_input(field_name)
|
16
|
+
when field_name.start_with?("@"), field_name.match?(/^[a-z]/)
|
17
|
+
Starry.parse_item(Starry.serialize(field_name))
|
18
|
+
else
|
19
|
+
raise Error, "Invalid component identifier: '#{field_name}'!"
|
20
|
+
end
|
21
|
+
rescue Starry::ParseError => ex
|
22
|
+
parse_error = "Failed to parse component identifier: '#{field_name}'!"
|
23
|
+
raise Error, parse_error, cause: ex
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def parse_unserialized_input(field_name)
|
29
|
+
field, *raw_params = field_name.split(";")
|
30
|
+
item = Starry.parse_item(Starry.serialize(field))
|
31
|
+
item.parameters = collect_parameters(raw_params)
|
32
|
+
item
|
33
|
+
end
|
34
|
+
|
35
|
+
def collect_parameters(str)
|
36
|
+
params = str.map do |param|
|
37
|
+
if (tokens = param.split("=")) == [param] # e.g.: ";bs"
|
38
|
+
{param => true}
|
39
|
+
else
|
40
|
+
Hash[*tokens.first(2)] # e.g.: ";key=\"foo\""
|
41
|
+
.transform_values! { |v| Starry.parse_item(v).value }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
params.reduce({}, :merge)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Linzer
|
4
|
+
class Message
|
5
|
+
class Field
|
6
|
+
module IdentifierMethods
|
7
|
+
def initialize(field_name:)
|
8
|
+
@item = Identifier::Parser.parse(field_name) rescue nil
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :item
|
13
|
+
|
14
|
+
def derived?
|
15
|
+
item&.value&.start_with?("@")
|
16
|
+
end
|
17
|
+
|
18
|
+
def serialize
|
19
|
+
raise Error, "Invalid component identifier: '#{field_name}'!" unless item
|
20
|
+
Starry.serialize(@item)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Excluded from coverage as obviously both branches cannot be covered
|
25
|
+
# on a single test run.
|
26
|
+
# :nocov:
|
27
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2.0")
|
28
|
+
class Identifier < Struct.new(:field_name, keyword_init: true); end
|
29
|
+
else
|
30
|
+
class Identifier < Data.define(:field_name); end
|
31
|
+
end
|
32
|
+
# :nocov:
|
33
|
+
|
34
|
+
Identifier.include Message::Field::IdentifierMethods
|
35
|
+
|
36
|
+
class Identifier
|
37
|
+
class << self
|
38
|
+
def serialize(component)
|
39
|
+
new(field_name: component).serialize
|
40
|
+
end
|
41
|
+
|
42
|
+
def serialize_components(components)
|
43
|
+
components.map(&method(:serialize))
|
44
|
+
end
|
45
|
+
|
46
|
+
def deserialize_components(components)
|
47
|
+
components.map do |c|
|
48
|
+
item = Starry.parse_item(c)
|
49
|
+
item.parameters.empty? ? item.value : Starry.serialize(item)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/linzer/rsa.rb
CHANGED
@@ -9,14 +9,13 @@ module Linzer
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def sign(data)
|
12
|
-
|
13
|
-
|
12
|
+
validate_signing_key
|
13
|
+
material.sign(@params[:digest], data)
|
14
14
|
end
|
15
15
|
|
16
16
|
def verify(signature, data)
|
17
|
-
|
18
|
-
|
19
|
-
false
|
17
|
+
validate_verify_key
|
18
|
+
material.verify(@params[:digest], signature, data)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
data/lib/linzer/rsa_pss.rb
CHANGED
@@ -11,19 +11,26 @@ module Linzer
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def sign(data)
|
14
|
-
|
15
|
-
|
14
|
+
validate_signing_key
|
15
|
+
material.sign(@params[:digest], data, signature_options)
|
16
16
|
end
|
17
17
|
|
18
18
|
def verify(signature, data)
|
19
|
-
|
20
|
-
|
19
|
+
validate_verify_key
|
20
|
+
material.verify(
|
21
21
|
@params[:digest],
|
22
22
|
signature,
|
23
23
|
data,
|
24
24
|
signature_options
|
25
25
|
)
|
26
|
-
|
26
|
+
end
|
27
|
+
|
28
|
+
def public?
|
29
|
+
has_pem_public?
|
30
|
+
end
|
31
|
+
|
32
|
+
def private?
|
33
|
+
has_pem_private?
|
27
34
|
end
|
28
35
|
|
29
36
|
private
|
data/lib/linzer/signature.rb
CHANGED
@@ -11,9 +11,13 @@ module Linzer
|
|
11
11
|
end
|
12
12
|
|
13
13
|
attr_reader :metadata, :value, :parameters, :label
|
14
|
-
alias_method :
|
14
|
+
alias_method :serialized_components, :metadata
|
15
15
|
alias_method :bytes, :value
|
16
16
|
|
17
|
+
def components
|
18
|
+
FieldId.deserialize_components(serialized_components)
|
19
|
+
end
|
20
|
+
|
17
21
|
def created
|
18
22
|
Integer(parameters["created"])
|
19
23
|
rescue
|
@@ -28,10 +32,13 @@ module Linzer
|
|
28
32
|
|
29
33
|
def to_h
|
30
34
|
{
|
31
|
-
"signature"
|
32
|
-
"signature-input" =>
|
33
|
-
Starry.
|
34
|
-
Starry
|
35
|
+
"signature" => Starry.serialize({label => value}),
|
36
|
+
"signature-input" => Starry.serialize({
|
37
|
+
label => Starry::InnerList.new(
|
38
|
+
serialized_components.map { |c| Starry.parse_item(c) },
|
39
|
+
parameters
|
40
|
+
)
|
41
|
+
})
|
35
42
|
}
|
36
43
|
end
|
37
44
|
|
@@ -56,7 +63,7 @@ module Linzer
|
|
56
63
|
|
57
64
|
fail_due_invalid_components unless input[label].value.respond_to?(:each)
|
58
65
|
|
59
|
-
components = input[label].value.map(
|
66
|
+
components = input[label].value.map { |c| Starry.serialize_item(c) }
|
60
67
|
parameters = input[label].parameters
|
61
68
|
|
62
69
|
new(components, raw_signature, label, parameters)
|
data/lib/linzer/signer.rb
CHANGED
@@ -8,15 +8,16 @@ module Linzer
|
|
8
8
|
include Common
|
9
9
|
|
10
10
|
def sign(key, message, components, options = {})
|
11
|
-
|
11
|
+
serialized_components = FieldId.serialize_components(Array(components))
|
12
|
+
validate key, message, serialized_components
|
12
13
|
|
13
14
|
parameters = populate_parameters(key, options)
|
14
|
-
signature_base = signature_base(message,
|
15
|
+
signature_base = signature_base(message, serialized_components, parameters)
|
15
16
|
|
16
17
|
signature = key.sign(signature_base)
|
17
18
|
label = options[:label] || DEFAULT_LABEL
|
18
19
|
|
19
|
-
Linzer::Signature.build(serialize(signature,
|
20
|
+
Linzer::Signature.build(serialize(signature, serialized_components, parameters, label))
|
20
21
|
end
|
21
22
|
|
22
23
|
def default_label
|
@@ -55,8 +56,11 @@ module Linzer
|
|
55
56
|
{
|
56
57
|
"signature" => Starry.serialize({label => signature}),
|
57
58
|
"signature-input" =>
|
58
|
-
Starry.serialize(
|
59
|
-
Starry::InnerList.new(
|
59
|
+
Starry.serialize(label =>
|
60
|
+
Starry::InnerList.new(
|
61
|
+
components.map { |c| Starry.parse_item(c) },
|
62
|
+
parameters
|
63
|
+
))
|
60
64
|
}
|
61
65
|
end
|
62
66
|
end
|
data/lib/linzer/verifier.rb
CHANGED
@@ -9,9 +9,9 @@ module Linzer
|
|
9
9
|
validate message, key, signature, no_older_than: no_older_than
|
10
10
|
|
11
11
|
parameters = signature.parameters
|
12
|
-
|
12
|
+
serialized_components = signature.serialized_components
|
13
13
|
|
14
|
-
signature_base = signature_base(message,
|
14
|
+
signature_base = signature_base(message, serialized_components, parameters)
|
15
15
|
|
16
16
|
verify_or_fail key, signature.value, signature_base
|
17
17
|
end
|
@@ -31,7 +31,7 @@ module Linzer
|
|
31
31
|
raise VerifyError, "Components cannot be null" if signature.components.nil?
|
32
32
|
|
33
33
|
begin
|
34
|
-
validate_components message, signature.
|
34
|
+
validate_components message, signature.serialized_components
|
35
35
|
rescue Error => ex
|
36
36
|
raise VerifyError, ex.message, cause: ex
|
37
37
|
end
|
data/lib/linzer/version.rb
CHANGED
data/lib/linzer.rb
CHANGED
@@ -14,6 +14,8 @@ require_relative "linzer/options"
|
|
14
14
|
require_relative "linzer/message"
|
15
15
|
require_relative "linzer/message/adapter"
|
16
16
|
require_relative "linzer/message/wrapper"
|
17
|
+
require_relative "linzer/message/field"
|
18
|
+
require_relative "linzer/message/field/parser"
|
17
19
|
require_relative "linzer/signature"
|
18
20
|
require_relative "linzer/key"
|
19
21
|
require_relative "linzer/rsa"
|
@@ -25,7 +27,6 @@ require_relative "linzer/key/helper"
|
|
25
27
|
require_relative "linzer/signer"
|
26
28
|
require_relative "linzer/verifier"
|
27
29
|
require_relative "linzer/http"
|
28
|
-
require_relative "rack/auth/signature"
|
29
30
|
|
30
31
|
module Linzer
|
31
32
|
class Error < StandardError; end
|
@@ -50,4 +51,8 @@ module Linzer
|
|
50
51
|
Linzer::Common.signature_base(message, components, parameters)
|
51
52
|
end
|
52
53
|
end
|
54
|
+
|
55
|
+
FieldId = Message::Field::Identifier
|
53
56
|
end
|
57
|
+
|
58
|
+
require_relative "rack/auth/signature"
|
@@ -36,6 +36,11 @@ module Rack
|
|
36
36
|
end
|
37
37
|
|
38
38
|
module Configuration
|
39
|
+
def default_covered_components
|
40
|
+
Linzer::Options::DEFAULT[:covered_components]
|
41
|
+
end
|
42
|
+
module_function :default_covered_components
|
43
|
+
|
39
44
|
DEFAULT_OPTIONS = {
|
40
45
|
signatures: {
|
41
46
|
reject_older_than: 900,
|
@@ -45,7 +50,9 @@ module Rack
|
|
45
50
|
tag_required: false,
|
46
51
|
expires_required: false,
|
47
52
|
keyid_required: false,
|
48
|
-
covered_components:
|
53
|
+
covered_components:
|
54
|
+
Linzer::FieldId
|
55
|
+
.serialize_components(default_covered_components),
|
49
56
|
error_response: {body: [], status: 401, headers: {}}
|
50
57
|
},
|
51
58
|
keys: {}
|
data/lib/rack/auth/signature.rb
CHANGED
@@ -85,7 +85,7 @@ module Rack
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def has_required_components?
|
88
|
-
components = @signature.
|
88
|
+
components = @signature.serialized_components || []
|
89
89
|
covered_components = options[:signatures][:covered_components]
|
90
90
|
warning = "Insufficient coverage by signature. Consult S 7.2.1. in RFC"
|
91
91
|
logger.warn warning if covered_components.empty?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: linzer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Landaeta
|
@@ -210,6 +210,8 @@ files:
|
|
210
210
|
- lib/linzer/message/adapter/rack/common.rb
|
211
211
|
- lib/linzer/message/adapter/rack/request.rb
|
212
212
|
- lib/linzer/message/adapter/rack/response.rb
|
213
|
+
- lib/linzer/message/field.rb
|
214
|
+
- lib/linzer/message/field/parser.rb
|
213
215
|
- lib/linzer/message/wrapper.rb
|
214
216
|
- lib/linzer/options.rb
|
215
217
|
- lib/linzer/rsa.rb
|
@@ -241,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
241
243
|
- !ruby/object:Gem::Version
|
242
244
|
version: '0'
|
243
245
|
requirements: []
|
244
|
-
rubygems_version: 3.6.
|
246
|
+
rubygems_version: 3.6.8
|
245
247
|
specification_version: 4
|
246
248
|
summary: An implementation of HTTP Messages Signatures (RFC9421)
|
247
249
|
test_files: []
|