webauthn 3.0.0 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/build.yml +6 -2
- data/.github/workflows/git.yml +1 -1
- data/CHANGELOG.md +17 -0
- data/README.md +1 -1
- data/docs/advanced_configuration.md +6 -6
- data/lib/webauthn/attestation_statement/base.rb +9 -0
- data/lib/webauthn/credential.rb +0 -1
- data/lib/webauthn/encoder.rb +13 -4
- data/lib/webauthn/fake_client.rb +2 -0
- data/lib/webauthn/public_key_credential.rb +17 -2
- data/lib/webauthn/version.rb +1 -1
- data/webauthn.gemspec +1 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b23698bdd722a0cda45be7ee9d5ba528f966eb98304a50069242f0a25dcd259
|
4
|
+
data.tar.gz: 4d7bf8874268cbbbfa75136006af9dc5a824b25d3f0522c5f2046092261bae5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf2d6697ee0c34cccbb1f5f9765e70efe1a8062f73b35cb900894c59f512d81157a836046e8006c9c6d5b0a0b3040f9c76a83417928d0ff9fbaba2db1893aaef
|
7
|
+
data.tar.gz: 2952c2573b030ffbba7837f2ba299e73c7a4e09a3a46b4a7a19c7875b4ea5394a8af00059dda69ae4c3dc34b1531b3aad3d1d1445dc4000260b3cfc4e5e23a98
|
data/.github/workflows/build.yml
CHANGED
@@ -7,7 +7,11 @@
|
|
7
7
|
|
8
8
|
name: build
|
9
9
|
|
10
|
-
on:
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [master]
|
13
|
+
pull_request:
|
14
|
+
types: [opened, synchronize]
|
11
15
|
|
12
16
|
jobs:
|
13
17
|
test:
|
@@ -24,7 +28,7 @@ jobs:
|
|
24
28
|
- '2.5'
|
25
29
|
- truffleruby
|
26
30
|
steps:
|
27
|
-
- uses: actions/checkout@
|
31
|
+
- uses: actions/checkout@v4
|
28
32
|
- uses: ruby/setup-ruby@v1
|
29
33
|
with:
|
30
34
|
ruby-version: ${{ matrix.ruby }}
|
data/.github/workflows/git.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.1.0] - 2023-12-26
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Add support for optional `authenticator_attachment` in `PublicKeyCredential`. #370 [@8ma10s]
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
|
11
|
+
- Fix circular require warning between `webauthn/relying_party` and `webauthn/credential`. #389 [@bdewater]
|
12
|
+
- Correctly verify attestation that contains just a batch certificate that is present in the attestation root certificates. #406 [@santiagorodriguez96]
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
|
16
|
+
- Inlined `base64` implementation. #402 [@olleolleolle]
|
17
|
+
- Raise a more descriptive error if input `challenge` is `nil` when verifying the `PublicKeyCredential`. #413 [@soartec-lab]
|
18
|
+
|
3
19
|
## [v3.0.0] - 2023-02-15
|
4
20
|
|
5
21
|
### Added
|
@@ -358,6 +374,7 @@ Note: Both additions should help making it compatible with Chrome for Android 70
|
|
358
374
|
- `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
|
359
375
|
- Works with ruby 2.5
|
360
376
|
|
377
|
+
[v3.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v3.0.0...v3.1.0/
|
361
378
|
[v3.0.0]: https://github.com/cedarcode/webauthn-ruby/compare/2-stable...v3.0.0/
|
362
379
|
[v3.0.0.alpha2]: https://github.com/cedarcode/webauthn-ruby/compare/2-stable...v3.0.0.alpha2/
|
363
380
|
[v3.0.0.alpha1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.3.0...v3.0.0.alpha1
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ For the current release version see https://github.com/cedarcode/webauthn-ruby/b
|
|
6
6
|
![banner](assets/webauthn-ruby.png)
|
7
7
|
|
8
8
|
[![Gem](https://img.shields.io/gem/v/webauthn.svg?style=flat-square)](https://rubygems.org/gems/webauthn)
|
9
|
-
[![
|
9
|
+
[![Build](https://github.com/cedarcode/webauthn-ruby/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/cedarcode/webauthn-ruby/actions/workflows/build.yml)
|
10
10
|
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-informational.svg?style=flat-square)](https://conventionalcommits.org)
|
11
11
|
[![Join the chat at https://gitter.im/cedarcode/webauthn-ruby](https://badges.gitter.im/cedarcode/webauthn-ruby.svg)](https://gitter.im/cedarcode/webauthn-ruby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
12
12
|
|
@@ -59,7 +59,7 @@ Intead of the [Global Configuration](../README.md#configuration) you place in `c
|
|
59
59
|
|
60
60
|
**DISCLAIMER: This API was released on version 3.0.0.alpha1 and is still under evaluation. Although it has been throughly tested and it is fully functional it might be changed until the final release of version 3.0.0.**
|
61
61
|
|
62
|
-
The explanation for each ceremony can be found in depth in [Credential Registration](../README.md#credential-registration) and [Credential Authentication](../README.md#credential-authentication) but if you choose this instance based approach to define your WebAuthn configurations and assuming `relying_party` is the result of an instance you get through `WebAuthn::
|
62
|
+
The explanation for each ceremony can be found in depth in [Credential Registration](../README.md#credential-registration) and [Credential Authentication](../README.md#credential-authentication) but if you choose this instance based approach to define your WebAuthn configurations and assuming `relying_party` is the result of an instance you get through `WebAuthn::RelyingParty.new(...)` the code in those explanations needs to be updated to:
|
63
63
|
|
64
64
|
### Credential Registration
|
65
65
|
|
@@ -73,7 +73,7 @@ end
|
|
73
73
|
|
74
74
|
options = relying_party.options_for_registration(
|
75
75
|
user: { id: user.webauthn_id, name: user.name },
|
76
|
-
exclude: user.credentials.map { |c| c.
|
76
|
+
exclude: user.credentials.map { |c| c.external_id }
|
77
77
|
)
|
78
78
|
|
79
79
|
# Store the newly generated challenge somewhere so you can have it
|
@@ -106,7 +106,7 @@ begin
|
|
106
106
|
|
107
107
|
# Store Credential ID, Credential Public Key and Sign Count for future authentications
|
108
108
|
user.credentials.create!(
|
109
|
-
|
109
|
+
external_id: webauthn_credential.id,
|
110
110
|
public_key: webauthn_credential.public_key,
|
111
111
|
sign_count: webauthn_credential.sign_count
|
112
112
|
)
|
@@ -120,7 +120,7 @@ end
|
|
120
120
|
#### Initiation phase
|
121
121
|
|
122
122
|
```ruby
|
123
|
-
options = relying_party.
|
123
|
+
options = relying_party.options_for_authentication(allow: user.credentials.map { |c| c.webauthn_id })
|
124
124
|
|
125
125
|
# Store the newly generated challenge somewhere so you can have it
|
126
126
|
# for the verification phase.
|
@@ -148,9 +148,9 @@ begin
|
|
148
148
|
webauthn_credential, stored_credential = relying_party.verify_authentication(
|
149
149
|
params[:publicKeyCredential],
|
150
150
|
session[:authentication_challenge]
|
151
|
-
) do
|
151
|
+
) do |webauthn_credential|
|
152
152
|
# the returned object needs to respond to #public_key and #sign_count
|
153
|
-
user.credentials.find_by(
|
153
|
+
user.credentials.find_by(external_id: webauthn_credential.id)
|
154
154
|
end
|
155
155
|
|
156
156
|
# Update the stored credential sign count with the value from `webauthn_credential.sign_count`
|
@@ -102,6 +102,15 @@ module WebAuthn
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def valid_certificate_chain?(aaguid: nil, attestation_certificate_key_id: nil)
|
105
|
+
root_certificates = root_certificates(
|
106
|
+
aaguid: aaguid,
|
107
|
+
attestation_certificate_key_id: attestation_certificate_key_id
|
108
|
+
)
|
109
|
+
|
110
|
+
if certificates&.one? && root_certificates.include?(attestation_certificate)
|
111
|
+
return true
|
112
|
+
end
|
113
|
+
|
105
114
|
attestation_root_certificates_store(
|
106
115
|
aaguid: aaguid,
|
107
116
|
attestation_certificate_key_id: attestation_certificate_key_id
|
data/lib/webauthn/credential.rb
CHANGED
@@ -4,7 +4,6 @@ require "webauthn/public_key_credential/creation_options"
|
|
4
4
|
require "webauthn/public_key_credential/request_options"
|
5
5
|
require "webauthn/public_key_credential_with_assertion"
|
6
6
|
require "webauthn/public_key_credential_with_attestation"
|
7
|
-
require "webauthn/relying_party"
|
8
7
|
|
9
8
|
module WebAuthn
|
10
9
|
module Credential
|
data/lib/webauthn/encoder.rb
CHANGED
@@ -20,9 +20,12 @@ module WebAuthn
|
|
20
20
|
def encode(data)
|
21
21
|
case encoding
|
22
22
|
when :base64
|
23
|
-
Base64.strict_encode64(data)
|
23
|
+
[data].pack("m0") # Base64.strict_encode64(data)
|
24
24
|
when :base64url
|
25
|
-
Base64.urlsafe_encode64(data, padding: false)
|
25
|
+
data = [data].pack("m0") # Base64.urlsafe_encode64(data, padding: false)
|
26
|
+
data.chomp!("==") or data.chomp!("=")
|
27
|
+
data.tr!("+/", "-_")
|
28
|
+
data
|
26
29
|
when nil, false
|
27
30
|
data
|
28
31
|
else
|
@@ -33,9 +36,15 @@ module WebAuthn
|
|
33
36
|
def decode(data)
|
34
37
|
case encoding
|
35
38
|
when :base64
|
36
|
-
Base64.strict_decode64(data)
|
39
|
+
data.unpack1("m0") # Base64.strict_decode64(data)
|
37
40
|
when :base64url
|
38
|
-
Base64.urlsafe_decode64(data)
|
41
|
+
if !data.end_with?("=") && data.length % 4 != 0 # Base64.urlsafe_decode64(data)
|
42
|
+
data = data.ljust((data.length + 3) & ~3, "=")
|
43
|
+
data.tr!("-_", "+/")
|
44
|
+
else
|
45
|
+
data = data.tr("-_", "+/")
|
46
|
+
end
|
47
|
+
data.unpack1("m0")
|
39
48
|
when nil, false
|
40
49
|
data
|
41
50
|
else
|
data/lib/webauthn/fake_client.rb
CHANGED
@@ -64,6 +64,7 @@ module WebAuthn
|
|
64
64
|
"type" => "public-key",
|
65
65
|
"id" => internal_encoder.encode(id),
|
66
66
|
"rawId" => encoder.encode(id),
|
67
|
+
"authenticatorAttachment" => 'platform',
|
67
68
|
"clientExtensionResults" => extensions,
|
68
69
|
"response" => {
|
69
70
|
"attestationObject" => encoder.encode(attestation_object),
|
@@ -108,6 +109,7 @@ module WebAuthn
|
|
108
109
|
"id" => internal_encoder.encode(assertion[:credential_id]),
|
109
110
|
"rawId" => encoder.encode(assertion[:credential_id]),
|
110
111
|
"clientExtensionResults" => extensions,
|
112
|
+
"authenticatorAttachment" => 'platform',
|
111
113
|
"response" => {
|
112
114
|
"clientDataJSON" => encoder.encode(client_data_json),
|
113
115
|
"authenticatorData" => encoder.encode(assertion[:authenticator_data]),
|
@@ -4,7 +4,9 @@ require "webauthn/encoder"
|
|
4
4
|
|
5
5
|
module WebAuthn
|
6
6
|
class PublicKeyCredential
|
7
|
-
|
7
|
+
class InvalidChallengeError < Error; end
|
8
|
+
|
9
|
+
attr_reader :type, :id, :raw_id, :client_extension_outputs, :authenticator_attachment, :response
|
8
10
|
|
9
11
|
def self.from_client(credential, relying_party: WebAuthn.configuration.relying_party)
|
10
12
|
new(
|
@@ -12,6 +14,7 @@ module WebAuthn
|
|
12
14
|
id: credential["id"],
|
13
15
|
raw_id: relying_party.encoder.decode(credential["rawId"]),
|
14
16
|
client_extension_outputs: credential["clientExtensionResults"],
|
17
|
+
authenticator_attachment: credential["authenticatorAttachment"],
|
15
18
|
response: response_class.from_client(credential["response"], relying_party: relying_party),
|
16
19
|
relying_party: relying_party
|
17
20
|
)
|
@@ -22,6 +25,7 @@ module WebAuthn
|
|
22
25
|
id:,
|
23
26
|
raw_id:,
|
24
27
|
response:,
|
28
|
+
authenticator_attachment: nil,
|
25
29
|
client_extension_outputs: {},
|
26
30
|
relying_party: WebAuthn.configuration.relying_party
|
27
31
|
)
|
@@ -29,11 +33,18 @@ module WebAuthn
|
|
29
33
|
@id = id
|
30
34
|
@raw_id = raw_id
|
31
35
|
@client_extension_outputs = client_extension_outputs
|
36
|
+
@authenticator_attachment = authenticator_attachment
|
32
37
|
@response = response
|
33
38
|
@relying_party = relying_party
|
34
39
|
end
|
35
40
|
|
36
|
-
def verify(*_args)
|
41
|
+
def verify(challenge, *_args)
|
42
|
+
unless valid_class?(challenge)
|
43
|
+
msg = "challenge must be a String. input challenge class: #{challenge.class}"
|
44
|
+
|
45
|
+
raise(InvalidChallengeError, msg)
|
46
|
+
end
|
47
|
+
|
37
48
|
valid_type? || raise("invalid type")
|
38
49
|
valid_id? || raise("invalid id")
|
39
50
|
|
@@ -68,6 +79,10 @@ module WebAuthn
|
|
68
79
|
raw_id && id && raw_id == WebAuthn.standard_encoder.decode(id)
|
69
80
|
end
|
70
81
|
|
82
|
+
def valid_class?(challenge)
|
83
|
+
challenge.is_a?(String)
|
84
|
+
end
|
85
|
+
|
71
86
|
def authenticator_data
|
72
87
|
response&.authenticator_data
|
73
88
|
end
|
data/lib/webauthn/version.rb
CHANGED
data/webauthn.gemspec
CHANGED
@@ -42,6 +42,7 @@ Gem::Specification.new do |spec|
|
|
42
42
|
spec.add_dependency "safety_net_attestation", "~> 0.4.0"
|
43
43
|
spec.add_dependency "tpm-key_attestation", "~> 0.12.0"
|
44
44
|
|
45
|
+
spec.add_development_dependency "base64", ">= 0.1.0"
|
45
46
|
spec.add_development_dependency "bundler", ">= 1.17", "< 3.0"
|
46
47
|
spec.add_development_dependency "byebug", "~> 11.0"
|
47
48
|
spec.add_development_dependency "rake", "~> 13.0"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webauthn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gonzalo Rodriguez
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-12-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: android_key_attestation
|
@@ -123,6 +123,20 @@ dependencies:
|
|
123
123
|
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: 0.12.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: base64
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 0.1.0
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 0.1.0
|
126
140
|
- !ruby/object:Gem::Dependency
|
127
141
|
name: bundler
|
128
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -237,6 +251,7 @@ executables: []
|
|
237
251
|
extensions: []
|
238
252
|
extra_rdoc_files: []
|
239
253
|
files:
|
254
|
+
- ".github/dependabot.yml"
|
240
255
|
- ".github/workflows/build.yml"
|
241
256
|
- ".github/workflows/git.yml"
|
242
257
|
- ".gitignore"
|
@@ -322,7 +337,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
322
337
|
- !ruby/object:Gem::Version
|
323
338
|
version: '0'
|
324
339
|
requirements: []
|
325
|
-
rubygems_version: 3.
|
340
|
+
rubygems_version: 3.4.10
|
326
341
|
signing_key:
|
327
342
|
specification_version: 4
|
328
343
|
summary: WebAuthn ruby server library
|