webauthn 1.17.0 → 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4cc833d8288e0519614728a71e26e4e7842ec0c597bd7fc839fe9bacbb44c61
4
- data.tar.gz: 712c9ad093705954409facf4ee171752ba76865cbca831121a0f88a4c4d9430c
3
+ metadata.gz: 7a6a15357ab32b764ce0694b5a6cc4950e9298e377c8a93f8b664befb67dffcb
4
+ data.tar.gz: 3481eba4bbdd21676eda5015c9ebc9d11a92422ab0d57b6fed1da31b2ebc9d14
5
5
  SHA512:
6
- metadata.gz: 6fd66258429cadca7660ce7c69640b630b13bd21ac4b690d60c37834edcf4b6ce368688186f1b1a23fba8dc4856767314f7a7308e1ae9932f2f51776fabe89cb
7
- data.tar.gz: a28362aa5cf1bd451a5b0303750bb55ffd80f2b47c63c9ef04b7f04e300c8b4f997ec0d6a808361503ecb0b780c263d2447c36bde0239657bc3cc5fd6b106719
6
+ metadata.gz: 78f3d1242e008dac5a7d1b66944f6e64dd2a11baced08a454ca587d5bb7b5a93b2e51052d044f8c34034355ab2536af96438b9178e9b6536e92366cd55fbe495
7
+ data.tar.gz: 1e4ecf4a58bad0213e0893834f57f5564ce9b2d9d76ad214e35a85d7ede4d693d0d9f55a289fe998ac4ee4479279d7c521afef98fd7ddce1eec1f849d346948d
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.18.0] - 2019-07-27
4
+
5
+ ### Added
6
+
7
+ - Ability to migrate U2F credentials to WebAuthn ([#211](https://github.com/cedarcode/webauthn-ruby/pull/211)) (@bdewater + @jdongelmans)
8
+ - Ability to skip attestation statement verification ([#219](https://github.com/cedarcode/webauthn-ruby/pull/219)) (@MaximeNdutiye)
9
+ - Ability to configure default credential options timeout ([#243](https://github.com/cedarcode/webauthn-ruby/pull/243)) (@MaximeNdutiye)
10
+ - AttestedCredentialData presence verification ([#237](https://github.com/cedarcode/webauthn-ruby/pull/237))
11
+ - FakeClient learns how to increment sign count ([#225](https://github.com/cedarcode/webauthn-ruby/pull/225))
12
+
13
+ ### Fixed
14
+
15
+ - Properly verify SafetyNet certificates from input ([#233](https://github.com/cedarcode/webauthn-ruby/pull/233)) (@bdewater)
16
+ - FakeClient default origin URL ([#242](https://github.com/cedarcode/webauthn-ruby/pull/242)) (@kalebtesfay)
17
+
3
18
  ## [v1.17.0] - 2019-06-18
4
19
 
5
20
  ### Added
@@ -194,6 +209,7 @@ Note: Both additions should help making it compatible with Chrome for Android 70
194
209
  - `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
195
210
  - Works with ruby 2.5
196
211
 
212
+ [v1.18.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.17.0...v1.18.0/
197
213
  [v1.17.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.16.0...v1.17.0/
198
214
  [v1.16.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.15.0...v1.16.0/
199
215
  [v1.15.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.14.0...v1.15.0/
@@ -0,0 +1,44 @@
1
+ ## Contributing to webauthn-ruby
2
+
3
+ ### How?
4
+
5
+ - Creating a new issue to report a bug
6
+ - Creating a new issue to suggest a new feature
7
+ - Commenting on an existing issue to answer an open question
8
+ - Commenting on an existing issue to ask the reporter for more details to aid reproducing the problem
9
+ - Improving documentation
10
+ - Creating a pull request that fixes an issue (see [beginner friendly issues](https://github.com/cedarcode/webauthn-ruby/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22))
11
+ - Creating a pull request that implements a new feature (worth first creating an issue to discuss the suggested feature)
12
+
13
+ ### Development
14
+
15
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests and code-style checks. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
16
+
17
+ Some tests require stubbing time with [libfaketime](https://github.com/wolfcw/libfaketime) in order to pass, otherwise they're skipped. You can install this library with your package manager. Follow libfaketime's instructions for your OS to preload the library before running the tests, and use the `DONT_FAKE_MONOTONIC=1 FAKETIME_NO_CACHE=1` options. E.g. when installed via homebrew on macOS:
18
+ ```shell
19
+ DYLD_INSERT_LIBRARIES=/usr/local/Cellar/libfaketime/2.9.7_1/lib/faketime/libfaketime.1.dylib DYLD_FORCE_FLAT_NAMESPACE=1 DONT_FAKE_MONOTONIC=1 FAKETIME_NO_CACHE=1 bundle exec rspec
20
+ ```
21
+
22
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
23
+
24
+ ### Styleguide
25
+
26
+ #### Ruby
27
+
28
+ We use [rubocop](https://rubygems.org/gems/rubocop) to check ruby code style.
29
+
30
+ #### Git commit messages
31
+
32
+ We try to follow [Conventional Commits](https://conventionalcommits.org) specification since `v1.17.0`.
33
+
34
+ On top of `fix` and `feat` types, we also use optional:
35
+
36
+ * __build__: Changes that affect the build system or external dependencies
37
+ * __ci__: Changes to the CI configuration files and scripts
38
+ * __docs__: Documentation only changes
39
+ * __perf__: A code change that improves performance
40
+ * __refactor__: A code change that neither fixes a bug nor adds a feature
41
+ * __style__: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
42
+ * __test__: Adding missing tests or correcting existing tests
43
+
44
+ Partially inspired in [Angular's Commit Message Guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines).
data/README.md CHANGED
@@ -1,4 +1,13 @@
1
- # WebAuthn ruby server library :key:
1
+ # webauthn-ruby
2
+
3
+ ![banner](webauthn-ruby.png)
4
+
5
+ [![Gem](https://img.shields.io/gem/v/webauthn.svg?style=flat-square)](https://rubygems.org/gems/webauthn)
6
+ [![Travis](https://img.shields.io/travis/cedarcode/webauthn-ruby/master.svg?style=flat-square)](https://travis-ci.org/cedarcode/webauthn-ruby)
7
+ [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-informational.svg?style=flat-square)](https://conventionalcommits.org)
8
+ [![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)
9
+
10
+ > WebAuthn ruby server library
2
11
 
3
12
  Makes your Ruby/Rails web server become a functional [WebAuthn Relying Party](https://www.w3.org/TR/webauthn/#webauthn-relying-party).
4
13
 
@@ -6,24 +15,40 @@ Takes care of the [server-side operations](https://www.w3.org/TR/webauthn/#rp-op
6
15
  [register](https://www.w3.org/TR/webauthn/#registration) or [authenticate](https://www.w3.org/TR/webauthn/#authentication)
7
16
  a user [credential](https://www.w3.org/TR/webauthn/#public-key-credential), including the necessary cryptographic checks.
8
17
 
9
- [![Gem](https://img.shields.io/gem/v/webauthn.svg?style=flat-square)](https://rubygems.org/gems/webauthn)
10
- [![Travis](https://img.shields.io/travis/cedarcode/webauthn-ruby/master.svg?style=flat-square)](https://travis-ci.org/cedarcode/webauthn-ruby)
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)
18
+ ## Table of Contents
19
+
20
+ - [Security](#security)
21
+ - [Background](#background)
22
+ - [Prerequisites](#prerequisites)
23
+ - [Install](#install)
24
+ - [Usage](#usage)
25
+ - [API](#api)
26
+ - [Attestation Statement Formats](#attestation-statement-formats)
27
+ - [Testing Your Integration](#testing-your-integration)
28
+ - [Contributing](#contributing)
29
+ - [License](#license)
12
30
 
13
- ## Why WebAuthn in my web server?
31
+ ## Security
32
+
33
+ If you have discovered a security bug, please send an email to security@cedarcode.com instead of posting to the GitHub issue tracker.
14
34
 
15
- - [Security Benefits for WebAuthn Relying Parties](https://www.w3.org/TR/webauthn/#sctn-rp-benefits)
35
+ ## Background
16
36
 
17
- ## What is WebAuthn?
37
+ ### What is WebAuthn?
18
38
 
19
39
  WebAuthn (Web Authentication) is a W3C standard for secure public-key authentication on the Web supported by all leading browsers and platforms.
20
40
 
41
+ #### Good Intros
42
+
43
+ - [Guide to Web Authentication](https://webauthn.guide) by Duo
44
+ - [What is WebAuthn?](https://www.yubico.com/webauthn/) by Yubico
45
+
46
+ #### In Depth
47
+
21
48
  - WebAuthn [W3C Recommendation](https://www.w3.org/TR/webauthn/) (i.e. "The Standard")
22
- - WebAuthn [intro](https://www.yubico.com/webauthn/) by Yubico
23
- - WebAuthn [article](https://en.wikipedia.org/wiki/WebAuthn) in Wikipedia
24
49
  - [Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API) in MDN
25
- - WebAuthn [article with talk](https://developers.google.com/web/updates/2018/05/webauthn) in Google Developers
26
50
  - How to use [WebAuthn in Android apps](https://developers.google.com/identity/fido/android/native-apps)
51
+ - [Security Benefits for WebAuthn Servers (a.k.a Relying Parties)](https://www.w3.org/TR/webauthn/#sctn-rp-benefits)
27
52
 
28
53
  ## Prerequisites
29
54
 
@@ -41,7 +66,7 @@ For a detailed picture about what is conformant and what not, you can refer to:
41
66
  - [FIDO certified products](https://fidoalliance.org/certification/fido-certified-products)
42
67
 
43
68
 
44
- ## Installation
69
+ ## Install
45
70
 
46
71
  Add this line to your application's Gemfile:
47
72
 
@@ -59,7 +84,10 @@ Or install it yourself as:
59
84
 
60
85
  ## Usage
61
86
 
62
- NOTE: You can find a working example on how to use this gem in a __Rails__ app in [webauthn-rails-demo-app](https://github.com/cedarcode/webauthn-rails-demo-app).
87
+ You can find a working example on how to use this gem in a __Rails__ app in [webauthn-rails-demo-app](https://github.com/cedarcode/webauthn-rails-demo-app).
88
+
89
+ If you are migrating an existing application from the legacy FIDO U2F JavaScript API to WebAuthn, also refer to
90
+ [`docs/u2f_migration.md`](docs/u2f_migration.md).
63
91
 
64
92
  ### Configuration
65
93
 
@@ -74,6 +102,13 @@ WebAuthn.configure do |config|
74
102
  # Relying Party name for display purposes
75
103
  config.rp_name = "Example Inc."
76
104
 
105
+ # Optionally configure a client timeout hint, in milliseconds.
106
+ # This hint specifies how long the browser should wait for an
107
+ # attestation or an assertion response.
108
+ # This hint may be overridden by the browser.
109
+ # https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout
110
+ config.credential_options_timeout = 120000
111
+
77
112
  # You can optionally specify a different Relying Party ID
78
113
  # (https://www.w3.org/TR/webauthn/#relying-party-identifier)
79
114
  # if it differs from the default one.
@@ -204,6 +239,10 @@ end
204
239
  # Update the stored sign count with the value from `assertion_response.authenticator_data.sign_count`
205
240
  ```
206
241
 
242
+ ## API
243
+
244
+ _Pending_
245
+
207
246
  ## Attestation Statement Formats
208
247
 
209
248
  | Attestation Statement Format | Supported? |
@@ -224,43 +263,12 @@ NOTE: Be aware that it is up to you to do "trust path validation" (steps 15 and
224
263
 
225
264
  The Webauthn spec requires for data that is signed and authenticated. As a result, it can be difficult to create valid test authenticator data when testing your integration. webauthn-ruby exposes [WebAuthn::FakeClient](https://github.com/cedarcode/webauthn-ruby/blob/master/lib/webauthn/fake_client.rb) for you to use in your tests. Example usage can be found in [webauthn-ruby/spec/webauthn/authenticator_assertion_response_spec.rb](https://github.com/cedarcode/webauthn-ruby/blob/master/spec/webauthn/authenticator_assertion_response_spec.rb).
226
265
 
227
- ## Development
228
-
229
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests and code-style checks. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
230
-
231
- Some tests require stubbing time with [libfaketime](https://github.com/wolfcw/libfaketime) in order to pass, otherwise they're skipped. You can install this library with your package manager. Follow libfaketime's instructions for your OS to preload the library before running the tests, and use the `DONT_FAKE_MONOTONIC=1 FAKETIME_NO_CACHE=1` options. E.g. when installed via homebrew on macOS:
232
- ```shell
233
- DYLD_INSERT_LIBRARIES=/usr/local/Cellar/libfaketime/2.9.7_1/lib/faketime/libfaketime.1.dylib DYLD_FORCE_FLAT_NAMESPACE=1 DONT_FAKE_MONOTONIC=1 FAKETIME_NO_CACHE=1 bundle exec rspec
234
- ```
235
-
236
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
237
-
238
- ### Commit message format
239
-
240
- Each commit message follows the `<type>: <message>` format.
241
-
242
- The "message" starts with lowercase and the "type" is one of:
243
-
244
- * __build__: Changes that affect the build system or external dependencies
245
- * __ci__: Changes to the CI configuration files and scripts
246
- * __docs__: Documentation only changes
247
- * __feat__: A new feature
248
- * __fix__: A bug fix
249
- * __perf__: A code change that improves performance
250
- * __refactor__: A code change that neither fixes a bug nor adds a feature
251
- * __style__: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
252
- * __test__: Adding missing tests or correcting existing tests
253
-
254
- Inspired in a subset of [Angular's Commit Message Guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines).
255
-
256
266
  ## Contributing
257
267
 
258
- Bug reports and pull requests are welcome on GitHub at https://github.com/cedarcode/webauthn-ruby.
259
-
260
- ### Security
268
+ See [the contributing file](CONTRIBUTING.md)!
261
269
 
262
- If you have discovered a security bug, please send an email to security@cedarcode.com instead of posting to the GitHub issue tracker.
270
+ Bug reports, feature suggestions, and pull requests are welcome on GitHub at https://github.com/cedarcode/webauthn-ruby.
263
271
 
264
272
  ## License
265
273
 
266
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
274
+ The library is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,96 @@
1
+ # Migrating from U2F to WebAuthn
2
+
3
+ The Chromium team [recommends](https://groups.google.com/a/chromium.org/forum/#!msg/security-dev/BGWA1d7a6rI/W2avestmBAAJ)
4
+ application developers to switch from the U2F API to the WebAuthn API. This document describes how a Ruby application
5
+ using the [u2f gem by Castle](https://github.com/castle/ruby-u2f) can migrate existing credentials so that their users
6
+ do not experience interruption or need to re-register their security keys.
7
+
8
+ Note that the migration is one-way: credentials registered using WebAuthn cannot be made compatible with the U2F API.
9
+ It is recommended to successfully migrate authorization flows before migrating registration flows.
10
+
11
+ ## Migrate registered U2F credentials
12
+
13
+ Assuming you have a registered credential per the u2f gem readme, base64 urlsafe encoded in a database:
14
+
15
+ ```ruby
16
+ # This domain will be used in all code examples. It's a single-facet app but a multi-facet AppID
17
+ # (e.g. https://example.com/app-id.json) will work as well.
18
+ domain = URI("https://login.example.com")
19
+
20
+ u2f_registration = U2F::U2F.new(domain.to_s).register!(u2f_challenge, u2f_register_response)
21
+ # => #<U2F::Registration:0x00007fd62f43d688
22
+ # @certificate=
23
+ # "MIIBCzCBsgIBATAKBggqhkjOPQQDAjASMRAwDgYDVQQDDAdVMkZUZXN0MB4XDTE5MDUzMDE3MjIwM1oXDTIwMDUyOTE3MjIwM1owEjEQMA4GA1UEAwwHVTJGVGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBMKpejumzlH6NxWIx2Ol+EManS9oX5nguG4RT43rZNkyn/zGjdJEhXksN5zT34rLZgFheBgkDGJCdtTPlhVK10wCgYIKoZIzj0EAwIDSAAwRQIhALYxFcROCeifWpv5+wNZIiaO/bGQg8rFBHCw3aHgehdZAiBJ3xFmQh7+Gjxt6CeAcY/k/VVAYu2vP4sUqXnCQFgJUA==",
24
+ # @key_handle="mbVMRTgzST5xLumckGztJ9VFW6veObfNIYWSn3sTqIY",
25
+ # @public_key="BOJQXlFg+ZfZKm48FNq2Ye5vSwOscE1i7YsGRSIjIe3GI0OXrSBDADDn0dQlz2iDzZ7LvCwiHz72U1qhVas3vus=">
26
+ ```
27
+
28
+ The `U2fMigrator` class quacks like `WebAuthn::AuthenticatorAttestationResponse` and can be used similarly as documented
29
+ in the [registration verification phase](https://github.com/cedarcode/webauthn-ruby/blob/master/README.md#verification-phase).
30
+ Of course a `verify` instance method is not implemented, as there is no real interaction with an authenticator.
31
+
32
+ The migrator can be used to convert credentials in real time during authentication while keeping them stored in the U2F
33
+ format, and in a backfill task to store credentials in the new format, depending on how you are approaching your
34
+ migration.
35
+
36
+ ```ruby
37
+ require "webauthn/u2f_migrator"
38
+
39
+ migrated_credential = WebAuthn::U2fMigrator.new(
40
+ app_id: domain,
41
+ certificate: u2f_registration.certificate,
42
+ key_handle: u2f_registration.key_handle,
43
+ public_key: u2f_registration.public_key,
44
+ counter: u2f_registration.counter
45
+ )
46
+ migrated_credential.credential.id
47
+ # => "\x99\xB5LE83I>q.\xE9\x9C\x90l\xED'\xD5E[\xAB\xDE9\xB7\xCD!\x85\x92\x9F{\x13\xA8\x86"
48
+ migrated_credential.credential.public_key
49
+ # => "\xA5\x03& \x01!X \xE2P^Q`\xF9\x97\xD9*n<\x14\xDA\xB6a\xEEoK\x03\xACpMb\xED\x8B\x06E\"#!\xED\xC6\x01\x02\"X #C\x97\xAD C\x000\xE7\xD1\xD4%\xCFh\x83\xCD\x9E\xCB\xBC,\"\x1F>\xF6SZ\xA1U\xAB7\xBE\xEB"
50
+ migrated_credential.authenticator_data.sign_count
51
+ # => 41
52
+ ```
53
+
54
+ ## Authenticate migrated U2F credentials
55
+
56
+ Following the documentation on the [authentication initiation](https://github.com/cedarcode/webauthn-ruby/blob/master/README.md#authentication),
57
+ you need to specify the [FIDO AppID extension](https://www.w3.org/TR/webauthn/#sctn-appid-extension) for U2F migratedq
58
+ credentials. The WebAuthn standard explains:
59
+
60
+ > The FIDO APIs use an alternative identifier for Relying Parties called an _AppID_, and any credentials created using
61
+ > those APIs will be scoped to that identifier. Without this extension, they would need to be re-registered in order to
62
+ > be scoped to an RP ID.
63
+
64
+ For the earlier given example `domain` this means:
65
+ - FIDO AppID: `https://login.example.com`
66
+ - Valid RP IDs: `login.example.com` (default) and `example.com`
67
+
68
+ ```ruby
69
+ credential_request_options = WebAuthn.credential_request_options
70
+ credential_request_options[:extensions] = { appid: domain.to_s }
71
+ ```
72
+
73
+ On the frontend, in the resolved value from `navigator.credentials.get({ "publicKey": credentialRequestOptions })` add
74
+ a call to [getClientExtensionResults()](https://www.w3.org/TR/webauthn/#dom-publickeycredential-getclientextensionresults)
75
+ and send its result to your backend alongside the `id`/`rawId` and `response` values. If the authenticator used the AppID
76
+ extension, the returned value will contain `{ "appid": true }`. In the example below, we use `clientExtensionResults`.
77
+
78
+ During authentication verification phase, you must pass either the original AppID or the RP ID as the `rp_id` argument:
79
+
80
+ > If true, the AppID was used and thus, when verifying an assertion, the Relying Party MUST expect the `rpIdHash` to be
81
+ > the hash of the _AppID_, not the RP ID.
82
+
83
+ ```ruby
84
+ assertion_response = WebAuthn::AuthenticatorAssertionResponse.new(
85
+ credential_id: params[:id],
86
+ authenticator_data: params[:response][:authenticatorData],
87
+ client_data_json: params[:response][:clientDataJSON],
88
+ signature: params[:response][:signature],
89
+ )
90
+
91
+ assertion_response.verify(
92
+ expected_challenge,
93
+ allowed_credentials: [credential],
94
+ rp_id: params[:clientExtensionResults][:appid] ? domain.to_s : domain.host,
95
+ )
96
+ ```
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "webauthn/authenticator_attestation_response"
4
- require "webauthn/authenticator_assertion_response"
5
3
  require "webauthn/configuration"
6
4
  require "webauthn/credential_creation_options"
7
5
  require "webauthn/credential_request_options"
@@ -6,7 +6,7 @@ require "webauthn/attestation_statement/base"
6
6
 
7
7
  module WebAuthn
8
8
  module AttestationStatement
9
- # Implements https://www.w3.org/TR/2018/CR-webauthn-20180807/#android-safetynet-attestation
9
+ # Implements https://www.w3.org/TR/webauthn-1/#sctn-android-safetynet-attestation
10
10
  class AndroidSafetynet < Base
11
11
  def self.default_trust_store
12
12
  OpenSSL::X509::Store.new.tap { |trust_store| trust_store.set_default_paths }
@@ -22,11 +22,9 @@ module WebAuthn
22
22
 
23
23
  private
24
24
 
25
+ # FIXME: This should be a responsibility of AndroidSafetynet::AttestationResponse#verify
25
26
  def trusted_attestation_certificate?(trust_store)
26
- signing_certificates.each do |certificate|
27
- trust_store.add_cert(certificate)
28
- end
29
- trust_store.verify(attestation_certificate)
27
+ trust_store.verify(attestation_certificate, signing_certificates)
30
28
  end
31
29
 
32
30
  def valid_response?(authenticator_data, client_data_hash)
@@ -16,7 +16,7 @@ module WebAuthn
16
16
  valid_format? &&
17
17
  valid_certificate_public_key? &&
18
18
  valid_credential_public_key?(authenticator_data.credential.public_key) &&
19
- valid_aaguid?(authenticator_data.attested_credential_data.aaguid) &&
19
+ valid_aaguid?(authenticator_data.attested_credential_data.raw_aaguid) &&
20
20
  valid_signature?(authenticator_data, client_data_hash) &&
21
21
  [WebAuthn::AttestationStatement::ATTESTATION_TYPE_BASIC_OR_ATTCA, [attestation_certificate]]
22
22
  end
@@ -18,7 +18,7 @@ module WebAuthn
18
18
  valid_certificate_chain? &&
19
19
  valid_ec_public_keys?(authenticator_data.credential) &&
20
20
  meet_certificate_requirement? &&
21
- matching_aaguid?(authenticator_data.attested_credential_data.aaguid) &&
21
+ matching_aaguid?(authenticator_data.attested_credential_data.raw_aaguid) &&
22
22
  valid_signature?(authenticator_data, client_data_hash) &&
23
23
  attestation_type_and_trust_path
24
24
  end
@@ -25,7 +25,7 @@ module WebAuthn
25
25
  valid_attestation_certificate? &&
26
26
  pub_area.valid?(authenticator_data.credential.public_key) &&
27
27
  cert_info.valid?(statement["pubArea"], OpenSSL::Digest.digest(cose_algorithm.hash, att_to_be_signed)) &&
28
- matching_aaguid?(authenticator_data.attested_credential_data.aaguid) &&
28
+ matching_aaguid?(authenticator_data.attested_credential_data.raw_aaguid) &&
29
29
  [attestation_type, attestation_trust_path]
30
30
  when ATTESTATION_TYPE_ECDAA
31
31
  raise(
@@ -13,12 +13,16 @@ module WebAuthn
13
13
  class SignCountVerificationError < VerificationError; end
14
14
 
15
15
  class AuthenticatorAssertionResponse < AuthenticatorResponse
16
- def initialize(credential_id:, authenticator_data:, signature:, **options)
16
+ attr_reader :user_handle
17
+
18
+ # FIXME: credential_id doesn't belong inside AuthenticatorAssertionResponse
19
+ def initialize(credential_id:, authenticator_data:, signature:, user_handle: nil, **options)
17
20
  super(options)
18
21
 
19
22
  @credential_id = credential_id
20
23
  @authenticator_data_bytes = authenticator_data
21
24
  @signature = signature
25
+ @user_handle = user_handle
22
26
  end
23
27
 
24
28
  def verify(expected_challenge, expected_origin = nil, allowed_credentials:, user_verification: nil, rp_id: nil)
@@ -11,6 +11,7 @@ require "webauthn/client_data"
11
11
 
12
12
  module WebAuthn
13
13
  class AttestationStatementVerificationError < VerificationError; end
14
+ class AttestedCredentialVerificationError < VerificationError; end
14
15
 
15
16
  class AuthenticatorAttestationResponse < AuthenticatorResponse
16
17
  attr_reader :attestation_type, :attestation_trust_path
@@ -24,7 +25,8 @@ module WebAuthn
24
25
  def verify(expected_challenge, expected_origin = nil, user_verification: nil, rp_id: nil)
25
26
  super
26
27
 
27
- verify_item(:attestation_statement)
28
+ verify_item(:attested_credential)
29
+ verify_item(:attestation_statement) if WebAuthn.configuration.verify_attestation_statement
28
30
 
29
31
  true
30
32
  end
@@ -58,6 +60,11 @@ module WebAuthn
58
60
  WebAuthn::TYPES[:create]
59
61
  end
60
62
 
63
+ def valid_attested_credential?
64
+ authenticator_data.attested_credential_data_included? &&
65
+ authenticator_data.attested_credential_data.valid?
66
+ end
67
+
61
68
  def valid_attestation_statement?
62
69
  @attestation_type, @attestation_trust_path = attestation_statement.valid?(authenticator_data, client_data.hash)
63
70
  end
@@ -26,10 +26,14 @@ module WebAuthn
26
26
  data.length >= AAGUID_LENGTH + ID_LENGTH_LENGTH && valid_credential_public_key?
27
27
  end
28
28
 
29
- def aaguid
29
+ def raw_aaguid
30
30
  data_at(0, AAGUID_LENGTH)
31
31
  end
32
32
 
33
+ def aaguid
34
+ raw_aaguid.unpack("H8H4H4H4H12").join("-")
35
+ end
36
+
33
37
  def credential
34
38
  @credential ||=
35
39
  if id
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "openssl"
4
+
3
5
  module WebAuthn
4
6
  def self.configuration
5
7
  @configuration ||= Configuration.new
@@ -20,9 +22,13 @@ module WebAuthn
20
22
  attr_accessor :origin
21
23
  attr_accessor :rp_id
22
24
  attr_accessor :rp_name
25
+ attr_accessor :verify_attestation_statement
26
+ attr_accessor :credential_options_timeout
23
27
 
24
28
  def initialize
25
29
  @algorithms = DEFAULT_ALGORITHMS.dup
30
+ @verify_attestation_statement = true
31
+ @credential_options_timeout = 120000
26
32
  end
27
33
  end
28
34
  end
@@ -42,6 +42,7 @@ module WebAuthn
42
42
  options = {
43
43
  challenge: challenge,
44
44
  pubKeyCredParams: pub_key_cred_params,
45
+ timeout: timeout,
45
46
  user: { id: user.id, name: user.name, displayName: user.display_name },
46
47
  rp: { name: rp.name }
47
48
  }
@@ -9,5 +9,9 @@ module WebAuthn
9
9
  def challenge
10
10
  @challenge ||= SecureRandom.random_bytes(CHALLENGE_LENGTH)
11
11
  end
12
+
13
+ def timeout
14
+ @timeout = WebAuthn.configuration.credential_options_timeout
15
+ end
12
16
  end
13
17
  end
@@ -17,7 +17,11 @@ module WebAuthn
17
17
  end
18
18
 
19
19
  def to_h
20
- options = { challenge: challenge, allowCredentials: allow_credentials }
20
+ options = {
21
+ challenge: challenge,
22
+ timeout: timeout,
23
+ allowCredentials: allow_credentials
24
+ }
21
25
 
22
26
  if extensions
23
27
  options[:extensions] = extensions
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+
5
+ module WebAuthn
6
+ class Encoder
7
+ attr_reader :encoding
8
+
9
+ def initialize(encoding = :base64)
10
+ @encoding = encoding
11
+ end
12
+
13
+ def encode(data)
14
+ case encoding
15
+ when :base64
16
+ Base64.strict_encode64(data)
17
+ when :base64url
18
+ Base64.urlsafe_encode64(data, padding: false)
19
+ when nil, false
20
+ data
21
+ else
22
+ raise "Unsupported or unknown encoding: #{encoding}"
23
+ end
24
+ end
25
+
26
+ def decode(data)
27
+ case encoding
28
+ when :base64
29
+ Base64.strict_decode64(data)
30
+ when :base64url
31
+ Base64.urlsafe_decode64(data)
32
+ when nil, false
33
+ data
34
+ else
35
+ raise "Unsupported or unknown encoding: #{encoding}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -12,22 +12,33 @@ module WebAuthn
12
12
  @credentials = {}
13
13
  end
14
14
 
15
- def make_credential(rp_id:, client_data_hash:, user_present: true, user_verified: false)
16
- credential_id, credential_key = new_credential
15
+ def make_credential(
16
+ rp_id:,
17
+ client_data_hash:,
18
+ user_present: true,
19
+ user_verified: false,
20
+ attested_credential_data: true,
21
+ sign_count: nil
22
+ )
23
+ credential_id, credential_key, credential_sign_count = new_credential
24
+ sign_count ||= credential_sign_count
17
25
 
18
- attestation_object = AttestationObject.new(
26
+ credentials[rp_id] ||= {}
27
+ credentials[rp_id][credential_id] = {
28
+ credential_key: credential_key,
29
+ sign_count: sign_count + 1
30
+ }
31
+
32
+ AttestationObject.new(
19
33
  client_data_hash: client_data_hash,
20
34
  rp_id_hash: hashed(rp_id),
21
35
  credential_id: credential_id,
22
36
  credential_key: credential_key,
23
37
  user_present: user_present,
24
- user_verified: user_verified
38
+ user_verified: user_verified,
39
+ attested_credential_data: attested_credential_data,
40
+ sign_count: sign_count
25
41
  ).serialize
26
-
27
- credentials[rp_id] ||= {}
28
- credentials[rp_id][credential_id] = credential_key
29
-
30
- attestation_object
31
42
  end
32
43
 
33
44
  def get_assertion(
@@ -36,22 +47,25 @@ module WebAuthn
36
47
  user_present: true,
37
48
  user_verified: false,
38
49
  aaguid: AuthenticatorData::AAGUID,
39
- sign_count: 0
50
+ sign_count: nil
40
51
  )
41
52
  credential_options = credentials[rp_id]
42
53
 
43
54
  if credential_options
44
- credential_id, credential_key = credential_options.first
55
+ credential_id, credential = credential_options.first
56
+ credential_key = credential[:credential_key]
57
+ credential_sign_count = credential[:sign_count]
45
58
 
46
59
  authenticator_data = AuthenticatorData.new(
47
60
  rp_id_hash: hashed(rp_id),
48
61
  user_present: user_present,
49
62
  user_verified: user_verified,
50
63
  aaguid: aaguid,
51
- sign_count: sign_count,
64
+ sign_count: sign_count || credential_sign_count,
52
65
  ).serialize
53
66
 
54
67
  signature = credential_key.sign("SHA256", authenticator_data + client_data_hash)
68
+ credential[:sign_count] += 1
55
69
 
56
70
  {
57
71
  credential_id: credential_id,
@@ -68,7 +82,7 @@ module WebAuthn
68
82
  attr_reader :credentials
69
83
 
70
84
  def new_credential
71
- [SecureRandom.random_bytes(16), OpenSSL::PKey::EC.new("prime256v1").generate_key]
85
+ [SecureRandom.random_bytes(16), OpenSSL::PKey::EC.new("prime256v1").generate_key, 0]
72
86
  end
73
87
 
74
88
  def hashed(target)
@@ -12,7 +12,9 @@ module WebAuthn
12
12
  credential_id:,
13
13
  credential_key:,
14
14
  user_present: true,
15
- user_verified: false
15
+ user_verified: false,
16
+ attested_credential_data: true,
17
+ sign_count: 0
16
18
  )
17
19
  @client_data_hash = client_data_hash
18
20
  @rp_id_hash = rp_id_hash
@@ -20,6 +22,8 @@ module WebAuthn
20
22
  @credential_key = credential_key
21
23
  @user_present = user_present
22
24
  @user_verified = user_verified
25
+ @attested_credential_data = attested_credential_data
26
+ @sign_count = sign_count
23
27
  end
24
28
 
25
29
  def serialize
@@ -32,15 +36,33 @@ module WebAuthn
32
36
 
33
37
  private
34
38
 
35
- attr_reader :client_data_hash, :rp_id_hash, :credential_id, :credential_key, :user_present, :user_verified
39
+ attr_reader(
40
+ :client_data_hash,
41
+ :rp_id_hash,
42
+ :credential_id,
43
+ :credential_key,
44
+ :user_present,
45
+ :user_verified,
46
+ :attested_credential_data,
47
+ :sign_count
48
+ )
36
49
 
37
50
  def authenticator_data
38
- @authenticator_data ||= AuthenticatorData.new(
39
- rp_id_hash: rp_id_hash,
40
- credential: { id: credential_id, public_key: credential_key.public_key },
41
- user_present: user_present,
42
- user_verified: user_verified
43
- )
51
+ @authenticator_data ||=
52
+ begin
53
+ credential_data =
54
+ if attested_credential_data
55
+ { id: credential_id, public_key: credential_key.public_key }
56
+ end
57
+
58
+ AuthenticatorData.new(
59
+ rp_id_hash: rp_id_hash,
60
+ credential: credential_data,
61
+ user_present: user_present,
62
+ user_verified: user_verified,
63
+ sign_count: 0
64
+ )
65
+ end
44
66
  end
45
67
  end
46
68
  end
@@ -9,6 +9,8 @@ module WebAuthn
9
9
  class AuthenticatorData
10
10
  AAGUID = SecureRandom.random_bytes(16)
11
11
 
12
+ attr_reader :sign_count
13
+
12
14
  def initialize(
13
15
  rp_id_hash:,
14
16
  credential: {
@@ -36,7 +38,7 @@ module WebAuthn
36
38
 
37
39
  private
38
40
 
39
- attr_reader :rp_id_hash, :credential, :sign_count, :user_present, :user_verified, :extensions
41
+ attr_reader :rp_id_hash, :credential, :user_present, :user_verified, :extensions
40
42
 
41
43
  def flags
42
44
  [
@@ -3,6 +3,7 @@
3
3
  require "base64"
4
4
  require "openssl"
5
5
  require "webauthn/authenticator_data"
6
+ require "webauthn/encoder"
6
7
  require "webauthn/fake_authenticator"
7
8
 
8
9
  module WebAuthn
@@ -11,13 +12,24 @@ module WebAuthn
11
12
 
12
13
  attr_reader :origin, :token_binding
13
14
 
14
- def initialize(origin = fake_origin, token_binding: nil, authenticator: WebAuthn::FakeAuthenticator.new)
15
+ def initialize(
16
+ origin = fake_origin,
17
+ token_binding: nil,
18
+ authenticator: WebAuthn::FakeAuthenticator.new,
19
+ encoding: nil
20
+ )
15
21
  @origin = origin
16
22
  @token_binding = token_binding
17
23
  @authenticator = authenticator
24
+ @encoding = encoding
18
25
  end
19
26
 
20
- def create(challenge: fake_challenge, rp_id: nil, user_present: true, user_verified: false)
27
+ def create(
28
+ challenge: fake_challenge,
29
+ rp_id: nil, user_present: true,
30
+ user_verified: false,
31
+ attested_credential_data: true
32
+ )
21
33
  rp_id ||= URI.parse(origin).host
22
34
 
23
35
  client_data_json = data_json_for(:create, challenge)
@@ -27,21 +39,30 @@ module WebAuthn
27
39
  rp_id: rp_id,
28
40
  client_data_hash: client_data_hash,
29
41
  user_present: user_present,
30
- user_verified: user_verified
42
+ user_verified: user_verified,
43
+ attested_credential_data: attested_credential_data
31
44
  )
32
45
 
33
- id = WebAuthn::AuthenticatorData.new(CBOR.decode(attestation_object)["authData"]).credential.id
46
+ id =
47
+ if attested_credential_data
48
+ WebAuthn::AuthenticatorData.new(CBOR.decode(attestation_object)["authData"]).credential.id
49
+ else
50
+ "id-for-pk-without-attested-credential-data"
51
+ end
34
52
 
53
+ # TODO: return camelCase string keys instead of snakecase symbols
35
54
  {
36
- id: id,
55
+ type: "public-key",
56
+ id: Base64.urlsafe_encode64(id),
57
+ raw_id: encoder.encode(id),
37
58
  response: {
38
- attestation_object: attestation_object,
39
- client_data_json: client_data_json
59
+ attestation_object: encoder.encode(attestation_object),
60
+ client_data_json: encoder.encode(client_data_json)
40
61
  }
41
62
  }
42
63
  end
43
64
 
44
- def get(challenge: fake_challenge, rp_id: nil, user_present: true, user_verified: false, sign_count: 0)
65
+ def get(challenge: fake_challenge, rp_id: nil, user_present: true, user_verified: false, sign_count: nil)
45
66
  rp_id ||= URI.parse(origin).host
46
67
 
47
68
  client_data_json = data_json_for(:get, challenge)
@@ -55,24 +76,27 @@ module WebAuthn
55
76
  sign_count: sign_count,
56
77
  )
57
78
 
79
+ # TODO: return camelCase string keys instead of snakecase symbols
58
80
  {
59
- id: assertion[:credential_id],
81
+ type: "public-key",
82
+ id: Base64.urlsafe_encode64(assertion[:credential_id]),
83
+ raw_id: encoder.encode(assertion[:credential_id]),
60
84
  response: {
61
- client_data_json: client_data_json,
62
- authenticator_data: assertion[:authenticator_data],
63
- signature: assertion[:signature]
85
+ client_data_json: encoder.encode(client_data_json),
86
+ authenticator_data: encoder.encode(assertion[:authenticator_data]),
87
+ signature: encoder.encode(assertion[:signature])
64
88
  }
65
89
  }
66
90
  end
67
91
 
68
92
  private
69
93
 
70
- attr_reader :authenticator
94
+ attr_reader :authenticator, :encoding
71
95
 
72
96
  def data_json_for(method, challenge)
73
97
  data = {
74
98
  type: type_for(method),
75
- challenge: encode(challenge),
99
+ challenge: Base64.urlsafe_encode64(challenge, padding: false),
76
100
  origin: origin
77
101
  }
78
102
 
@@ -83,8 +107,8 @@ module WebAuthn
83
107
  data.to_json
84
108
  end
85
109
 
86
- def encode(data)
87
- Base64.urlsafe_encode64(data, padding: false)
110
+ def encoder
111
+ @encoder ||= WebAuthn::Encoder.new(encoding)
88
112
  end
89
113
 
90
114
  def hashed(data)
@@ -96,7 +120,7 @@ module WebAuthn
96
120
  end
97
121
 
98
122
  def fake_origin
99
- "http://localhost#{rand(1000)}"
123
+ "http://localhost#{rand(1000)}.test"
100
124
  end
101
125
 
102
126
  def type_for(method)
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "base64"
4
+ require "webauthn/authenticator_assertion_response"
5
+ require "webauthn/authenticator_attestation_response"
6
+ require "webauthn/encoder"
4
7
 
5
8
  module WebAuthn
6
9
  class PublicKeyCredential
@@ -8,6 +11,43 @@ module WebAuthn
8
11
 
9
12
  attr_reader :type, :id, :raw_id, :response
10
13
 
14
+ def self.from_create(credential, encoding: :base64)
15
+ encoder = WebAuthn::Encoder.new(encoding)
16
+
17
+ new(
18
+ type: credential["type"],
19
+ id: credential["id"],
20
+ raw_id: encoder.decode(credential["rawId"]),
21
+ response: WebAuthn::AuthenticatorAttestationResponse.new(
22
+ attestation_object: encoder.decode(credential["response"]["attestationObject"]),
23
+ client_data_json: encoder.decode(credential["response"]["clientDataJSON"])
24
+ )
25
+ )
26
+ end
27
+
28
+ def self.from_get(credential, encoding: :base64)
29
+ encoder = WebAuthn::Encoder.new(encoding)
30
+
31
+ user_handle =
32
+ if credential["response"]["userHandle"]
33
+ encoder.decode(credential["response"]["userHandle"])
34
+ end
35
+
36
+ new(
37
+ type: credential["type"],
38
+ id: credential["id"],
39
+ raw_id: encoder.decode(credential["rawId"]),
40
+ response: WebAuthn::AuthenticatorAssertionResponse.new(
41
+ # FIXME: credential_id doesn't belong inside AuthenticatorAssertionResponse
42
+ credential_id: Base64.urlsafe_decode64(credential["id"]),
43
+ authenticator_data: encoder.decode(credential["response"]["authenticatorData"]),
44
+ client_data_json: encoder.decode(credential["response"]["clientDataJSON"]),
45
+ signature: encoder.decode(credential["response"]["signature"]),
46
+ user_handle: user_handle
47
+ )
48
+ )
49
+ end
50
+
11
51
  def initialize(type:, id:, raw_id:, response:)
12
52
  @type = type
13
53
  @id = id
@@ -23,6 +63,20 @@ module WebAuthn
23
63
  true
24
64
  end
25
65
 
66
+ def public_key
67
+ response&.authenticator_data&.credential&.public_key
68
+ end
69
+
70
+ def user_handle
71
+ if response.is_a?(WebAuthn::AuthenticatorAssertionResponse)
72
+ response.user_handle
73
+ end
74
+ end
75
+
76
+ def sign_count
77
+ response&.authenticator_data&.sign_count
78
+ end
79
+
26
80
  private
27
81
 
28
82
  def valid_type?
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'webauthn/fake_client'
4
+ require 'webauthn/attestation_statement/fido_u2f'
5
+
6
+ module WebAuthn
7
+ class U2fMigrator
8
+ def initialize(app_id:, certificate:, key_handle:, public_key:, counter:)
9
+ @app_id = app_id
10
+ @certificate = certificate
11
+ @key_handle = key_handle
12
+ @public_key = public_key
13
+ @counter = counter
14
+ end
15
+
16
+ def authenticator_data
17
+ @authenticator_data ||= WebAuthn::FakeAuthenticator::AuthenticatorData.new(
18
+ rp_id_hash: OpenSSL::Digest::SHA256.digest(@app_id.to_s),
19
+ credential: {
20
+ id: credential_id,
21
+ public_key: credential_cose_key
22
+ },
23
+ sign_count: @counter,
24
+ user_present: true,
25
+ user_verified: false,
26
+ aaguid: WebAuthn::AttestationStatement::FidoU2f::VALID_ATTESTED_AAGUID,
27
+ )
28
+ end
29
+
30
+ def credential
31
+ @credential ||= begin
32
+ hash = authenticator_data.send(:credential)
33
+ WebAuthn::AuthenticatorData::AttestedCredentialData::Credential.new(hash[:id], hash[:public_key].serialize)
34
+ end
35
+ end
36
+
37
+ def attestation_type
38
+ WebAuthn::AttestationStatement::ATTESTATION_TYPE_BASIC_OR_ATTCA
39
+ end
40
+
41
+ def attestation_trust_path
42
+ @attestation_trust_path ||= [OpenSSL::X509::Certificate.new(Base64.strict_decode64(@certificate))]
43
+ end
44
+
45
+ private
46
+
47
+ # https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#u2f-authenticatorMakeCredential-interoperability
48
+ # Let credentialId be a credentialIdLength byte array initialized with CTAP1/U2F response key handle bytes.
49
+ def credential_id
50
+ Base64.urlsafe_decode64(@key_handle)
51
+ end
52
+
53
+ # Let x9encodedUserPublicKey be the user public key returned in the U2F registration response message [U2FRawMsgs].
54
+ # Let coseEncodedCredentialPublicKey be the result of converting x9encodedUserPublicKey’s value from ANS X9.62 /
55
+ # Sec-1 v2 uncompressed curve point representation [SEC1V2] to COSE_Key representation ([RFC8152] Section 7).
56
+ def credential_cose_key
57
+ decoded_public_key = Base64.strict_decode64(@public_key)
58
+ if WebAuthn::AttestationStatement::FidoU2f::PublicKey.uncompressed_point?(decoded_public_key)
59
+ COSE::Key::EC2.new(
60
+ alg: COSE::Algorithm.by_name("ES256").id,
61
+ crv: 1,
62
+ x: decoded_public_key[1..32],
63
+ y: decoded_public_key[33..-1]
64
+ )
65
+ else
66
+ raise "expected U2F public key to be in uncompressed point format"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebAuthn
4
- VERSION = "1.17.0"
4
+ VERSION = "1.18.0"
5
5
  end
Binary file
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = "WebAuthn ruby server library"
14
14
  spec.description = 'WebAuthn ruby server library ― Make your application a W3C Web Authentication conformant
15
- Relying Party and allow your users to authenticate with U2F and FIDO 2.0 authenticators.'
15
+ Relying Party and allow your users to authenticate with U2F and FIDO2 authenticators.'
16
16
  spec.homepage = "https://github.com/cedarcode/webauthn-ruby"
17
17
  spec.license = "MIT"
18
18
 
@@ -43,5 +43,5 @@ Gem::Specification.new do |spec|
43
43
  spec.add_development_dependency "byebug", "~> 11.0"
44
44
  spec.add_development_dependency "rake", "~> 12.3"
45
45
  spec.add_development_dependency "rspec", "~> 3.8"
46
- spec.add_development_dependency "rubocop", "0.71.0"
46
+ spec.add_development_dependency "rubocop", "0.73.0"
47
47
  end
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: 1.17.0
4
+ version: 1.18.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: 2019-06-18 00:00:00.000000000 Z
12
+ date: 2019-07-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bindata
@@ -183,17 +183,17 @@ dependencies:
183
183
  requirements:
184
184
  - - '='
185
185
  - !ruby/object:Gem::Version
186
- version: 0.71.0
186
+ version: 0.73.0
187
187
  type: :development
188
188
  prerelease: false
189
189
  version_requirements: !ruby/object:Gem::Requirement
190
190
  requirements:
191
191
  - - '='
192
192
  - !ruby/object:Gem::Version
193
- version: 0.71.0
193
+ version: 0.73.0
194
194
  description: |-
195
195
  WebAuthn ruby server library ― Make your application a W3C Web Authentication conformant
196
- Relying Party and allow your users to authenticate with U2F and FIDO 2.0 authenticators.
196
+ Relying Party and allow your users to authenticate with U2F and FIDO2 authenticators.
197
197
  email:
198
198
  - gonzalo@cedarcode.com
199
199
  - braulio@cedarcode.com
@@ -207,12 +207,14 @@ files:
207
207
  - ".travis.yml"
208
208
  - Appraisals
209
209
  - CHANGELOG.md
210
+ - CONTRIBUTING.md
210
211
  - Gemfile
211
212
  - LICENSE.txt
212
213
  - README.md
213
214
  - Rakefile
214
215
  - bin/console
215
216
  - bin/setup
217
+ - docs/u2f_migration.md
216
218
  - gemfiles/openssl_2_0.gemfile
217
219
  - gemfiles/openssl_2_1.gemfile
218
220
  - lib/android_safetynet/attestation_response.rb
@@ -251,6 +253,7 @@ files:
251
253
  - lib/webauthn/credential_request_options.rb
252
254
  - lib/webauthn/credential_rp_entity.rb
253
255
  - lib/webauthn/credential_user_entity.rb
256
+ - lib/webauthn/encoder.rb
254
257
  - lib/webauthn/error.rb
255
258
  - lib/webauthn/fake_authenticator.rb
256
259
  - lib/webauthn/fake_authenticator/attestation_object.rb
@@ -259,7 +262,9 @@ files:
259
262
  - lib/webauthn/public_key_credential.rb
260
263
  - lib/webauthn/security_utils.rb
261
264
  - lib/webauthn/signature_verifier.rb
265
+ - lib/webauthn/u2f_migrator.rb
262
266
  - lib/webauthn/version.rb
267
+ - webauthn-ruby.png
263
268
  - webauthn.gemspec
264
269
  homepage: https://github.com/cedarcode/webauthn-ruby
265
270
  licenses: