webauthn 2.4.1 → 2.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +32 -0
- data/.github/workflows/git.yml +21 -0
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +43 -0
- data/README.md +5 -2
- data/SECURITY.md +2 -1
- data/docs/advanced_configuration.md +174 -0
- data/docs/u2f_migration.md +3 -2
- data/lib/webauthn/attestation_statement/android_key.rb +0 -4
- data/lib/webauthn/attestation_statement/android_safetynet.rb +1 -5
- data/lib/webauthn/attestation_statement/apple.rb +65 -0
- data/lib/webauthn/attestation_statement/base.rb +11 -22
- data/lib/webauthn/attestation_statement/packed.rb +1 -1
- data/lib/webauthn/attestation_statement/tpm.rb +2 -2
- data/lib/webauthn/attestation_statement.rb +4 -1
- data/lib/webauthn/authenticator_response.rb +1 -2
- data/lib/webauthn/configuration.rb +2 -6
- data/lib/webauthn/fake_authenticator/authenticator_data.rb +1 -1
- data/lib/webauthn/fake_authenticator.rb +11 -3
- data/lib/webauthn/fake_client.rb +8 -2
- data/lib/webauthn/public_key_credential/entity.rb +3 -4
- data/lib/webauthn/version.rb +1 -1
- data/webauthn.gemspec +5 -6
- metadata +42 -56
- data/.travis.yml +0 -39
- data/Appraisals +0 -21
- data/gemfiles/cose_head.gemfile +0 -7
- data/gemfiles/openssl_2_0.gemfile +0 -7
- data/gemfiles/openssl_2_1.gemfile +0 -7
- data/gemfiles/openssl_2_2.gemfile +0 -7
- data/gemfiles/openssl_head.gemfile +0 -7
- data/lib/webauthn/security_utils.rb +0 -20
- data/script/ci/install-openssl +0 -7
- data/script/ci/install-ruby +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f07d44a7778995c6bd2531b26f61e8974ba6ccc8dcf5ff1f21886f353423d598
|
4
|
+
data.tar.gz: ecb287679447b3074065f2b06cb0f38b20c9a94114ed2b592d93e99874dfda1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98811fdbdb15cd80defb95a75de555a3775864bb1c1f1ac94af4a605af2fa3acf7908d91a120b5c3e214af890469d5f2194e5e037a9f8a40b03935159be6a1f1
|
7
|
+
data.tar.gz: 8d90a9d37fb83a0ecf5e0c29e8f5154a0ee2170da994238b55fcc4042cb84f6b7fb4e09386e704a2d83f363ef0864fb1fa60c913eea3ae2754e5189435302570
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: build
|
9
|
+
|
10
|
+
on: push
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
test:
|
14
|
+
runs-on: ubuntu-20.04
|
15
|
+
strategy:
|
16
|
+
fail-fast: false
|
17
|
+
matrix:
|
18
|
+
ruby:
|
19
|
+
- '3.1'
|
20
|
+
- '3.0'
|
21
|
+
- '2.7'
|
22
|
+
- '2.6'
|
23
|
+
- '2.5'
|
24
|
+
- '2.4'
|
25
|
+
- truffleruby
|
26
|
+
steps:
|
27
|
+
- uses: actions/checkout@v2
|
28
|
+
- uses: ruby/setup-ruby@v1
|
29
|
+
with:
|
30
|
+
ruby-version: ${{ matrix.ruby }}
|
31
|
+
bundler-cache: true
|
32
|
+
- run: bundle exec rake
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Syntax reference:
|
2
|
+
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
|
3
|
+
name: Git Checks
|
4
|
+
|
5
|
+
on:
|
6
|
+
pull_request:
|
7
|
+
types: [opened, synchronize]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
# Fixup commits are OK in pull requests, but should generally be squashed
|
11
|
+
# before merging to master, e.g. using `git rebase -i --autosquash master`.
|
12
|
+
# See https://github.com/marketplace/actions/block-autosquash-commits
|
13
|
+
block-fixup:
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v2.0.0
|
18
|
+
- name: Block autosquash commits
|
19
|
+
uses: xt0rted/block-autosquash-commits-action@v2
|
20
|
+
with:
|
21
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require:
|
2
2
|
- rubocop-rspec
|
3
|
+
- rubocop-rake
|
3
4
|
|
4
5
|
inherit_mode:
|
5
6
|
merge:
|
@@ -8,6 +9,7 @@ inherit_mode:
|
|
8
9
|
AllCops:
|
9
10
|
TargetRubyVersion: 2.4
|
10
11
|
DisabledByDefault: true
|
12
|
+
NewCops: disable
|
11
13
|
Exclude:
|
12
14
|
- "gemfiles/**/*"
|
13
15
|
- "vendor/**/*"
|
@@ -24,6 +26,9 @@ Layout:
|
|
24
26
|
Layout/ClassStructure:
|
25
27
|
Enabled: true
|
26
28
|
|
29
|
+
Layout/EmptyLineBetweenDefs:
|
30
|
+
AllowAdjacentOneLineDefs: true
|
31
|
+
|
27
32
|
Layout/EmptyLinesAroundAttributeAccessor:
|
28
33
|
Enabled: true
|
29
34
|
|
@@ -92,6 +97,9 @@ Lint/UnreachableLoop:
|
|
92
97
|
Naming:
|
93
98
|
Enabled: true
|
94
99
|
|
100
|
+
Naming/VariableNumber:
|
101
|
+
Enabled: false
|
102
|
+
|
95
103
|
RSpec/Be:
|
96
104
|
Enabled: true
|
97
105
|
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,38 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.0.0.alpha1] - 2020-06-27
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Ability to define multiple relying parties with the introduction of the `WebAuthn::RelyingParty` class ([@padulafacundo], [@brauliomartinezlm])
|
8
|
+
|
9
|
+
## [v2.5.1] - 2022-07-13
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- Updated dependencies to make the gem compatible with openssl-3 [@ClearlyClaire]
|
14
|
+
|
15
|
+
## [v2.5.1] - 2022-03-20
|
16
|
+
|
17
|
+
### Added
|
18
|
+
|
19
|
+
- Updated openssl support to be ~>2.2 [@bdewater]
|
20
|
+
|
21
|
+
### Removed
|
22
|
+
|
23
|
+
- Removed dependency [secure_compare dependency] (https://rubygems.org/gems/secure_compare/versions/0.0.1) and use OpenSSL#secure_compare instead [@bdewater]
|
24
|
+
|
25
|
+
## [v2.5.0] - 2021-03-14
|
26
|
+
|
27
|
+
### Added
|
28
|
+
|
29
|
+
- Support 'apple' attestation statement format ([#343](https://github.com/cedarcode/webauthn-ruby/pull/343) / [@juanarias93], [@santiagorodriguez96])
|
30
|
+
- Allow specifying an array of ids as `allow_credentials:` for `FakeClient#get` method ([#335](https://github.com/cedarcode/webauthn-ruby/pull/335) / [@kingjan1999])
|
31
|
+
|
32
|
+
### Removed
|
33
|
+
|
34
|
+
- No longer accept "removed from the WebAuthn spec" options `rp: { icon: }` and `user: { icon: }` for `WebAuthn::Credential.options_for_create` method ([#326](https://github.com/cedarcode/webauthn-ruby/pull/326) / [@santiagorodriguez96])
|
35
|
+
|
3
36
|
## [v2.4.1] - 2021-02-15
|
4
37
|
|
5
38
|
### Fixed
|
@@ -307,6 +340,10 @@ Note: Both additions should help making it compatible with Chrome for Android 70
|
|
307
340
|
- `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
|
308
341
|
- Works with ruby 2.5
|
309
342
|
|
343
|
+
[v3.0.0.alpha1]: https://github.com/cedarcode/webauthn-ruby/compare/2-stable...v3.0.0.alpha1/
|
344
|
+
[v2.5.2]: https://github.com/cedarcode/webauthn-ruby/compare/v2.5.0...v2.5.2/
|
345
|
+
[v2.5.1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.5.0...v2.5.1/
|
346
|
+
[v2.5.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.4.1...v2.5.0/
|
310
347
|
[v2.4.1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.4.0...v2.4.1/
|
311
348
|
[v2.4.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.3.0...v2.4.0/
|
312
349
|
[v2.3.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.2.1...v2.3.0/
|
@@ -336,6 +373,7 @@ Note: Both additions should help making it compatible with Chrome for Android 70
|
|
336
373
|
[v0.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.1.0...v0.2.0/
|
337
374
|
[v0.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.0.0...v0.1.0/
|
338
375
|
|
376
|
+
[@brauliomartinezlm]: https://github.com/brauliomartinezlm
|
339
377
|
[@bdewater]: https://github.com/bdewater
|
340
378
|
[@jdongelmans]: https://github.com/jdongelmans
|
341
379
|
[@kalebtesfay]: https://github.com/kalebtesfay
|
@@ -345,3 +383,8 @@ Note: Both additions should help making it compatible with Chrome for Android 70
|
|
345
383
|
[@padulafacundo]: https://github.com/padulafacundo
|
346
384
|
[@santiagorodriguez96]: https://github.com/santiagorodriguez96
|
347
385
|
[@lgarron]: https://github.com/lgarron
|
386
|
+
[@juanarias93]: https://github.com/juanarias93
|
387
|
+
[@kingjan1999]: https://github.com/@kingjan1999
|
388
|
+
[@jdongelmans]: https://github.com/jdongelmans
|
389
|
+
[@petergoldstein]: https://github.com/petergoldstein
|
390
|
+
[@ClearlyClaire]: https://github.com/ClearlyClaire
|
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
|
-
[![Travis](https://img.shields.io/travis/cedarcode/webauthn-ruby/master.svg?style=flat-square)](https://travis-ci.
|
9
|
+
[![Travis](https://img.shields.io/travis/cedarcode/webauthn-ruby/master.svg?style=flat-square)](https://travis-ci.com/cedarcode/webauthn-ruby)
|
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
|
|
@@ -96,6 +96,8 @@ If you are migrating an existing application from the legacy FIDO U2F JavaScript
|
|
96
96
|
|
97
97
|
### Configuration
|
98
98
|
|
99
|
+
If you have a multi-tenant application or just need to configure WebAuthn differently for separate parts of your application (e.g. if your users authenticate to different subdomains in the same application), we strongly recommend you look at this [Advanced Configuration](docs/advanced_configuration.md) section instead of this.
|
100
|
+
|
99
101
|
For a Rails application this would go in `config/initializers/webauthn.rb`.
|
100
102
|
|
101
103
|
```ruby
|
@@ -408,7 +410,7 @@ credential.authenticator_extension_outputs
|
|
408
410
|
|
409
411
|
## Attestation
|
410
412
|
|
411
|
-
### Attestation Statement
|
413
|
+
### Attestation Statement Formats
|
412
414
|
|
413
415
|
| Attestation Statement Format | Supported? |
|
414
416
|
| -------- | :--------: |
|
@@ -417,6 +419,7 @@ credential.authenticator_extension_outputs
|
|
417
419
|
| tpm (x5c attestation) | Yes |
|
418
420
|
| android-key | Yes |
|
419
421
|
| android-safetynet | Yes |
|
422
|
+
| apple | Yes |
|
420
423
|
| fido-u2f | Yes |
|
421
424
|
| none | Yes |
|
422
425
|
|
data/SECURITY.md
CHANGED
@@ -4,9 +4,10 @@
|
|
4
4
|
|
5
5
|
| Version | Supported |
|
6
6
|
| ------- | ------------------ |
|
7
|
+
| 2.5.z | :white_check_mark: |
|
7
8
|
| 2.4.z | :white_check_mark: |
|
8
9
|
| 2.3.z | :white_check_mark: |
|
9
|
-
| 2.2.z | :
|
10
|
+
| 2.2.z | :x: |
|
10
11
|
| 2.1.z | :x: |
|
11
12
|
| 2.0.z | :x: |
|
12
13
|
| 1.18.z | :white_check_mark: |
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# Advanced Configuration
|
2
|
+
|
3
|
+
## Global vs Instance Based Configuration
|
4
|
+
|
5
|
+
Which approach suits best your needs will depend on the architecture of your application and how do your users need to register and authenticate to it.
|
6
|
+
|
7
|
+
If you have a multi-tenant application, or any application segmenation, where your users register and authenticate to each of these tenants or segments individuallly using different hostnames, or with different security needs, you need to go through [Instance Based Configuration](#instance-based-configuration).
|
8
|
+
|
9
|
+
However, if your application is served for just one hostname, or else if your users authenticate to only one subdmain (e.g. your application serves www.example.com and admin.example.com but all you users authenticate through auth.example.com) you can still rely on one [Global Configuration](../README.md#configuration).
|
10
|
+
|
11
|
+
If you are still not sure, or want to keep your options open, be aware that [Instance Based Configuration](#instance-based-configuration) is also a valid way of defining a single instance configuration and how you share such configuration across your application, it's up to you.
|
12
|
+
|
13
|
+
|
14
|
+
## Instance Based Configuration
|
15
|
+
|
16
|
+
Intead of the [Global Configuration](../README.md#configuration) you place in `config/initializers/webauthn.rb`,
|
17
|
+
you can now have an on-demand instance of `WebAuthn::RelyingParty` with the same configuration options, that
|
18
|
+
you can build anywhere in you application, in the following way:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
relying_party = WebAuthn::RelyingParty.new(
|
22
|
+
# This value needs to match `window.location.origin` evaluated by
|
23
|
+
# the User Agent during registration and authentication ceremonies.
|
24
|
+
origin: "https://admin.example.com"
|
25
|
+
|
26
|
+
# Relying Party name for display purposes
|
27
|
+
name: "Admin Site for Example Inc."
|
28
|
+
|
29
|
+
# Optionally configure a client timeout hint, in milliseconds.
|
30
|
+
# This hint specifies how long the browser should wait for any
|
31
|
+
# interaction with the user.
|
32
|
+
# This hint may be overridden by the browser.
|
33
|
+
# https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout
|
34
|
+
# credential_options_timeout: 120_000
|
35
|
+
|
36
|
+
# You can optionally specify a different Relying Party ID
|
37
|
+
# (https://www.w3.org/TR/webauthn/#relying-party-identifier)
|
38
|
+
# if it differs from the default one.
|
39
|
+
#
|
40
|
+
# In this case the default would be "admin.example.com", but you can set it to
|
41
|
+
# the suffix "example.com"
|
42
|
+
#
|
43
|
+
# rp_id: "example.com"
|
44
|
+
|
45
|
+
# Configure preferred binary-to-text encoding scheme. This should match the encoding scheme
|
46
|
+
# used in your client-side (user agent) code before sending the credential to the server.
|
47
|
+
# Supported values: `:base64url` (default), `:base64` or `false` to disable all encoding.
|
48
|
+
#
|
49
|
+
# encoding: :base64url
|
50
|
+
|
51
|
+
# Possible values: "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512", "RS1"
|
52
|
+
# Default: ["ES256", "PS256", "RS256"]
|
53
|
+
#
|
54
|
+
# algorithms: ["ES384"]
|
55
|
+
)
|
56
|
+
```
|
57
|
+
|
58
|
+
## Instance Based API
|
59
|
+
|
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
|
+
|
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::RelytingParty.new(...)` the code in those explanations needs to be updated to:
|
63
|
+
|
64
|
+
### Credential Registration
|
65
|
+
|
66
|
+
#### Initiation phase
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
# Generate and store the WebAuthn User ID the first time the user registers a credential
|
70
|
+
if !user.webauthn_id
|
71
|
+
user.update!(webauthn_id: WebAuthn.generate_user_id)
|
72
|
+
end
|
73
|
+
|
74
|
+
options = relying_party.options_for_create(
|
75
|
+
user: { id: user.webauthn_id, name: user.name },
|
76
|
+
exclude: user.credentials.map { |c| c.webauthn_id }
|
77
|
+
)
|
78
|
+
|
79
|
+
# Store the newly generated challenge somewhere so you can have it
|
80
|
+
# for the verification phase.
|
81
|
+
session[:creation_challenge] = options.challenge
|
82
|
+
|
83
|
+
# Send `options` back to the browser, so that they can be used
|
84
|
+
# to call `navigator.credentials.create({ "publicKey": options })`
|
85
|
+
#
|
86
|
+
# You can call `options.as_json` to get a ruby hash with a JSON representation if needed.
|
87
|
+
|
88
|
+
# If inside a Rails controller, `render json: options` will just work.
|
89
|
+
# I.e. it will encode and convert the options to JSON automatically.
|
90
|
+
|
91
|
+
# For your frontend code, you might find @github/webauthn-json npm package useful.
|
92
|
+
# Especially for handling the necessary decoding of the options, and sending the
|
93
|
+
# `PublicKeyCredential` object back to the server.
|
94
|
+
```
|
95
|
+
|
96
|
+
#### Verification phase
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
# Assuming you're using @github/webauthn-json package to send the `PublicKeyCredential` object back
|
100
|
+
# in params[:publicKeyCredential]:
|
101
|
+
begin
|
102
|
+
webauthn_credential = relying_party.verify_registration(
|
103
|
+
params[:publicKeyCredential],
|
104
|
+
params[:create_challenge]
|
105
|
+
)
|
106
|
+
|
107
|
+
# Store Credential ID, Credential Public Key and Sign Count for future authentications
|
108
|
+
user.credentials.create!(
|
109
|
+
webauthn_id: webauthn_credential.id,
|
110
|
+
public_key: webauthn_credential.public_key,
|
111
|
+
sign_count: webauthn_credential.sign_count
|
112
|
+
)
|
113
|
+
rescue WebAuthn::Error => e
|
114
|
+
# Handle error
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
### Credential Authentication
|
119
|
+
|
120
|
+
#### Initiation phase
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
options = relying_party.options_for_get(allow: user.credentials.map { |c| c.webauthn_id })
|
124
|
+
|
125
|
+
# Store the newly generated challenge somewhere so you can have it
|
126
|
+
# for the verification phase.
|
127
|
+
session[:authentication_challenge] = options.challenge
|
128
|
+
|
129
|
+
# Send `options` back to the browser, so that they can be used
|
130
|
+
# to call `navigator.credentials.get({ "publicKey": options })`
|
131
|
+
|
132
|
+
# You can call `options.as_json` to get a ruby hash with a JSON representation if needed.
|
133
|
+
|
134
|
+
# If inside a Rails controller, `render json: options` will just work.
|
135
|
+
# I.e. it will encode and convert the options to JSON automatically.
|
136
|
+
|
137
|
+
# For your frontend code, you might find @github/webauthn-json npm package useful.
|
138
|
+
# Especially for handling the necessary decoding of the options, and sending the
|
139
|
+
# `PublicKeyCredential` object back to the server.
|
140
|
+
```
|
141
|
+
|
142
|
+
#### Verification phase
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
begin
|
146
|
+
# Assuming you're using @github/webauthn-json package to send the `PublicKeyCredential` object back
|
147
|
+
# in params[:publicKeyCredential]:
|
148
|
+
webauthn_credential, stored_credential = relying_party.verify_authentication(
|
149
|
+
params[:publicKeyCredential],
|
150
|
+
session[:authentication_challenge]
|
151
|
+
) do
|
152
|
+
# the returned object needs to respond to #public_key and #sign_count
|
153
|
+
user.credentials.find_by(webauthn_id: webauthn_credential.id)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Update the stored credential sign count with the value from `webauthn_credential.sign_count`
|
157
|
+
stored_credential.update!(sign_count: webauthn_credential.sign_count)
|
158
|
+
|
159
|
+
# Continue with successful sign in or 2FA verification...
|
160
|
+
|
161
|
+
rescue WebAuthn::SignCountVerificationError => e
|
162
|
+
# Cryptographic verification of the authenticator data succeeded, but the signature counter was less then or equal
|
163
|
+
# to the stored value. This can have several reasons and depending on your risk tolerance you can choose to fail or
|
164
|
+
# pass authentication. For more information see https://www.w3.org/TR/webauthn/#sign-counter
|
165
|
+
rescue WebAuthn::Error => e
|
166
|
+
# Handle error
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
## Moving from Global to Instance Based Configuration
|
171
|
+
|
172
|
+
Adding a configuration for a new instance does not mean you need to get rid of your Global configuration. They can co-exist in your application and be both available for the different usages you might have. `WebAuthn.configuration.relying_party` will always return the global one while `WebAuthn::RelyingParty.new`, executed anywhere in your codebase, will allow you to create a different instance as you see the need. They will not collide and instead operate in isolation without any shared state.
|
173
|
+
|
174
|
+
The gem API described in the current [Usage](../README.md#usage) section for the [Global Configuration](../README.md#configuration) approach will still valid but the [Instance Based API](#instance-based-api) also works with the global `relying_party` that is maintain globally at `WebAuthn.configuration.relying_party`.
|
data/docs/u2f_migration.md
CHANGED
@@ -82,7 +82,7 @@ During authentication verification phase, you must pass either the original AppI
|
|
82
82
|
|
83
83
|
```ruby
|
84
84
|
assertion_response = WebAuthn::AuthenticatorAssertionResponse.new(
|
85
|
-
|
85
|
+
user_handle: params[:response][:userHandle],
|
86
86
|
authenticator_data: params[:response][:authenticatorData],
|
87
87
|
client_data_json: params[:response][:clientDataJSON],
|
88
88
|
signature: params[:response][:signature],
|
@@ -90,7 +90,8 @@ assertion_response = WebAuthn::AuthenticatorAssertionResponse.new(
|
|
90
90
|
|
91
91
|
assertion_response.verify(
|
92
92
|
expected_challenge,
|
93
|
-
|
93
|
+
public_key: credential.public_key,
|
94
|
+
sign_count: credential.count,
|
94
95
|
rp_id: params[:clientExtensionResults][:appid] ? domain.to_s : domain.host,
|
95
96
|
)
|
96
97
|
```
|
@@ -20,10 +20,6 @@ module WebAuthn
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
-
def matching_public_key?(authenticator_data)
|
24
|
-
attestation_certificate.public_key.to_der == authenticator_data.credential.public_key_object.to_der
|
25
|
-
end
|
26
|
-
|
27
23
|
def valid_attestation_challenge?(client_data_hash)
|
28
24
|
android_key_attestation.verify_challenge(client_data_hash)
|
29
25
|
rescue AndroidKeyAttestation::ChallengeMismatchError
|
@@ -16,10 +16,6 @@ module WebAuthn
|
|
16
16
|
[attestation_type, attestation_trust_path]
|
17
17
|
end
|
18
18
|
|
19
|
-
def attestation_certificate
|
20
|
-
attestation_trust_path.first
|
21
|
-
end
|
22
|
-
|
23
19
|
private
|
24
20
|
|
25
21
|
def valid_response?(authenticator_data, client_data_hash)
|
@@ -52,7 +48,7 @@ module WebAuthn
|
|
52
48
|
end
|
53
49
|
|
54
50
|
# SafetyNetAttestation returns full chain including root, WebAuthn expects only the x5c certificates
|
55
|
-
def
|
51
|
+
def certificates
|
56
52
|
attestation_response.certificate_chain[0..-2]
|
57
53
|
end
|
58
54
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
require "webauthn/attestation_statement/base"
|
5
|
+
|
6
|
+
module WebAuthn
|
7
|
+
module AttestationStatement
|
8
|
+
class Apple < Base
|
9
|
+
# Source: https://www.apple.com/certificateauthority/private/
|
10
|
+
ROOT_CERTIFICATE =
|
11
|
+
OpenSSL::X509::Certificate.new(<<~PEM)
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w
|
14
|
+
HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ
|
15
|
+
bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx
|
16
|
+
NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG
|
17
|
+
A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49
|
18
|
+
AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k
|
19
|
+
xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/
|
20
|
+
pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk
|
21
|
+
2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
|
22
|
+
MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3
|
23
|
+
jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
|
24
|
+
1bWeT0vT
|
25
|
+
-----END CERTIFICATE-----
|
26
|
+
PEM
|
27
|
+
|
28
|
+
NONCE_EXTENSION_OID = "1.2.840.113635.100.8.2"
|
29
|
+
|
30
|
+
def valid?(authenticator_data, client_data_hash)
|
31
|
+
valid_nonce?(authenticator_data, client_data_hash) &&
|
32
|
+
matching_public_key?(authenticator_data) &&
|
33
|
+
trustworthy? &&
|
34
|
+
[attestation_type, attestation_trust_path]
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def valid_nonce?(authenticator_data, client_data_hash)
|
40
|
+
extension = cred_cert&.find_extension(NONCE_EXTENSION_OID)
|
41
|
+
|
42
|
+
if extension
|
43
|
+
sequence = OpenSSL::ASN1.decode(extension.value_der)
|
44
|
+
|
45
|
+
sequence.tag == OpenSSL::ASN1::SEQUENCE &&
|
46
|
+
sequence.value.size == 1 &&
|
47
|
+
sequence.value[0].value[0].value ==
|
48
|
+
OpenSSL::Digest::SHA256.digest(authenticator_data.data + client_data_hash)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def attestation_type
|
53
|
+
WebAuthn::AttestationStatement::ATTESTATION_TYPE_ANONCA
|
54
|
+
end
|
55
|
+
|
56
|
+
def cred_cert
|
57
|
+
attestation_certificate
|
58
|
+
end
|
59
|
+
|
60
|
+
def default_root_certificates
|
61
|
+
[ROOT_CERTIFICATE]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -16,11 +16,13 @@ module WebAuthn
|
|
16
16
|
ATTESTATION_TYPE_SELF = "Self"
|
17
17
|
ATTESTATION_TYPE_ATTCA = "AttCA"
|
18
18
|
ATTESTATION_TYPE_BASIC_OR_ATTCA = "Basic_or_AttCA"
|
19
|
+
ATTESTATION_TYPE_ANONCA = "AnonCA"
|
19
20
|
|
20
21
|
ATTESTATION_TYPES_WITH_ROOT = [
|
21
22
|
ATTESTATION_TYPE_BASIC,
|
22
23
|
ATTESTATION_TYPE_BASIC_OR_ATTCA,
|
23
|
-
ATTESTATION_TYPE_ATTCA
|
24
|
+
ATTESTATION_TYPE_ATTCA,
|
25
|
+
ATTESTATION_TYPE_ANONCA
|
24
26
|
].freeze
|
25
27
|
|
26
28
|
class Base
|
@@ -42,14 +44,8 @@ module WebAuthn
|
|
42
44
|
certificates&.first
|
43
45
|
end
|
44
46
|
|
45
|
-
def certificate_chain
|
46
|
-
if certificates
|
47
|
-
certificates[1..-1]
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
47
|
def attestation_certificate_key_id
|
52
|
-
|
48
|
+
attestation_certificate.subject_key_identifier&.unpack("H*")&.[](0)
|
53
49
|
end
|
54
50
|
|
55
51
|
private
|
@@ -57,17 +53,19 @@ module WebAuthn
|
|
57
53
|
attr_reader :statement
|
58
54
|
|
59
55
|
def matching_aaguid?(attested_credential_data_aaguid)
|
60
|
-
extension = attestation_certificate&.
|
56
|
+
extension = attestation_certificate&.find_extension(AAGUID_EXTENSION_OID)
|
61
57
|
if extension
|
62
|
-
|
63
|
-
|
64
|
-
extension.to_der[-WebAuthn::AuthenticatorData::AttestedCredentialData::AAGUID_LENGTH..-1] ==
|
65
|
-
attested_credential_data_aaguid
|
58
|
+
aaguid_value = OpenSSL::ASN1.decode(extension.value_der).value
|
59
|
+
aaguid_value == attested_credential_data_aaguid
|
66
60
|
else
|
67
61
|
true
|
68
62
|
end
|
69
63
|
end
|
70
64
|
|
65
|
+
def matching_public_key?(authenticator_data)
|
66
|
+
attestation_certificate.public_key.to_der == authenticator_data.credential.public_key_object.to_der
|
67
|
+
end
|
68
|
+
|
71
69
|
def certificates
|
72
70
|
@certificates ||=
|
73
71
|
raw_certificates&.map do |raw_certificate|
|
@@ -141,15 +139,6 @@ module WebAuthn
|
|
141
139
|
end
|
142
140
|
end
|
143
141
|
|
144
|
-
def raw_subject_key_identifier
|
145
|
-
extension = attestation_certificate.extensions.detect { |ext| ext.oid == "subjectKeyIdentifier" }
|
146
|
-
return unless extension
|
147
|
-
|
148
|
-
ext_asn1 = OpenSSL::ASN1.decode(extension.to_der)
|
149
|
-
ext_value = ext_asn1.value.last
|
150
|
-
OpenSSL::ASN1.decode(ext_value.value).value
|
151
|
-
end
|
152
|
-
|
153
142
|
def valid_signature?(authenticator_data, client_data_hash, public_key = attestation_certificate.public_key)
|
154
143
|
raise("Incompatible algorithm and key") unless cose_algorithm.compatible_key?(public_key)
|
155
144
|
|
@@ -46,7 +46,7 @@ module WebAuthn
|
|
46
46
|
|
47
47
|
attestation_certificate.version == 2 &&
|
48
48
|
subject.assoc('OU')&.at(1) == "Authenticator Attestation" &&
|
49
|
-
attestation_certificate.
|
49
|
+
attestation_certificate.find_extension('basicConstraints')&.value == 'CA:FALSE'
|
50
50
|
else
|
51
51
|
true
|
52
52
|
end
|
@@ -42,7 +42,7 @@ module WebAuthn
|
|
42
42
|
OpenSSL::Digest.digest(cose_algorithm.hash_function, certified_extra_data),
|
43
43
|
signature_algorithm: tpm_algorithm[:signature],
|
44
44
|
hash_algorithm: tpm_algorithm[:hash],
|
45
|
-
|
45
|
+
trusted_certificates: root_certificates(aaguid: aaguid)
|
46
46
|
)
|
47
47
|
|
48
48
|
key_attestation.valid? && key_attestation.key && key_attestation.key.to_pem == key.to_pem
|
@@ -54,7 +54,7 @@ module WebAuthn
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def default_root_certificates
|
57
|
-
::TPM::KeyAttestation::
|
57
|
+
::TPM::KeyAttestation::TRUSTED_CERTIFICATES
|
58
58
|
end
|
59
59
|
|
60
60
|
def tpm_algorithm
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "webauthn/attestation_statement/android_key"
|
4
4
|
require "webauthn/attestation_statement/android_safetynet"
|
5
|
+
require "webauthn/attestation_statement/apple"
|
5
6
|
require "webauthn/attestation_statement/fido_u2f"
|
6
7
|
require "webauthn/attestation_statement/none"
|
7
8
|
require "webauthn/attestation_statement/packed"
|
@@ -18,6 +19,7 @@ module WebAuthn
|
|
18
19
|
ATTESTATION_FORMAT_ANDROID_SAFETYNET = "android-safetynet"
|
19
20
|
ATTESTATION_FORMAT_ANDROID_KEY = "android-key"
|
20
21
|
ATTESTATION_FORMAT_TPM = "tpm"
|
22
|
+
ATTESTATION_FORMAT_APPLE = "apple"
|
21
23
|
|
22
24
|
FORMAT_TO_CLASS = {
|
23
25
|
ATTESTATION_FORMAT_NONE => WebAuthn::AttestationStatement::None,
|
@@ -25,7 +27,8 @@ module WebAuthn
|
|
25
27
|
ATTESTATION_FORMAT_PACKED => WebAuthn::AttestationStatement::Packed,
|
26
28
|
ATTESTATION_FORMAT_ANDROID_SAFETYNET => WebAuthn::AttestationStatement::AndroidSafetynet,
|
27
29
|
ATTESTATION_FORMAT_ANDROID_KEY => WebAuthn::AttestationStatement::AndroidKey,
|
28
|
-
ATTESTATION_FORMAT_TPM => WebAuthn::AttestationStatement::TPM
|
30
|
+
ATTESTATION_FORMAT_TPM => WebAuthn::AttestationStatement::TPM,
|
31
|
+
ATTESTATION_FORMAT_APPLE => WebAuthn::AttestationStatement::Apple
|
29
32
|
}.freeze
|
30
33
|
|
31
34
|
def self.from(format, statement)
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require "webauthn/authenticator_data"
|
4
4
|
require "webauthn/client_data"
|
5
5
|
require "webauthn/error"
|
6
|
-
require "webauthn/security_utils"
|
7
6
|
|
8
7
|
module WebAuthn
|
9
8
|
TYPES = { create: "webauthn.create", get: "webauthn.get" }.freeze
|
@@ -79,7 +78,7 @@ module WebAuthn
|
|
79
78
|
end
|
80
79
|
|
81
80
|
def valid_challenge?(expected_challenge)
|
82
|
-
|
81
|
+
OpenSSL.secure_compare(client_data.challenge, expected_challenge)
|
83
82
|
end
|
84
83
|
|
85
84
|
def valid_origin?(expected_origin)
|
@@ -16,11 +16,7 @@ module WebAuthn
|
|
16
16
|
class RootCertificateFinderNotSupportedError < Error; end
|
17
17
|
|
18
18
|
class Configuration
|
19
|
-
|
20
|
-
OpenSSL::PKey::RSA.instance_methods.include?(:verify_pss) ? algorithm : nil
|
21
|
-
end
|
22
|
-
|
23
|
-
DEFAULT_ALGORITHMS = ["ES256", if_pss_supported("PS256"), "RS256"].compact.freeze
|
19
|
+
DEFAULT_ALGORITHMS = ["ES256", "PS256", "RS256"].compact.freeze
|
24
20
|
|
25
21
|
attr_accessor :algorithms
|
26
22
|
attr_accessor :encoding
|
@@ -39,7 +35,7 @@ module WebAuthn
|
|
39
35
|
@verify_attestation_statement = true
|
40
36
|
@credential_options_timeout = 120000
|
41
37
|
@silent_authentication = false
|
42
|
-
@acceptable_attestation_types = ['None', 'Self', 'Basic', 'AttCA', 'Basic_or_AttCA']
|
38
|
+
@acceptable_attestation_types = ['None', 'Self', 'Basic', 'AttCA', 'Basic_or_AttCA', 'AnonCA']
|
43
39
|
@attestation_root_certificates_finders = []
|
44
40
|
end
|
45
41
|
|
@@ -15,7 +15,7 @@ module WebAuthn
|
|
15
15
|
rp_id_hash:,
|
16
16
|
credential: {
|
17
17
|
id: SecureRandom.random_bytes(16),
|
18
|
-
public_key: OpenSSL::PKey::EC.
|
18
|
+
public_key: OpenSSL::PKey::EC.generate("prime256v1").public_key
|
19
19
|
},
|
20
20
|
sign_count: 0,
|
21
21
|
user_present: true,
|
@@ -50,12 +50,20 @@ module WebAuthn
|
|
50
50
|
user_verified: false,
|
51
51
|
aaguid: AuthenticatorData::AAGUID,
|
52
52
|
sign_count: nil,
|
53
|
-
extensions: nil
|
53
|
+
extensions: nil,
|
54
|
+
allow_credentials: nil
|
54
55
|
)
|
55
56
|
credential_options = credentials[rp_id]
|
56
57
|
|
57
58
|
if credential_options
|
58
|
-
|
59
|
+
allow_credentials ||= credential_options.keys
|
60
|
+
credential_id = (credential_options.keys & allow_credentials).first
|
61
|
+
unless credential_id
|
62
|
+
raise "No matching credentials (allowed=#{allow_credentials}) " \
|
63
|
+
"found for RP #{rp_id} among credentials=#{credential_options}"
|
64
|
+
end
|
65
|
+
|
66
|
+
credential = credential_options[credential_id]
|
59
67
|
credential_key = credential[:credential_key]
|
60
68
|
credential_sign_count = credential[:sign_count]
|
61
69
|
|
@@ -87,7 +95,7 @@ module WebAuthn
|
|
87
95
|
attr_reader :credentials
|
88
96
|
|
89
97
|
def new_credential
|
90
|
-
[SecureRandom.random_bytes(16), OpenSSL::PKey::EC.
|
98
|
+
[SecureRandom.random_bytes(16), OpenSSL::PKey::EC.generate("prime256v1"), 0]
|
91
99
|
end
|
92
100
|
|
93
101
|
def hashed(target)
|
data/lib/webauthn/fake_client.rb
CHANGED
@@ -74,19 +74,25 @@ module WebAuthn
|
|
74
74
|
user_verified: false,
|
75
75
|
sign_count: nil,
|
76
76
|
extensions: nil,
|
77
|
-
user_handle: nil
|
77
|
+
user_handle: nil,
|
78
|
+
allow_credentials: nil)
|
78
79
|
rp_id ||= URI.parse(origin).host
|
79
80
|
|
80
81
|
client_data_json = data_json_for(:get, encoder.decode(challenge))
|
81
82
|
client_data_hash = hashed(client_data_json)
|
82
83
|
|
84
|
+
if allow_credentials
|
85
|
+
allow_credentials = allow_credentials.map { |credential| encoder.decode(credential) }
|
86
|
+
end
|
87
|
+
|
83
88
|
assertion = authenticator.get_assertion(
|
84
89
|
rp_id: rp_id,
|
85
90
|
client_data_hash: client_data_hash,
|
86
91
|
user_present: user_present,
|
87
92
|
user_verified: user_verified,
|
88
93
|
sign_count: sign_count,
|
89
|
-
extensions: extensions
|
94
|
+
extensions: extensions,
|
95
|
+
allow_credentials: allow_credentials
|
90
96
|
)
|
91
97
|
|
92
98
|
{
|
@@ -5,11 +5,10 @@ require "awrence"
|
|
5
5
|
module WebAuthn
|
6
6
|
class PublicKeyCredential
|
7
7
|
class Entity
|
8
|
-
attr_reader :name
|
8
|
+
attr_reader :name
|
9
9
|
|
10
|
-
def initialize(name
|
10
|
+
def initialize(name:)
|
11
11
|
@name = name
|
12
|
-
@icon = icon
|
13
12
|
end
|
14
13
|
|
15
14
|
def as_json
|
@@ -37,7 +36,7 @@ module WebAuthn
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def attributes
|
40
|
-
[:name
|
39
|
+
[:name]
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
data/lib/webauthn/version.rb
CHANGED
data/webauthn.gemspec
CHANGED
@@ -38,16 +38,15 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_dependency "bindata", "~> 2.4"
|
39
39
|
spec.add_dependency "cbor", "~> 0.5.9"
|
40
40
|
spec.add_dependency "cose", "~> 1.1"
|
41
|
-
spec.add_dependency "openssl", "
|
41
|
+
spec.add_dependency "openssl", ">= 2.2", "< 3.1"
|
42
42
|
spec.add_dependency "safety_net_attestation", "~> 0.4.0"
|
43
|
-
spec.add_dependency "
|
44
|
-
spec.add_dependency "tpm-key_attestation", "~> 0.10.0"
|
43
|
+
spec.add_dependency "tpm-key_attestation", "~> 0.11.0"
|
45
44
|
|
46
|
-
spec.add_development_dependency "appraisal", "~> 2.3.0"
|
47
45
|
spec.add_development_dependency "bundler", ">= 1.17", "< 3.0"
|
48
46
|
spec.add_development_dependency "byebug", "~> 11.0"
|
49
47
|
spec.add_development_dependency "rake", "~> 13.0"
|
50
48
|
spec.add_development_dependency "rspec", "~> 3.8"
|
51
|
-
spec.add_development_dependency "rubocop", "
|
52
|
-
spec.add_development_dependency "rubocop-
|
49
|
+
spec.add_development_dependency "rubocop", "~> 1.9.1"
|
50
|
+
spec.add_development_dependency "rubocop-rake", "~> 0.5.1"
|
51
|
+
spec.add_development_dependency "rubocop-rspec", "~> 2.2.0"
|
53
52
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webauthn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gonzalo Rodriguez
|
8
8
|
- Braulio Martinez
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-07-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: android_key_attestation
|
@@ -85,16 +85,22 @@ dependencies:
|
|
85
85
|
name: openssl
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- - "
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '2.2'
|
91
|
+
- - "<"
|
89
92
|
- !ruby/object:Gem::Version
|
90
|
-
version: '
|
93
|
+
version: '3.1'
|
91
94
|
type: :runtime
|
92
95
|
prerelease: false
|
93
96
|
version_requirements: !ruby/object:Gem::Requirement
|
94
97
|
requirements:
|
95
|
-
- - "
|
98
|
+
- - ">="
|
96
99
|
- !ruby/object:Gem::Version
|
97
|
-
version: '2.
|
100
|
+
version: '2.2'
|
101
|
+
- - "<"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.1'
|
98
104
|
- !ruby/object:Gem::Dependency
|
99
105
|
name: safety_net_attestation
|
100
106
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,48 +115,20 @@ dependencies:
|
|
109
115
|
- - "~>"
|
110
116
|
- !ruby/object:Gem::Version
|
111
117
|
version: 0.4.0
|
112
|
-
- !ruby/object:Gem::Dependency
|
113
|
-
name: securecompare
|
114
|
-
requirement: !ruby/object:Gem::Requirement
|
115
|
-
requirements:
|
116
|
-
- - "~>"
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
version: '1.0'
|
119
|
-
type: :runtime
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
requirements:
|
123
|
-
- - "~>"
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: '1.0'
|
126
118
|
- !ruby/object:Gem::Dependency
|
127
119
|
name: tpm-key_attestation
|
128
120
|
requirement: !ruby/object:Gem::Requirement
|
129
121
|
requirements:
|
130
122
|
- - "~>"
|
131
123
|
- !ruby/object:Gem::Version
|
132
|
-
version: 0.
|
124
|
+
version: 0.11.0
|
133
125
|
type: :runtime
|
134
126
|
prerelease: false
|
135
127
|
version_requirements: !ruby/object:Gem::Requirement
|
136
128
|
requirements:
|
137
129
|
- - "~>"
|
138
130
|
- !ruby/object:Gem::Version
|
139
|
-
version: 0.
|
140
|
-
- !ruby/object:Gem::Dependency
|
141
|
-
name: appraisal
|
142
|
-
requirement: !ruby/object:Gem::Requirement
|
143
|
-
requirements:
|
144
|
-
- - "~>"
|
145
|
-
- !ruby/object:Gem::Version
|
146
|
-
version: 2.3.0
|
147
|
-
type: :development
|
148
|
-
prerelease: false
|
149
|
-
version_requirements: !ruby/object:Gem::Requirement
|
150
|
-
requirements:
|
151
|
-
- - "~>"
|
152
|
-
- !ruby/object:Gem::Version
|
153
|
-
version: 2.3.0
|
131
|
+
version: 0.11.0
|
154
132
|
- !ruby/object:Gem::Dependency
|
155
133
|
name: bundler
|
156
134
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,30 +195,44 @@ dependencies:
|
|
217
195
|
name: rubocop
|
218
196
|
requirement: !ruby/object:Gem::Requirement
|
219
197
|
requirements:
|
220
|
-
- -
|
198
|
+
- - "~>"
|
221
199
|
- !ruby/object:Gem::Version
|
222
|
-
version:
|
200
|
+
version: 1.9.1
|
223
201
|
type: :development
|
224
202
|
prerelease: false
|
225
203
|
version_requirements: !ruby/object:Gem::Requirement
|
226
204
|
requirements:
|
227
|
-
- -
|
205
|
+
- - "~>"
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: 1.9.1
|
208
|
+
- !ruby/object:Gem::Dependency
|
209
|
+
name: rubocop-rake
|
210
|
+
requirement: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - "~>"
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: 0.5.1
|
215
|
+
type: :development
|
216
|
+
prerelease: false
|
217
|
+
version_requirements: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - "~>"
|
228
220
|
- !ruby/object:Gem::Version
|
229
|
-
version:
|
221
|
+
version: 0.5.1
|
230
222
|
- !ruby/object:Gem::Dependency
|
231
223
|
name: rubocop-rspec
|
232
224
|
requirement: !ruby/object:Gem::Requirement
|
233
225
|
requirements:
|
234
226
|
- - "~>"
|
235
227
|
- !ruby/object:Gem::Version
|
236
|
-
version:
|
228
|
+
version: 2.2.0
|
237
229
|
type: :development
|
238
230
|
prerelease: false
|
239
231
|
version_requirements: !ruby/object:Gem::Requirement
|
240
232
|
requirements:
|
241
233
|
- - "~>"
|
242
234
|
- !ruby/object:Gem::Version
|
243
|
-
version:
|
235
|
+
version: 2.2.0
|
244
236
|
description: |-
|
245
237
|
WebAuthn ruby server library ― Make your application a W3C Web Authentication conformant
|
246
238
|
Relying Party and allow your users to authenticate with U2F and FIDO2 authenticators.
|
@@ -251,11 +243,11 @@ executables: []
|
|
251
243
|
extensions: []
|
252
244
|
extra_rdoc_files: []
|
253
245
|
files:
|
246
|
+
- ".github/workflows/build.yml"
|
247
|
+
- ".github/workflows/git.yml"
|
254
248
|
- ".gitignore"
|
255
249
|
- ".rspec"
|
256
250
|
- ".rubocop.yml"
|
257
|
-
- ".travis.yml"
|
258
|
-
- Appraisals
|
259
251
|
- CHANGELOG.md
|
260
252
|
- CONTRIBUTING.md
|
261
253
|
- Gemfile
|
@@ -265,18 +257,15 @@ files:
|
|
265
257
|
- SECURITY.md
|
266
258
|
- bin/console
|
267
259
|
- bin/setup
|
260
|
+
- docs/advanced_configuration.md
|
268
261
|
- docs/u2f_migration.md
|
269
|
-
- gemfiles/cose_head.gemfile
|
270
|
-
- gemfiles/openssl_2_0.gemfile
|
271
|
-
- gemfiles/openssl_2_1.gemfile
|
272
|
-
- gemfiles/openssl_2_2.gemfile
|
273
|
-
- gemfiles/openssl_head.gemfile
|
274
262
|
- lib/cose/rsapkcs1_algorithm.rb
|
275
263
|
- lib/webauthn.rb
|
276
264
|
- lib/webauthn/attestation_object.rb
|
277
265
|
- lib/webauthn/attestation_statement.rb
|
278
266
|
- lib/webauthn/attestation_statement/android_key.rb
|
279
267
|
- lib/webauthn/attestation_statement/android_safetynet.rb
|
268
|
+
- lib/webauthn/attestation_statement/apple.rb
|
280
269
|
- lib/webauthn/attestation_statement/base.rb
|
281
270
|
- lib/webauthn/attestation_statement/fido_u2f.rb
|
282
271
|
- lib/webauthn/attestation_statement/fido_u2f/public_key.rb
|
@@ -313,11 +302,8 @@ files:
|
|
313
302
|
- lib/webauthn/public_key_credential/user_entity.rb
|
314
303
|
- lib/webauthn/public_key_credential_with_assertion.rb
|
315
304
|
- lib/webauthn/public_key_credential_with_attestation.rb
|
316
|
-
- lib/webauthn/security_utils.rb
|
317
305
|
- lib/webauthn/u2f_migrator.rb
|
318
306
|
- lib/webauthn/version.rb
|
319
|
-
- script/ci/install-openssl
|
320
|
-
- script/ci/install-ruby
|
321
307
|
- webauthn.gemspec
|
322
308
|
homepage: https://github.com/cedarcode/webauthn-ruby
|
323
309
|
licenses:
|
@@ -326,7 +312,7 @@ metadata:
|
|
326
312
|
bug_tracker_uri: https://github.com/cedarcode/webauthn-ruby/issues
|
327
313
|
changelog_uri: https://github.com/cedarcode/webauthn-ruby/blob/master/CHANGELOG.md
|
328
314
|
source_code_uri: https://github.com/cedarcode/webauthn-ruby
|
329
|
-
post_install_message:
|
315
|
+
post_install_message:
|
330
316
|
rdoc_options: []
|
331
317
|
require_paths:
|
332
318
|
- lib
|
@@ -341,8 +327,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
341
327
|
- !ruby/object:Gem::Version
|
342
328
|
version: '0'
|
343
329
|
requirements: []
|
344
|
-
rubygems_version: 3.2.
|
345
|
-
signing_key:
|
330
|
+
rubygems_version: 3.2.32
|
331
|
+
signing_key:
|
346
332
|
specification_version: 4
|
347
333
|
summary: WebAuthn ruby server library
|
348
334
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
dist: bionic
|
2
|
-
language: ruby
|
3
|
-
|
4
|
-
cache:
|
5
|
-
bundler: true
|
6
|
-
directories:
|
7
|
-
- /home/travis/.rvm/
|
8
|
-
|
9
|
-
env:
|
10
|
-
- LIBSSL=1.1 RB=2.7.1
|
11
|
-
- LIBSSL=1.1 RB=2.6.6
|
12
|
-
- LIBSSL=1.1 RB=2.5.8
|
13
|
-
- LIBSSL=1.1 RB=2.4.10
|
14
|
-
- LIBSSL=1.1 RB=ruby-head
|
15
|
-
- LIBSSL=1.0 RB=2.7.1
|
16
|
-
- LIBSSL=1.0 RB=2.6.6
|
17
|
-
- LIBSSL=1.0 RB=2.5.8
|
18
|
-
- LIBSSL=1.0 RB=2.4.10
|
19
|
-
- LIBSSL=1.0 RB=ruby-head
|
20
|
-
|
21
|
-
gemfile:
|
22
|
-
- gemfiles/cose_head.gemfile
|
23
|
-
- gemfiles/openssl_head.gemfile
|
24
|
-
- gemfiles/openssl_2_2.gemfile
|
25
|
-
- gemfiles/openssl_2_1.gemfile
|
26
|
-
- gemfiles/openssl_2_0.gemfile
|
27
|
-
|
28
|
-
matrix:
|
29
|
-
fast_finish: true
|
30
|
-
allow_failures:
|
31
|
-
- env: LIBSSL=1.1 RB=ruby-head
|
32
|
-
- env: LIBSSL=1.0 RB=ruby-head
|
33
|
-
- gemfile: gemfiles/cose_head.gemfile
|
34
|
-
- gemfile: gemfiles/openssl_head.gemfile
|
35
|
-
|
36
|
-
before_install:
|
37
|
-
- ./script/ci/install-openssl
|
38
|
-
- ./script/ci/install-ruby
|
39
|
-
- gem install bundler -v "~> 2.0"
|
data/Appraisals
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
appraise "cose_head" do
|
4
|
-
gem "cose", git: "https://github.com/cedarcode/cose-ruby"
|
5
|
-
end
|
6
|
-
|
7
|
-
appraise "openssl_head" do
|
8
|
-
gem "openssl", git: "https://github.com/ruby/openssl"
|
9
|
-
end
|
10
|
-
|
11
|
-
appraise "openssl_2_2" do
|
12
|
-
gem "openssl", "~> 2.2.0"
|
13
|
-
end
|
14
|
-
|
15
|
-
appraise "openssl_2_1" do
|
16
|
-
gem "openssl", "~> 2.1.0"
|
17
|
-
end
|
18
|
-
|
19
|
-
appraise "openssl_2_0" do
|
20
|
-
gem "openssl", "~> 2.0.0"
|
21
|
-
end
|
data/gemfiles/cose_head.gemfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "securecompare"
|
4
|
-
|
5
|
-
module WebAuthn
|
6
|
-
module SecurityUtils
|
7
|
-
# Constant time string comparison, for variable length strings.
|
8
|
-
# This code was adapted from Rails ActiveSupport::SecurityUtils
|
9
|
-
#
|
10
|
-
# The values are first processed by SHA256, so that we don't leak length info
|
11
|
-
# via timing attacks.
|
12
|
-
def secure_compare(first_string, second_string)
|
13
|
-
first_string_sha256 = ::Digest::SHA256.digest(first_string)
|
14
|
-
second_string_sha256 = ::Digest::SHA256.digest(second_string)
|
15
|
-
|
16
|
-
SecureCompare.compare(first_string_sha256, second_string_sha256) && first_string == second_string
|
17
|
-
end
|
18
|
-
module_function :secure_compare
|
19
|
-
end
|
20
|
-
end
|
data/script/ci/install-openssl
DELETED
data/script/ci/install-ruby
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
|
3
|
-
set -e
|
4
|
-
|
5
|
-
source "$HOME/.rvm/scripts/rvm"
|
6
|
-
|
7
|
-
if [[ "$LIBSSL" == "1.0" ]]; then
|
8
|
-
rvm use --install $RB --autolibs=read-only --disable-binary
|
9
|
-
elif [[ "$LIBSSL" == "1.1" ]]; then
|
10
|
-
rvm use --install $RB --binary --fuzzy
|
11
|
-
fi
|
12
|
-
|
13
|
-
[[ "`ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION'`" =~ "OpenSSL $LIBSSL" ]] || { echo "Wrong libssl version"; exit 1; }
|