webauthn 2.1.0 → 2.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +113 -13
  3. data/.travis.yml +21 -18
  4. data/Appraisals +4 -0
  5. data/CHANGELOG.md +41 -0
  6. data/CONTRIBUTING.md +0 -5
  7. data/README.md +70 -8
  8. data/SECURITY.md +6 -4
  9. data/gemfiles/openssl_2_2.gemfile +7 -0
  10. data/lib/cose/rsapkcs1_algorithm.rb +50 -0
  11. data/lib/webauthn/attestation_object.rb +43 -0
  12. data/lib/webauthn/attestation_statement.rb +20 -20
  13. data/lib/webauthn/attestation_statement/android_key.rb +28 -30
  14. data/lib/webauthn/attestation_statement/android_safetynet.rb +27 -7
  15. data/lib/webauthn/attestation_statement/base.rb +108 -10
  16. data/lib/webauthn/attestation_statement/fido_u2f.rb +8 -6
  17. data/lib/webauthn/attestation_statement/none.rb +7 -1
  18. data/lib/webauthn/attestation_statement/packed.rb +13 -41
  19. data/lib/webauthn/attestation_statement/tpm.rb +38 -75
  20. data/lib/webauthn/authenticator_assertion_response.rb +3 -7
  21. data/lib/webauthn/authenticator_attestation_response.rb +19 -84
  22. data/lib/webauthn/authenticator_data.rb +51 -51
  23. data/lib/webauthn/authenticator_data/attested_credential_data.rb +29 -50
  24. data/lib/webauthn/authenticator_response.rb +3 -0
  25. data/lib/webauthn/credential_creation_options.rb +2 -0
  26. data/lib/webauthn/credential_request_options.rb +2 -0
  27. data/lib/webauthn/fake_authenticator.rb +7 -3
  28. data/lib/webauthn/fake_authenticator/attestation_object.rb +7 -3
  29. data/lib/webauthn/fake_authenticator/authenticator_data.rb +2 -4
  30. data/lib/webauthn/fake_client.rb +19 -5
  31. data/lib/webauthn/public_key.rb +21 -2
  32. data/lib/webauthn/public_key_credential.rb +13 -3
  33. data/lib/webauthn/u2f_migrator.rb +5 -4
  34. data/lib/webauthn/version.rb +1 -1
  35. data/script/ci/install-openssl +7 -0
  36. data/script/ci/install-ruby +13 -0
  37. data/webauthn.gemspec +13 -9
  38. metadata +54 -41
  39. data/lib/android_safetynet/attestation_response.rb +0 -116
  40. data/lib/cose/rsassa_algorithm.rb +0 -10
  41. data/lib/tpm/constants.rb +0 -44
  42. data/lib/tpm/s_attest.rb +0 -26
  43. data/lib/tpm/s_attest/s_certify_info.rb +0 -14
  44. data/lib/tpm/sized_buffer.rb +0 -13
  45. data/lib/tpm/t_public.rb +0 -32
  46. data/lib/tpm/t_public/s_ecc_parms.rb +0 -17
  47. data/lib/tpm/t_public/s_rsa_parms.rb +0 -17
  48. data/lib/webauthn/attestation_statement/android_key/authorization_list.rb +0 -39
  49. data/lib/webauthn/attestation_statement/android_key/key_description.rb +0 -37
  50. data/lib/webauthn/attestation_statement/tpm/cert_info.rb +0 -44
  51. data/lib/webauthn/attestation_statement/tpm/pub_area.rb +0 -85
  52. data/lib/webauthn/signature_verifier.rb +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78367d9a528b780d4e53a29667fe47cf95d03698c976714fc7d71d46b253f4fa
4
- data.tar.gz: ab4e9b0ef6a0bfcb9bd2c33d8220e0f3241f2ba949c57053d52968b6e34a5a61
3
+ metadata.gz: e1ffc928d4b54cc4c19c946a30e3e0d1e6a56b317d9d82376bb7f7f9693ee88a
4
+ data.tar.gz: fe42ab966c5ec4ef20089f147276ba485496b8bcf284c1a16a05606c217a434a
5
5
  SHA512:
6
- metadata.gz: f9a3514276b45c34c5509e7d55a6238d8a705ab19534a5ca3a802be4a00f42784b81c3dbc02f3c991918bb61da55b6f20c268a0573b8099224d9467d13932a60
7
- data.tar.gz: e337a703e30a984b881d589f5c31a653e312a9ae4395cf2c411408e0f162871622c7f3d212412ea01de4db121a1ddf2431000ae55968358062f513b5feef812c
6
+ metadata.gz: bd77e2c99e1a08f63dc1986edef737e64872f48108e5e664c8517c7bea11e22a9b4c2bf6e07f7d370d09c3ba3ba3264dff309fd792a47c239d359b27bdd070db
7
+ data.tar.gz: 36a50f38e8c7dac6e33e0494d9ebeac33587ace21d4cad022be1984bd7f915112ba99c6fb975186e63d2757156c09014538a8cfda55db8edeac5ef0327c42bc0
data/.rubocop.yml CHANGED
@@ -1,12 +1,16 @@
1
+ require:
2
+ - rubocop-rspec
3
+
1
4
  inherit_mode:
2
5
  merge:
3
6
  - AllowedNames
4
7
 
5
8
  AllCops:
6
- TargetRubyVersion: 2.3
9
+ TargetRubyVersion: 2.4
7
10
  DisabledByDefault: true
8
11
  Exclude:
9
12
  - "gemfiles/**/*"
13
+ - "vendor/**/*"
10
14
 
11
15
  Bundler:
12
16
  Enabled: true
@@ -17,18 +21,117 @@ Gemspec:
17
21
  Layout:
18
22
  Enabled: true
19
23
 
20
- Lint:
24
+ Layout/ClassStructure:
25
+ Enabled: true
26
+
27
+ Layout/EmptyLinesAroundAttributeAccessor:
28
+ Enabled: true
29
+
30
+ Layout/FirstMethodArgumentLineBreak:
21
31
  Enabled: true
22
32
 
23
- Metrics/LineLength:
33
+ Layout/LineLength:
24
34
  Max: 120
25
35
  Exclude:
26
36
  - spec/support/seeds.rb
27
37
 
38
+ Layout/MultilineAssignmentLayout:
39
+ Enabled: true
40
+
41
+ Layout/MultilineMethodArgumentLineBreaks:
42
+ Enabled: true
43
+
44
+ Layout/SpaceAroundMethodCallOperator:
45
+ Enabled: true
46
+
47
+ Lint:
48
+ Enabled: true
49
+
50
+ Lint/DeprecatedOpenSSLConstant:
51
+ Enabled: true
52
+
53
+ Lint/MixedRegexpCaptureTypes:
54
+ Enabled: true
55
+
56
+ Lint/RaiseException:
57
+ Enabled: true
58
+
59
+ Lint/StructNewOverride:
60
+ Enabled: true
61
+
62
+ Lint/BinaryOperatorWithIdenticalOperands:
63
+ Enabled: true
64
+
65
+ Lint/DuplicateElsifCondition:
66
+ Enabled: true
67
+
68
+ Lint/DuplicateRescueException:
69
+ Enabled: true
70
+
71
+ Lint/EmptyConditionalBody:
72
+ Enabled: true
73
+
74
+ Lint/FloatComparison:
75
+ Enabled: true
76
+
77
+ Lint/MissingSuper:
78
+ Enabled: true
79
+
80
+ Lint/OutOfRangeRegexpRef:
81
+ Enabled: true
82
+
83
+ Lint/SelfAssignment:
84
+ Enabled: true
85
+
86
+ Lint/TopLevelReturnWithArgument:
87
+ Enabled: true
88
+
89
+ Lint/UnreachableLoop:
90
+ Enabled: true
91
+
28
92
  Naming:
29
93
  Enabled: true
30
94
 
31
- Naming/UncommunicativeMethodParamName:
95
+ RSpec/Be:
96
+ Enabled: true
97
+
98
+ RSpec/BeforeAfterAll:
99
+ Enabled: true
100
+
101
+ RSpec/EmptyExampleGroup:
102
+ Enabled: true
103
+
104
+ RSpec/EmptyLineAfterExample:
105
+ Enabled: true
106
+
107
+ RSpec/EmptyLineAfterExampleGroup:
108
+ Enabled: true
109
+
110
+ RSpec/EmptyLineAfterFinalLet:
111
+ Enabled: true
112
+
113
+ RSpec/EmptyLineAfterHook:
114
+ Enabled: true
115
+
116
+ RSpec/EmptyLineAfterSubject:
117
+ Enabled: true
118
+
119
+ RSpec/HookArgument:
120
+ Enabled: true
121
+
122
+ RSpec/LeadingSubject:
123
+ Enabled: true
124
+
125
+ RSpec/NamedSubject:
126
+ Enabled: true
127
+
128
+ RSpec/ScatteredLet:
129
+ Enabled: true
130
+
131
+ RSpec/ScatteredSetup:
132
+ Enabled: true
133
+
134
+ Naming/MethodParameterName:
32
135
  AllowedNames:
33
136
  - rp
34
137
 
@@ -38,9 +141,6 @@ Security:
38
141
  Style/BlockComments:
39
142
  Enabled: true
40
143
 
41
- Style/BracesAroundHashParameters:
42
- Enabled: true
43
-
44
144
  Style/CaseEquality:
45
145
  Enabled: true
46
146
 
@@ -146,9 +246,15 @@ Style/RedundantException:
146
246
  Style/RedundantFreeze:
147
247
  Enabled: true
148
248
 
249
+ Style/RedundantInterpolation:
250
+ Enabled: true
251
+
149
252
  Style/RedundantParentheses:
150
253
  Enabled: true
151
254
 
255
+ Style/RedundantPercentQ:
256
+ Enabled: true
257
+
152
258
  Style/RedundantReturn:
153
259
  Enabled: true
154
260
 
@@ -182,12 +288,6 @@ Style/TrailingMethodEndStatement:
182
288
  Style/TrivialAccessors:
183
289
  Enabled: true
184
290
 
185
- Style/UnneededInterpolation:
186
- Enabled: true
187
-
188
- Style/UnneededPercentQ:
189
- Enabled: true
190
-
191
291
  Style/UnpackFirst:
192
292
  Enabled: true
193
293
 
data/.travis.yml CHANGED
@@ -1,36 +1,39 @@
1
1
  dist: bionic
2
2
  language: ruby
3
- cache: bundler
4
3
 
5
- rvm:
6
- - ruby-head
7
- - 2.7.0
8
- - 2.6.5
9
- - 2.5.7
10
- - 2.4.9
11
- - 2.3.8
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
12
20
 
13
21
  gemfile:
14
22
  - gemfiles/cose_head.gemfile
15
23
  - gemfiles/openssl_head.gemfile
24
+ - gemfiles/openssl_2_2.gemfile
16
25
  - gemfiles/openssl_2_1.gemfile
17
26
  - gemfiles/openssl_2_0.gemfile
18
27
 
19
28
  matrix:
20
29
  fast_finish: true
21
30
  allow_failures:
22
- - rvm: ruby-head
31
+ - env: LIBSSL=1.1 RB=ruby-head
32
+ - env: LIBSSL=1.0 RB=ruby-head
23
33
  - gemfile: gemfiles/cose_head.gemfile
24
34
  - gemfile: gemfiles/openssl_head.gemfile
25
35
 
26
- addons:
27
- apt:
28
- packages:
29
- - libfaketime
30
-
31
36
  before_install:
37
+ - ./script/ci/install-openssl
38
+ - ./script/ci/install-ruby
32
39
  - gem install bundler -v "~> 2.0"
33
-
34
- before_script:
35
- - export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
36
- - export FAKETIME_NO_CACHE=1
data/Appraisals CHANGED
@@ -8,6 +8,10 @@ appraise "openssl_head" do
8
8
  gem "openssl", git: "https://github.com/ruby/openssl"
9
9
  end
10
10
 
11
+ appraise "openssl_2_2" do
12
+ gem "openssl", "~> 2.2.0"
13
+ end
14
+
11
15
  appraise "openssl_2_1" do
12
16
  gem "openssl", "~> 2.1.0"
13
17
  end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## [v2.4.1] - 2021-02-15
4
+
5
+ ### Fixed
6
+
7
+ - Fix verification of new credential if no attestation provided and 'None' type is not among configured `acceptable_attestation_types`. I.e. reject it instead of letting it go through.
8
+
9
+ ## [v2.4.0] - 2020-09-03
10
+
11
+ ### Added
12
+
13
+ - Support for ES256K credentials
14
+ - `FakeClient#get` accepts `user_handle:` keyword argument ([@lgarron])
15
+
16
+ ## [v2.3.0] - 2020-06-27
17
+
18
+ ### Added
19
+
20
+ - Ability to access extension outputs with `PublicKeyCredential#client_extension_outputs` and `PublicKeyCredential#authenticator_extension_outputs` ([@santiagorodriguez96])
21
+
22
+ ## [v2.2.1] - 2020-06-06
23
+
24
+ ### Fixed
25
+
26
+ - Fixed compatibility with OpenSSL-C (libssl) v1.0.2 ([@santiagorodriguez96])
27
+
28
+ ## [v2.2.0] - 2020-03-14
29
+
30
+ ### Added
31
+
32
+ - Verification step that checks the received credential public key algorithm during registration matches one of the configured algorithms
33
+ - [EXPERIMENTAL] Attestation trustworthiness verification default steps for "tpm", "android-key" and "android-safetynet" ([@bdewater], [@padulafacundo]). Still manual configuration needed for "packed" and "fido-u2f".
34
+
35
+ Note: Expect possible breaking changes for "EXPERIMENTAL" features.
36
+
3
37
  ## [v2.1.0] - 2019-12-30
4
38
 
5
39
  ### Added
@@ -273,6 +307,11 @@ Note: Both additions should help making it compatible with Chrome for Android 70
273
307
  - `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
274
308
  - Works with ruby 2.5
275
309
 
310
+ [v2.4.1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.4.0...v2.4.1/
311
+ [v2.4.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.3.0...v2.4.0/
312
+ [v2.3.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.2.1...v2.3.0/
313
+ [v2.2.1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.2.0...v2.2.1/
314
+ [v2.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.1.0...v2.2.0/
276
315
  [v2.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.0.0...v2.1.0/
277
316
  [v2.0.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.18.0...v2.0.0/
278
317
  [v1.18.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.17.0...v1.18.0/
@@ -304,3 +343,5 @@ Note: Both additions should help making it compatible with Chrome for Android 70
304
343
  [@sorah]: https://github.com/sorah
305
344
  [@ssuttner]: https://github.com/ssuttner
306
345
  [@padulafacundo]: https://github.com/padulafacundo
346
+ [@santiagorodriguez96]: https://github.com/santiagorodriguez96
347
+ [@lgarron]: https://github.com/lgarron
data/CONTRIBUTING.md CHANGED
@@ -14,11 +14,6 @@
14
14
 
15
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
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 `FAKETIME_NO_CACHE=1` option. 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 FAKETIME_NO_CACHE=1 bundle exec rspec
20
- ```
21
-
22
17
  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
18
 
24
19
  ### Styleguide
data/README.md CHANGED
@@ -64,12 +64,12 @@ Known conformant pairs are, for example:
64
64
  - Google Chrome for Android 70+ and Android's Fingerprint-based platform authenticator
65
65
  - Microsoft Edge and Windows 10 platform authenticator
66
66
  - Mozilla Firefox for Desktop and Yubico's Security Key roaming authenticator via USB
67
+ - Safari in iOS 13.3+ and YubiKey 5 NFC via NFC
67
68
 
68
- For a detailed picture about what is conformant and what not, you can refer to:
69
-
70
- - [apowers313/fido2-webauthn-status](https://github.com/apowers313/fido2-webauthn-status)
71
- - [FIDO certified products](https://fidoalliance.org/certification/fido-certified-products)
69
+ For a complete list:
72
70
 
71
+ - User Agents (Clients): [Can I Use: Web Authentication API](https://caniuse.com/#search=webauthn)
72
+ - Authenticators: [FIDO certified products](https://fidoalliance.org/certification/fido-certified-products) (search for Type=Authenticator and Specification=FIDO2)
73
73
 
74
74
  ## Install
75
75
 
@@ -150,7 +150,7 @@ if !user.webauthn_id
150
150
  end
151
151
 
152
152
  options = WebAuthn::Credential.options_for_create(
153
- user: { id: user.webauthn_id, name: user.name }
153
+ user: { id: user.webauthn_id, name: user.name },
154
154
  exclude: user.credentials.map { |c| c.webauthn_id }
155
155
  )
156
156
 
@@ -252,6 +252,54 @@ rescue WebAuthn::Error => e
252
252
  end
253
253
  ```
254
254
 
255
+ ### Extensions
256
+
257
+ > The mechanism for generating public key credentials, as well as requesting and generating Authentication assertions, as defined in Web Authentication API, can be extended to suit particular use cases. Each case is addressed by defining a registration extension and/or an authentication extension.
258
+
259
+ > When creating a public key credential or requesting an authentication assertion, a WebAuthn Relying Party can request the use of a set of extensions. These extensions will be invoked during the requested ceremony if they are supported by the WebAuthn Client and/or the WebAuthn Authenticator. The Relying Party sends the client extension input for each extension in the get() call (for authentication extensions) or create() call (for registration extensions) to the WebAuthn client. [[source](https://www.w3.org/TR/webauthn-2/#sctn-extensions)]
260
+
261
+ Extensions can be requested in the initiation phase in both Credential Registration and Authentication ceremonies by adding the extension parameter when generating the options for create/get:
262
+
263
+ ```ruby
264
+ # Credential Registration
265
+ creation_options = WebAuthn::Credential.options_for_create(
266
+ user: { id: user.webauthn_id, name: user.name },
267
+ exclude: user.credentials.map { |c| c.webauthn_id },
268
+ extensions: { appidExclude: domain.to_s }
269
+ )
270
+
271
+ # OR
272
+
273
+ # Credential Authentication
274
+ options = WebAuthn::Credential.options_for_get(
275
+ allow: user.credentials.map { |c| c.webauthn_id },
276
+ extensions: { appid: domain.to_s }
277
+ )
278
+ ```
279
+
280
+ Consequently, after these `options` are sent to the WebAuthn client:
281
+
282
+ > The WebAuthn client performs client extension processing for each extension that the client supports, and augments the client data as specified by each extension, by including the extension identifier and client extension output values.
283
+
284
+ > For authenticator extensions, as part of the client extension processing, the client also creates the CBOR authenticator extension input value for each extension (often based on the corresponding client extension input value), and passes them to the authenticator in the create() call (for registration extensions) or the get() call (for authentication extensions).
285
+
286
+ > The authenticator, in turn, performs additional processing for the extensions that it supports, and returns the CBOR authenticator extension output for each as specified by the extension. Part of the client extension processing for authenticator extensions is to use the authenticator extension output as an input to creating the client extension output. [[source](https://www.w3.org/TR/webauthn-2/#sctn-extensions)]
287
+
288
+ Finally, you can check the values returned for each extension by calling `client_extension_outputs` and `authenticator_extension_outputs` respectively.
289
+ For example, following the initialization phase for the Credential Authentication ceremony specified in the above example:
290
+
291
+ ```ruby
292
+ webauthn_credential = WebAuthn::Credential.from_get(credential_get_result_hash)
293
+
294
+ webauthn_credential.client_extension_outputs #=> { "appid" => true }
295
+ webauthn_credential.authenticator_extension_outputs #=> nil
296
+ ```
297
+
298
+ A list of all currently defined extensions:
299
+
300
+ - [Last published version](https://www.w3.org/TR/webauthn-2/#sctn-defined-extensions)
301
+ - [Next version (in draft)](https://w3c.github.io/webauthn/#sctn-defined-extensions)
302
+
255
303
  ## API
256
304
 
257
305
  #### `WebAuthn.generate_user_id`
@@ -342,6 +390,22 @@ credential_with_assertion.verify(
342
390
  )
343
391
  ```
344
392
 
393
+ #### `PublicKeyCredential#client_extension_outputs`
394
+
395
+ ```ruby
396
+ credential = WebAuthn::Credential.from_create(params[:publicKeyCredential])
397
+
398
+ credential.client_extension_outputs
399
+ ```
400
+
401
+ #### `PublicKeyCredential#authenticator_extension_outputs`
402
+
403
+ ```ruby
404
+ credential = WebAuthn::Credential.from_create(params[:publicKeyCredential])
405
+
406
+ credential.authenticator_extension_outputs
407
+ ```
408
+
345
409
  ## Attestation
346
410
 
347
411
  ### Attestation Statement Format
@@ -350,9 +414,7 @@ credential_with_assertion.verify(
350
414
  | -------- | :--------: |
351
415
  | packed (self attestation) | Yes |
352
416
  | packed (x5c attestation) | Yes |
353
- | packed (ECDAA attestation) | No |
354
417
  | tpm (x5c attestation) | Yes |
355
- | tpm (ECDAA attestation) | No |
356
418
  | android-key | Yes |
357
419
  | android-safetynet | Yes |
358
420
  | fido-u2f | Yes |
@@ -360,7 +422,7 @@ credential_with_assertion.verify(
360
422
 
361
423
  ### Attestation Types
362
424
 
363
- You can define what trust policy to enforce by setting `acceptable_attestation_types` config to a subset of `['None', 'Self', 'Basic', 'AttCA', 'Basic_or_AttCA']` and `attestation_root_certificates_finders` to an object that responds to `#find` and returns the corresponding root certificate for each registration. The `#find` method will be called passing keyword arguments `attesation_format`, `aaguid` and `attestation_certificate_key_id`.
425
+ You can define what trust policy to enforce by setting `acceptable_attestation_types` config to a subset of `['None', 'Self', 'Basic', 'AttCA', 'Basic_or_AttCA']` and `attestation_root_certificates_finders` to an object that responds to `#find` and returns the corresponding root certificate for each registration. The `#find` method will be called passing keyword arguments `attestation_format`, `aaguid` and `attestation_certificate_key_id`.
364
426
 
365
427
  ## Testing Your Integration
366
428