linzer 0.6.3 → 0.6.5
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 +13 -0
- data/README.md +10 -1
- data/lib/linzer/key/helper.rb +22 -8
- data/lib/linzer/rsa.rb +1 -7
- data/lib/linzer/rsa_pss.rb +40 -0
- data/lib/linzer/signature.rb +12 -0
- data/lib/linzer/verifier.rb +6 -3
- data/lib/linzer/version.rb +1 -1
- data/lib/linzer.rb +3 -2
- metadata +4 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d5b1a0dfcd7d402e3a5bf2e22102271e3273e1f7092e4dad09ae7078e04dcf3
|
4
|
+
data.tar.gz: 197933c6728e55678e7f29e5161b57fecd0ca39bacb586260412674a538cd8b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6da1cd0829f06c15f1a5cf66af191836294ffeea666e15f969f28c7171bf2b8e887b1fb5aa405fbfc7c840719ce82cc6cdae3b7238f987bb00f6c71e238c930
|
7
|
+
data.tar.gz: 047a03b94451dcffe5982165bc14acc7c6419fe4d8ff9f72e2d4510a77fae87c5960fabdaa0ff129d89724b0185a37454e3a6d9ec6ea903192eadc013e1abb64
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.6.5] - 2025-04-09
|
4
|
+
|
5
|
+
- Add support for RSA (RSASSA-PKCS1-V1_5) and improve RSASSA-PSS handling.
|
6
|
+
Pull request [#10](https://github.com/nomadium/linzer/pull/10)
|
7
|
+
by [oneiros](https://github.com/oneiros).
|
8
|
+
|
9
|
+
## [0.6.4] - 2025-04-04
|
10
|
+
|
11
|
+
- Allow validating the `created` parameter to mitigate the
|
12
|
+
risk of replay attacks.
|
13
|
+
Pull request [#8](https://github.com/nomadium/linzer/pull/8)
|
14
|
+
by [oneiros](https://github.com/oneiros).
|
15
|
+
|
3
16
|
## [0.6.3] - 2025-03-29
|
4
17
|
|
5
18
|
- Parse signature structured fields values as ASCII string.
|
data/README.md
CHANGED
@@ -117,6 +117,15 @@ Linzer.verify(pubkey, message, signature)
|
|
117
117
|
# => true
|
118
118
|
```
|
119
119
|
|
120
|
+
To mitigate the risk of "replay attacks" (i.e. an attacker capturing a message with a valid signature and re-sending it at a later point) applications may want to validate the `created` parameter of the signature. Linzer can do this automatically when given the optional `no_older_than` keyword argument:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
Linzer.verify(pubkey, message, signature, no_older_than: 500)
|
124
|
+
```
|
125
|
+
|
126
|
+
`no_older_than` expects a number of seconds, but you can pass anything that to responds to `#to_i`, including an `ActiveSupport::Duration`.
|
127
|
+
`::verify` will raise if the `created` parameter of the signature is older than the given number of seconds.
|
128
|
+
|
120
129
|
### What if an invalid signature if verified?
|
121
130
|
|
122
131
|
```ruby
|
@@ -151,7 +160,7 @@ pp signature.to_h
|
|
151
160
|
|
152
161
|
For now, to consult additional details just take a look at source code and/or the unit tests.
|
153
162
|
|
154
|
-
Please note that is still early days and extensive testing is still ongoing. For now
|
163
|
+
Please note that is still early days and extensive testing is still ongoing. For now the following algorithms are supported: RSASSA-PSS using SHA-512, RSASSA-PKCS1-v1_5 using SHA-256, HMAC-SHA256, Ed25519 and ECDSA (P-256 and P-384 curves). JSON Web Signature (JWS) algorithms mentioned in the RFC are not supported yet.
|
155
164
|
|
156
165
|
I'll be expanding the library to cover more functionality specified in the RFC
|
157
166
|
in subsequent releases.
|
data/lib/linzer/key/helper.rb
CHANGED
@@ -4,24 +4,38 @@ module Linzer
|
|
4
4
|
class Key
|
5
5
|
module Helper
|
6
6
|
def generate_rsa_pss_sha512_key(size, key_id = nil)
|
7
|
-
material = OpenSSL::PKey
|
8
|
-
Linzer::
|
7
|
+
material = OpenSSL::PKey.generate_key("RSASSA-PSS")
|
8
|
+
Linzer::RSAPSS::Key.new(material, id: key_id, digest: "SHA512")
|
9
9
|
end
|
10
10
|
|
11
11
|
def new_rsa_pss_sha512_key(material, key_id = nil)
|
12
12
|
key = OpenSSL::PKey.read(material)
|
13
|
-
Linzer::
|
13
|
+
Linzer::RSAPSS::Key.new(key, id: key_id, digest: "SHA512")
|
14
14
|
end
|
15
15
|
|
16
|
+
# XXX: investigate: was this method made redundant after:
|
17
|
+
# https://github.com/nomadium/linzer/pull/10
|
16
18
|
def new_rsa_pss_sha512_public_key(material, key_id = nil)
|
17
19
|
key = OpenSSL::PKey::RSA.new(material)
|
18
|
-
Linzer::
|
20
|
+
Linzer::RSAPSS::Key.new(key, id: key_id, digest: "SHA512")
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
def generate_rsa_v1_5_sha256_key(size, key_id = nil)
|
24
|
+
material = OpenSSL::PKey::RSA.generate(size)
|
25
|
+
Linzer::RSA::Key.new(material, id: key_id, digest: "SHA256")
|
26
|
+
end
|
27
|
+
|
28
|
+
def new_rsa_v1_5_sha256_key(material, key_id = nil)
|
29
|
+
key = OpenSSL::PKey.read(material)
|
30
|
+
Linzer::RSA::Key.new(key, id: key_id, digest: "SHA256")
|
31
|
+
end
|
32
|
+
|
33
|
+
# XXX: investigate: was this method made redundant after:
|
34
|
+
# https://github.com/nomadium/linzer/pull/10
|
35
|
+
def new_rsa_v1_5_sha256_public_key(material, key_id = nil)
|
36
|
+
key = OpenSSL::PKey.read(material)
|
37
|
+
Linzer::RSA::Key.new(key, id: key_id, digest: "SHA256")
|
38
|
+
end
|
25
39
|
|
26
40
|
def generate_hmac_sha256_key(key_id = nil)
|
27
41
|
material = OpenSSL::Random.random_bytes(64)
|
data/lib/linzer/rsa.rb
CHANGED
@@ -15,13 +15,7 @@ module Linzer
|
|
15
15
|
|
16
16
|
def verify(signature, data)
|
17
17
|
# XXX: should check if the key is usable for verifying
|
18
|
-
return true if @material.
|
19
|
-
@params[:digest],
|
20
|
-
signature,
|
21
|
-
data,
|
22
|
-
salt_length: @params[:salt_length] || :auto,
|
23
|
-
mgf1_hash: @params[:digest]
|
24
|
-
)
|
18
|
+
return true if @material.verify(@params[:digest], signature, data)
|
25
19
|
false
|
26
20
|
end
|
27
21
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Linzer
|
4
|
+
module RSAPSS
|
5
|
+
SALT_LENGTH = 64
|
6
|
+
|
7
|
+
class Key < Linzer::Key
|
8
|
+
def validate
|
9
|
+
super
|
10
|
+
validate_digest
|
11
|
+
end
|
12
|
+
|
13
|
+
def sign(data)
|
14
|
+
# XXX: should check if the key is usable for signing
|
15
|
+
@material.sign(@params[:digest], data, signature_options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def verify(signature, data)
|
19
|
+
# XXX: should check if the key is usable for verifying
|
20
|
+
return true if @material.verify(
|
21
|
+
@params[:digest],
|
22
|
+
signature,
|
23
|
+
data,
|
24
|
+
signature_options
|
25
|
+
)
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def signature_options
|
32
|
+
{
|
33
|
+
rsa_padding_mode: "pss",
|
34
|
+
rsa_pss_saltlen: @params[:salt_length] || SALT_LENGTH,
|
35
|
+
rsa_mgf1_md: @params[:digest]
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/linzer/signature.rb
CHANGED
@@ -14,6 +14,18 @@ module Linzer
|
|
14
14
|
alias_method :components, :metadata
|
15
15
|
alias_method :bytes, :value
|
16
16
|
|
17
|
+
def created
|
18
|
+
Integer(parameters["created"])
|
19
|
+
rescue
|
20
|
+
return nil if parameters["created"].nil?
|
21
|
+
raise Error.new "Signature has a non-integer `created` parameter"
|
22
|
+
end
|
23
|
+
|
24
|
+
def older_than?(seconds)
|
25
|
+
raise Error.new "Signature is missing the `created` parameter" if created.nil?
|
26
|
+
(Time.now.to_i - created) > seconds
|
27
|
+
end
|
28
|
+
|
17
29
|
def to_h
|
18
30
|
{
|
19
31
|
"signature" => Starry.serialize({label => value}),
|
data/lib/linzer/verifier.rb
CHANGED
@@ -5,8 +5,8 @@ module Linzer
|
|
5
5
|
class << self
|
6
6
|
include Common
|
7
7
|
|
8
|
-
def verify(key, message, signature)
|
9
|
-
validate message, key, signature
|
8
|
+
def verify(key, message, signature, no_older_than: nil)
|
9
|
+
validate message, key, signature, no_older_than: no_older_than
|
10
10
|
|
11
11
|
parameters = signature.parameters
|
12
12
|
components = signature.components
|
@@ -18,7 +18,7 @@ module Linzer
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
def validate(message, key, signature)
|
21
|
+
def validate(message, key, signature, no_older_than: nil)
|
22
22
|
raise Error.new "Message to verify cannot be null" if message.nil?
|
23
23
|
raise Error.new "Key to verify signature cannot be null" if key.nil?
|
24
24
|
raise Error.new "Signature to verify cannot be null" if signature.nil?
|
@@ -31,6 +31,9 @@ module Linzer
|
|
31
31
|
raise Error.new "Components cannot be null" if signature.components.nil?
|
32
32
|
|
33
33
|
validate_components message, signature.components
|
34
|
+
|
35
|
+
return unless no_older_than
|
36
|
+
raise Error.new "Signature created more than #{no_older_than} seconds ago" if signature.older_than?(no_older_than.to_i)
|
34
37
|
end
|
35
38
|
|
36
39
|
def verify_or_fail(key, signature, data)
|
data/lib/linzer/version.rb
CHANGED
data/lib/linzer.rb
CHANGED
@@ -14,6 +14,7 @@ require_relative "linzer/message"
|
|
14
14
|
require_relative "linzer/signature"
|
15
15
|
require_relative "linzer/key"
|
16
16
|
require_relative "linzer/rsa"
|
17
|
+
require_relative "linzer/rsa_pss"
|
17
18
|
require_relative "linzer/hmac"
|
18
19
|
require_relative "linzer/ed25519"
|
19
20
|
require_relative "linzer/ecdsa"
|
@@ -32,8 +33,8 @@ module Linzer
|
|
32
33
|
Linzer::Request.build(verb, uri, params, headers)
|
33
34
|
end
|
34
35
|
|
35
|
-
def verify(pubkey, message, signature)
|
36
|
-
Linzer::Verifier.verify(pubkey, message, signature)
|
36
|
+
def verify(pubkey, message, signature, no_older_than: nil)
|
37
|
+
Linzer::Verifier.verify(pubkey, message, signature, no_older_than: no_older_than)
|
37
38
|
end
|
38
39
|
|
39
40
|
def sign(key, message, components, options = {})
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: linzer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Landaeta
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date: 2025-
|
10
|
+
date: 2025-04-09 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: openssl
|
@@ -104,7 +103,6 @@ dependencies:
|
|
104
103
|
- - ">="
|
105
104
|
- !ruby/object:Gem::Version
|
106
105
|
version: 3.1.2
|
107
|
-
description:
|
108
106
|
email:
|
109
107
|
- miguel@miguel.cc
|
110
108
|
executables: []
|
@@ -129,6 +127,7 @@ files:
|
|
129
127
|
- lib/linzer/request.rb
|
130
128
|
- lib/linzer/response.rb
|
131
129
|
- lib/linzer/rsa.rb
|
130
|
+
- lib/linzer/rsa_pss.rb
|
132
131
|
- lib/linzer/signature.rb
|
133
132
|
- lib/linzer/signer.rb
|
134
133
|
- lib/linzer/verifier.rb
|
@@ -140,7 +139,6 @@ metadata:
|
|
140
139
|
homepage_uri: https://github.com/nomadium/linzer
|
141
140
|
source_code_uri: https://github.com/nomadium/linzer
|
142
141
|
changelog_uri: https://github.com/nomadium/linzer/blob/master/CHANGELOG.md
|
143
|
-
post_install_message:
|
144
142
|
rdoc_options: []
|
145
143
|
require_paths:
|
146
144
|
- lib
|
@@ -155,8 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
153
|
- !ruby/object:Gem::Version
|
156
154
|
version: '0'
|
157
155
|
requirements: []
|
158
|
-
rubygems_version: 3.
|
159
|
-
signing_key:
|
156
|
+
rubygems_version: 3.6.2
|
160
157
|
specification_version: 4
|
161
158
|
summary: An implementation of HTTP Messages Signatures (RFC9421)
|
162
159
|
test_files: []
|