linzer 0.7.9.beta3 → 0.8.0.beta1
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 +31 -0
- data/README.md +8 -0
- data/Rakefile +6 -0
- data/benchmarks/profile_sign_ed25519.rb +102 -0
- data/benchmarks/profile_verify_ed25519.rb +107 -0
- data/benchmarks/sign.rb +55 -0
- data/benchmarks/verify.rb +68 -0
- data/lib/linzer/common.rb +52 -22
- data/lib/linzer/ed25519.rb +4 -2
- data/lib/linzer/hmac.rb +14 -12
- data/lib/linzer/http/structured_field.rb +48 -0
- data/lib/linzer/jws.rb +4 -4
- data/lib/linzer/key.rb +20 -2
- data/lib/linzer/message/adapter/abstract.rb +36 -9
- data/lib/linzer/message/adapter/faraday/response.rb +11 -9
- data/lib/linzer/message/adapter/generic/request.rb +11 -8
- data/lib/linzer/message/adapter/generic/response.rb +11 -8
- data/lib/linzer/message/adapter/http_gem/common.rb +11 -8
- data/lib/linzer/message/adapter/rack/request.rb +11 -8
- data/lib/linzer/message/adapter/rack/response.rb +11 -8
- data/lib/linzer/message/adapter.rb +0 -3
- data/lib/linzer/message/field.rb +53 -1
- data/lib/linzer/message/wrapper.rb +0 -2
- data/lib/linzer/rack.rb +24 -0
- data/lib/linzer/rsa_pss.rb +4 -4
- data/lib/linzer/signature.rb +143 -18
- data/lib/linzer/signer.rb +36 -15
- data/lib/linzer/verifier.rb +9 -3
- data/lib/linzer/version.rb +1 -1
- data/lib/linzer.rb +1 -4
- metadata +7 -61
data/lib/linzer/signer.rb
CHANGED
|
@@ -68,16 +68,31 @@ module Linzer
|
|
|
68
68
|
# tag: "my-app"
|
|
69
69
|
# )
|
|
70
70
|
def sign(key, message, components, options = {})
|
|
71
|
-
serialized_components =
|
|
72
|
-
|
|
71
|
+
serialized_components, field_ids =
|
|
72
|
+
FieldId.serialize_components_with_field_ids(Array(components))
|
|
73
|
+
validate key, message, serialized_components, field_ids: field_ids
|
|
74
|
+
|
|
75
|
+
# Reuse the already-parsed items from field_ids
|
|
76
|
+
parsed_items = field_ids.map(&:item)
|
|
73
77
|
|
|
74
78
|
parameters = populate_parameters(key, options)
|
|
75
|
-
signature_base = signature_base(message, serialized_components, parameters
|
|
79
|
+
signature_base = signature_base(message, serialized_components, parameters,
|
|
80
|
+
field_ids: field_ids)
|
|
76
81
|
|
|
77
|
-
|
|
82
|
+
raw_signature = key.sign(signature_base)
|
|
78
83
|
label = options[:label] || DEFAULT_LABEL
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
# Build the signature directly, bypassing the serialize -> parse round-trip
|
|
86
|
+
headers = serialize(raw_signature, serialized_components, parameters, label)
|
|
87
|
+
|
|
88
|
+
Linzer::Signature.from_components(
|
|
89
|
+
components: serialized_components,
|
|
90
|
+
raw_signature: raw_signature,
|
|
91
|
+
label: label,
|
|
92
|
+
parameters: parameters,
|
|
93
|
+
parsed_items: parsed_items,
|
|
94
|
+
headers: headers
|
|
95
|
+
)
|
|
81
96
|
end
|
|
82
97
|
|
|
83
98
|
# Returns the default signature label.
|
|
@@ -91,19 +106,22 @@ module Linzer
|
|
|
91
106
|
|
|
92
107
|
# Validates signing inputs.
|
|
93
108
|
# @raise [SigningError] If any input is invalid
|
|
94
|
-
def validate(key, message, components)
|
|
109
|
+
def validate(key, message, components, field_ids: nil)
|
|
95
110
|
msg = "Message cannot be signed with null %s"
|
|
96
111
|
raise SigningError, msg % "value" if message.nil?
|
|
97
112
|
raise SigningError, msg % "key" if key.nil?
|
|
98
113
|
raise SigningError, msg % "component" if components.nil?
|
|
99
114
|
|
|
100
115
|
begin
|
|
101
|
-
validate_components message, components
|
|
116
|
+
validate_components message, components, field_ids: field_ids
|
|
102
117
|
rescue Error => ex
|
|
103
118
|
raise SigningError, ex.message, cause: ex
|
|
104
119
|
end
|
|
105
120
|
end
|
|
106
121
|
|
|
122
|
+
RESERVED_OPTIONS = %i[created keyid label].freeze
|
|
123
|
+
private_constant :RESERVED_OPTIONS
|
|
124
|
+
|
|
107
125
|
# Builds the signature parameters hash from options and key.
|
|
108
126
|
# @return [Hash] The populated parameters
|
|
109
127
|
def populate_parameters(key, options)
|
|
@@ -114,22 +132,25 @@ module Linzer
|
|
|
114
132
|
key_id = options[:keyid] || (key.key_id if key.respond_to?(:key_id))
|
|
115
133
|
parameters[:keyid] = key_id unless key_id.nil?
|
|
116
134
|
|
|
117
|
-
|
|
135
|
+
options.each { |k, v| parameters[k] = v unless RESERVED_OPTIONS.include?(k) }
|
|
118
136
|
|
|
119
137
|
parameters
|
|
120
138
|
end
|
|
121
139
|
|
|
122
140
|
# Serializes the signature into HTTP header format.
|
|
141
|
+
#
|
|
142
|
+
# Uses direct string building instead of Starry.serialize to avoid
|
|
143
|
+
# the overhead of generic structured field serialization.
|
|
144
|
+
#
|
|
123
145
|
# @return [Hash] Hash with "signature" and "signature-input" keys
|
|
124
146
|
def serialize(signature, components, parameters, label)
|
|
147
|
+
sig_b64 = Base64.strict_encode64(signature)
|
|
148
|
+
input_params = HTTP::StructuredField.serialize_parameters(parameters)
|
|
149
|
+
components_str = components.join(" ")
|
|
150
|
+
|
|
125
151
|
{
|
|
126
|
-
"signature"
|
|
127
|
-
"signature-input" =>
|
|
128
|
-
Starry.serialize(label =>
|
|
129
|
-
Starry::InnerList.new(
|
|
130
|
-
components.map { |c| Starry.parse_item(c) },
|
|
131
|
-
parameters
|
|
132
|
-
))
|
|
152
|
+
"signature" => "#{label}=:#{sig_b64}:",
|
|
153
|
+
"signature-input" => "#{label}=(#{components_str})#{input_params}"
|
|
133
154
|
}
|
|
134
155
|
end
|
|
135
156
|
end
|
data/lib/linzer/verifier.rb
CHANGED
|
@@ -59,7 +59,12 @@ module Linzer
|
|
|
59
59
|
parameters = signature.parameters
|
|
60
60
|
serialized_components = signature.serialized_components
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
# Build fresh field_ids for signature_base (validate already
|
|
63
|
+
# consumed its own set, which may have been mutated by adapters).
|
|
64
|
+
field_ids = signature.field_ids
|
|
65
|
+
|
|
66
|
+
signature_base = signature_base(message, serialized_components, parameters,
|
|
67
|
+
field_ids: field_ids)
|
|
63
68
|
|
|
64
69
|
verify_or_fail key, signature.value, signature_base
|
|
65
70
|
end
|
|
@@ -78,10 +83,11 @@ module Linzer
|
|
|
78
83
|
end
|
|
79
84
|
|
|
80
85
|
raise VerifyError, "Signature raw value to cannot be null" if signature.value.nil?
|
|
81
|
-
raise VerifyError, "Components cannot be null" if signature.
|
|
86
|
+
raise VerifyError, "Components cannot be null" if signature.serialized_components.nil?
|
|
82
87
|
|
|
83
88
|
begin
|
|
84
|
-
validate_components message, signature.serialized_components
|
|
89
|
+
validate_components message, signature.serialized_components,
|
|
90
|
+
field_ids: signature.field_ids
|
|
85
91
|
rescue Error => ex
|
|
86
92
|
raise VerifyError, ex.message, cause: ex
|
|
87
93
|
end
|
data/lib/linzer/version.rb
CHANGED
data/lib/linzer.rb
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "starry"
|
|
4
4
|
require "openssl"
|
|
5
|
-
require "rack"
|
|
6
5
|
require "uri"
|
|
7
|
-
require "stringio"
|
|
8
6
|
require "net/http"
|
|
9
7
|
|
|
10
8
|
require_relative "linzer/version"
|
|
@@ -27,6 +25,7 @@ require_relative "linzer/key/helper"
|
|
|
27
25
|
require_relative "linzer/signer"
|
|
28
26
|
require_relative "linzer/verifier"
|
|
29
27
|
require_relative "linzer/http"
|
|
28
|
+
require_relative "linzer/http/structured_field"
|
|
30
29
|
|
|
31
30
|
# Linzer is a Ruby library for HTTP Message Signatures as defined in RFC 9421.
|
|
32
31
|
#
|
|
@@ -158,5 +157,3 @@ module Linzer
|
|
|
158
157
|
# Used for serializing and deserializing component identifiers.
|
|
159
158
|
FieldId = Message::Field::Identifier
|
|
160
159
|
end
|
|
161
|
-
|
|
162
|
-
require_relative "rack/auth/signature"
|
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.
|
|
4
|
+
version: 0.8.0.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Miguel Landaeta
|
|
@@ -23,26 +23,6 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0.2'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: rack
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - ">="
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '2.2'
|
|
33
|
-
- - "<"
|
|
34
|
-
- !ruby/object:Gem::Version
|
|
35
|
-
version: '4.0'
|
|
36
|
-
type: :runtime
|
|
37
|
-
prerelease: false
|
|
38
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
-
requirements:
|
|
40
|
-
- - ">="
|
|
41
|
-
- !ruby/object:Gem::Version
|
|
42
|
-
version: '2.2'
|
|
43
|
-
- - "<"
|
|
44
|
-
- !ruby/object:Gem::Version
|
|
45
|
-
version: '4.0'
|
|
46
26
|
- !ruby/object:Gem::Dependency
|
|
47
27
|
name: uri
|
|
48
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -63,46 +43,6 @@ dependencies:
|
|
|
63
43
|
- - ">="
|
|
64
44
|
- !ruby/object:Gem::Version
|
|
65
45
|
version: 1.0.2
|
|
66
|
-
- !ruby/object:Gem::Dependency
|
|
67
|
-
name: stringio
|
|
68
|
-
requirement: !ruby/object:Gem::Requirement
|
|
69
|
-
requirements:
|
|
70
|
-
- - "~>"
|
|
71
|
-
- !ruby/object:Gem::Version
|
|
72
|
-
version: '3.1'
|
|
73
|
-
- - ">="
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: 3.1.2
|
|
76
|
-
type: :runtime
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '3.1'
|
|
83
|
-
- - ">="
|
|
84
|
-
- !ruby/object:Gem::Version
|
|
85
|
-
version: 3.1.2
|
|
86
|
-
- !ruby/object:Gem::Dependency
|
|
87
|
-
name: logger
|
|
88
|
-
requirement: !ruby/object:Gem::Requirement
|
|
89
|
-
requirements:
|
|
90
|
-
- - "~>"
|
|
91
|
-
- !ruby/object:Gem::Version
|
|
92
|
-
version: '1.7'
|
|
93
|
-
- - ">="
|
|
94
|
-
- !ruby/object:Gem::Version
|
|
95
|
-
version: 1.7.0
|
|
96
|
-
type: :runtime
|
|
97
|
-
prerelease: false
|
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
-
requirements:
|
|
100
|
-
- - "~>"
|
|
101
|
-
- !ruby/object:Gem::Version
|
|
102
|
-
version: '1.7'
|
|
103
|
-
- - ">="
|
|
104
|
-
- !ruby/object:Gem::Version
|
|
105
|
-
version: 1.7.0
|
|
106
46
|
- !ruby/object:Gem::Dependency
|
|
107
47
|
name: forwardable
|
|
108
48
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -176,6 +116,10 @@ files:
|
|
|
176
116
|
- LICENSE.txt
|
|
177
117
|
- README.md
|
|
178
118
|
- Rakefile
|
|
119
|
+
- benchmarks/profile_sign_ed25519.rb
|
|
120
|
+
- benchmarks/profile_verify_ed25519.rb
|
|
121
|
+
- benchmarks/sign.rb
|
|
122
|
+
- benchmarks/verify.rb
|
|
179
123
|
- examples/sinatra/Gemfile
|
|
180
124
|
- examples/sinatra/config.ru
|
|
181
125
|
- examples/sinatra/http-signatures.yml
|
|
@@ -195,6 +139,7 @@ files:
|
|
|
195
139
|
- lib/linzer/http.rb
|
|
196
140
|
- lib/linzer/http/bootstrap.rb
|
|
197
141
|
- lib/linzer/http/signature_feature.rb
|
|
142
|
+
- lib/linzer/http/structured_field.rb
|
|
198
143
|
- lib/linzer/jws.rb
|
|
199
144
|
- lib/linzer/key.rb
|
|
200
145
|
- lib/linzer/key/helper.rb
|
|
@@ -217,6 +162,7 @@ files:
|
|
|
217
162
|
- lib/linzer/message/field/parser.rb
|
|
218
163
|
- lib/linzer/message/wrapper.rb
|
|
219
164
|
- lib/linzer/options.rb
|
|
165
|
+
- lib/linzer/rack.rb
|
|
220
166
|
- lib/linzer/rsa.rb
|
|
221
167
|
- lib/linzer/rsa_pss.rb
|
|
222
168
|
- lib/linzer/signature.rb
|