webauthn 2.2.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +36 -0
  3. data/.rubocop.yml +60 -0
  4. data/Appraisals +2 -10
  5. data/CHANGELOG.md +53 -0
  6. data/README.md +71 -9
  7. data/SECURITY.md +6 -3
  8. data/gemfiles/{openssl_2_0.gemfile → openssl_2_2.gemfile} +1 -1
  9. data/lib/cose/rsapkcs1_algorithm.rb +11 -0
  10. data/lib/webauthn/attestation_object.rb +2 -2
  11. data/lib/webauthn/attestation_statement.rb +4 -1
  12. data/lib/webauthn/attestation_statement/android_key.rb +0 -11
  13. data/lib/webauthn/attestation_statement/android_safetynet.rb +1 -5
  14. data/lib/webauthn/attestation_statement/apple.rb +65 -0
  15. data/lib/webauthn/attestation_statement/base.rb +36 -14
  16. data/lib/webauthn/attestation_statement/fido_u2f.rb +2 -5
  17. data/lib/webauthn/attestation_statement/none.rb +7 -1
  18. data/lib/webauthn/attestation_statement/packed.rb +10 -23
  19. data/lib/webauthn/attestation_statement/tpm.rb +10 -20
  20. data/lib/webauthn/authenticator_assertion_response.rb +1 -4
  21. data/lib/webauthn/authenticator_attestation_response.rb +2 -2
  22. data/lib/webauthn/configuration.rb +2 -6
  23. data/lib/webauthn/credential_creation_options.rb +2 -0
  24. data/lib/webauthn/credential_request_options.rb +2 -0
  25. data/lib/webauthn/fake_authenticator.rb +16 -4
  26. data/lib/webauthn/fake_authenticator/attestation_object.rb +7 -3
  27. data/lib/webauthn/fake_client.rb +21 -4
  28. data/lib/webauthn/public_key.rb +21 -2
  29. data/lib/webauthn/public_key_credential.rb +13 -3
  30. data/lib/webauthn/public_key_credential/entity.rb +3 -4
  31. data/lib/webauthn/version.rb +1 -1
  32. data/webauthn.gemspec +7 -6
  33. metadata +34 -22
  34. data/.travis.yml +0 -26
  35. data/gemfiles/cose_head.gemfile +0 -7
  36. data/gemfiles/openssl_head.gemfile +0 -7
  37. data/lib/webauthn/signature_verifier.rb +0 -52
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab7bf6dcca17e3cfe29921d5eb1b93202864d397c5e3a923b6626e365b2caf39
4
- data.tar.gz: 5d77612f3ba67243a44a93aab9cf6be9178728f5701fbae52d7a48a0590be356
3
+ metadata.gz: 1e6487b19f172c0c7e96af23d04e47f91bebd2ef7d20f144f99f85e761a2db86
4
+ data.tar.gz: 7623405e7cd01708f29897a0d4183fbc8c9b2a3dfb06b9c182646ddaf9c6cb0d
5
5
  SHA512:
6
- metadata.gz: cd9e2477f0b3e36f440a3bcd16694329abd4aab1e32df5a96441a54493689f9b2287a7bfbcd510ad6132784e18ad494e797964f6403f084c5fafb91c2bc7dd38
7
- data.tar.gz: 04eae0faa11df97e39d9e62f848e1dec2cce409829776ed00de928674e841eb0143c82803d2a32d6f01f429ac402dead7120ee9bc3cc46f45333415a478ed6eb
6
+ metadata.gz: d2f8d2137b2ee140a3258fbbff8d62e49264b2eafa80f0726dacc16a742addf75625b9da51696db6f3862a85e63f44ca5fc2b73320b1c256dd1c57f96121de24
7
+ data.tar.gz: dcb2ea914a14944b4bf7c4682394df12e00ddd4a4b0cc1076a03a7368bf4d563d08b61fbbe27ece3ddcbc05a9ed542d8236c1bfce833669c9b60c5d3387b35b4
@@ -0,0 +1,36 @@
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.0'
20
+ - '2.7'
21
+ - '2.6'
22
+ - '2.5'
23
+ - '2.4'
24
+ - truffleruby
25
+ gemfile:
26
+ - openssl_2_2
27
+ - openssl_2_1
28
+ env:
29
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
30
+ steps:
31
+ - uses: actions/checkout@v2
32
+ - uses: ruby/setup-ruby@v1
33
+ with:
34
+ ruby-version: ${{ matrix.ruby }}
35
+ bundler-cache: true
36
+ - run: bundle exec rake
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,8 +9,10 @@ inherit_mode:
8
9
  AllCops:
9
10
  TargetRubyVersion: 2.4
10
11
  DisabledByDefault: true
12
+ NewCops: disable
11
13
  Exclude:
12
14
  - "gemfiles/**/*"
15
+ - "vendor/**/*"
13
16
 
14
17
  Bundler:
15
18
  Enabled: true
@@ -20,6 +23,15 @@ Gemspec:
20
23
  Layout:
21
24
  Enabled: true
22
25
 
26
+ Layout/ClassStructure:
27
+ Enabled: true
28
+
29
+ Layout/EmptyLineBetweenDefs:
30
+ AllowAdjacentOneLineDefs: true
31
+
32
+ Layout/EmptyLinesAroundAttributeAccessor:
33
+ Enabled: true
34
+
23
35
  Layout/FirstMethodArgumentLineBreak:
24
36
  Enabled: true
25
37
 
@@ -34,12 +46,60 @@ Layout/MultilineAssignmentLayout:
34
46
  Layout/MultilineMethodArgumentLineBreaks:
35
47
  Enabled: true
36
48
 
49
+ Layout/SpaceAroundMethodCallOperator:
50
+ Enabled: true
51
+
37
52
  Lint:
38
53
  Enabled: true
39
54
 
55
+ Lint/DeprecatedOpenSSLConstant:
56
+ Enabled: true
57
+
58
+ Lint/MixedRegexpCaptureTypes:
59
+ Enabled: true
60
+
61
+ Lint/RaiseException:
62
+ Enabled: true
63
+
64
+ Lint/StructNewOverride:
65
+ Enabled: true
66
+
67
+ Lint/BinaryOperatorWithIdenticalOperands:
68
+ Enabled: true
69
+
70
+ Lint/DuplicateElsifCondition:
71
+ Enabled: true
72
+
73
+ Lint/DuplicateRescueException:
74
+ Enabled: true
75
+
76
+ Lint/EmptyConditionalBody:
77
+ Enabled: true
78
+
79
+ Lint/FloatComparison:
80
+ Enabled: true
81
+
82
+ Lint/MissingSuper:
83
+ Enabled: true
84
+
85
+ Lint/OutOfRangeRegexpRef:
86
+ Enabled: true
87
+
88
+ Lint/SelfAssignment:
89
+ Enabled: true
90
+
91
+ Lint/TopLevelReturnWithArgument:
92
+ Enabled: true
93
+
94
+ Lint/UnreachableLoop:
95
+ Enabled: true
96
+
40
97
  Naming:
41
98
  Enabled: true
42
99
 
100
+ Naming/VariableNumber:
101
+ Enabled: false
102
+
43
103
  RSpec/Be:
44
104
  Enabled: true
45
105
 
data/Appraisals CHANGED
@@ -1,17 +1,9 @@
1
1
  # frozen_string_literal: true
2
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"
3
+ appraise "openssl_2_2" do
4
+ gem "openssl", "~> 2.2.0"
9
5
  end
10
6
 
11
7
  appraise "openssl_2_1" do
12
8
  gem "openssl", "~> 2.1.0"
13
9
  end
14
-
15
- appraise "openssl_2_0" do
16
- gem "openssl", "~> 2.0.0"
17
- end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
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.0] - 2021-03-14
10
+
11
+ ### Added
12
+
13
+ - Support 'apple' attestation statement format ([#343](https://github.com/cedarcode/webauthn-ruby/pull/343) / [@juanarias93], [@santiagorodriguez96])
14
+ - Allow specifying an array of ids as `allow_credentials:` for `FakeClient#get` method ([#335](https://github.com/cedarcode/webauthn-ruby/pull/335) / [@kingjan1999])
15
+
16
+ ### Removed
17
+
18
+ - 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])
19
+
20
+ ## [v2.4.1] - 2021-02-15
21
+
22
+ ### Fixed
23
+
24
+ - 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.
25
+
26
+ ## [v2.4.0] - 2020-09-03
27
+
28
+ ### Added
29
+
30
+ - Support for ES256K credentials
31
+ - `FakeClient#get` accepts `user_handle:` keyword argument ([@lgarron])
32
+
33
+ ## [v2.3.0] - 2020-06-27
34
+
35
+ ### Added
36
+
37
+ - Ability to access extension outputs with `PublicKeyCredential#client_extension_outputs` and `PublicKeyCredential#authenticator_extension_outputs` ([@santiagorodriguez96])
38
+
39
+ ## [v2.2.1] - 2020-06-06
40
+
41
+ ### Fixed
42
+
43
+ - Fixed compatibility with OpenSSL-C (libssl) v1.0.2 ([@santiagorodriguez96])
44
+
3
45
  ## [v2.2.0] - 2020-03-14
4
46
 
5
47
  ### Added
@@ -282,6 +324,12 @@ Note: Both additions should help making it compatible with Chrome for Android 70
282
324
  - `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
283
325
  - Works with ruby 2.5
284
326
 
327
+ [v3.0.0.alpha1]: https://github.com/cedarcode/webauthn-ruby/compare/2-stable...v3.0.0.alpha1/
328
+ [v2.5.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.4.1...v2.5.0/
329
+ [v2.4.1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.4.0...v2.4.1/
330
+ [v2.4.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.3.0...v2.4.0/
331
+ [v2.3.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.2.1...v2.3.0/
332
+ [v2.2.1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.2.0...v2.2.1/
285
333
  [v2.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.1.0...v2.2.0/
286
334
  [v2.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.0.0...v2.1.0/
287
335
  [v2.0.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.18.0...v2.0.0/
@@ -307,6 +355,7 @@ Note: Both additions should help making it compatible with Chrome for Android 70
307
355
  [v0.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.1.0...v0.2.0/
308
356
  [v0.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.0.0...v0.1.0/
309
357
 
358
+ [@brauliomartinezlm]: https://github.com/brauliomartinezlm
310
359
  [@bdewater]: https://github.com/bdewater
311
360
  [@jdongelmans]: https://github.com/jdongelmans
312
361
  [@kalebtesfay]: https://github.com/kalebtesfay
@@ -314,3 +363,7 @@ Note: Both additions should help making it compatible with Chrome for Android 70
314
363
  [@sorah]: https://github.com/sorah
315
364
  [@ssuttner]: https://github.com/ssuttner
316
365
  [@padulafacundo]: https://github.com/padulafacundo
366
+ [@santiagorodriguez96]: https://github.com/santiagorodriguez96
367
+ [@lgarron]: https://github.com/lgarron
368
+ [@juanarias93]: https://github.com/juanarias93
369
+ [@kingjan1999]: https://github.com/@kingjan1999
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.org/cedarcode/webauthn-ruby)
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
 
@@ -66,11 +66,10 @@ Known conformant pairs are, for example:
66
66
  - Mozilla Firefox for Desktop and Yubico's Security Key roaming authenticator via USB
67
67
  - Safari in iOS 13.3+ and YubiKey 5 NFC via NFC
68
68
 
69
- For a detailed picture about what is conformant and what not, you can refer to:
70
-
71
- - [apowers313/fido2-webauthn-status](https://github.com/apowers313/fido2-webauthn-status)
72
- - [FIDO certified products](https://fidoalliance.org/certification/fido-certified-products)
69
+ For a complete list:
73
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)
74
73
 
75
74
  ## Install
76
75
 
@@ -151,7 +150,7 @@ if !user.webauthn_id
151
150
  end
152
151
 
153
152
  options = WebAuthn::Credential.options_for_create(
154
- user: { id: user.webauthn_id, name: user.name }
153
+ user: { id: user.webauthn_id, name: user.name },
155
154
  exclude: user.credentials.map { |c| c.webauthn_id }
156
155
  )
157
156
 
@@ -253,6 +252,54 @@ rescue WebAuthn::Error => e
253
252
  end
254
253
  ```
255
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
+
256
303
  ## API
257
304
 
258
305
  #### `WebAuthn.generate_user_id`
@@ -343,19 +390,34 @@ credential_with_assertion.verify(
343
390
  )
344
391
  ```
345
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
+
346
409
  ## Attestation
347
410
 
348
- ### Attestation Statement Format
411
+ ### Attestation Statement Formats
349
412
 
350
413
  | Attestation Statement Format | Supported? |
351
414
  | -------- | :--------: |
352
415
  | packed (self attestation) | Yes |
353
416
  | packed (x5c attestation) | Yes |
354
- | packed (ECDAA attestation) | No |
355
417
  | tpm (x5c attestation) | Yes |
356
- | tpm (ECDAA attestation) | No |
357
418
  | android-key | Yes |
358
419
  | android-safetynet | Yes |
420
+ | apple | Yes |
359
421
  | fido-u2f | Yes |
360
422
  | none | Yes |
361
423
 
data/SECURITY.md CHANGED
@@ -4,9 +4,12 @@
4
4
 
5
5
  | Version | Supported |
6
6
  | ------- | ------------------ |
7
- | 2.2.z | :white_check_mark: |
8
- | 2.1.z | :white_check_mark: |
9
- | 2.0.z | :white_check_mark: |
7
+ | 2.5.z | :white_check_mark: |
8
+ | 2.4.z | :white_check_mark: |
9
+ | 2.3.z | :white_check_mark: |
10
+ | 2.2.z | :x: |
11
+ | 2.1.z | :x: |
12
+ | 2.0.z | :x: |
10
13
  | 1.18.z | :white_check_mark: |
11
14
  | < 1.18 | :x: |
12
15
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "openssl", "~> 2.0.0"
5
+ gem "openssl", "~> 2.2.0"
6
6
 
7
7
  gemspec path: "../"
@@ -21,6 +21,10 @@ class RSAPKCS1Algorithm < COSE::Algorithm::SignatureAlgorithm
21
21
  OpenSSL::SignatureAlgorithm::RSAPKCS1
22
22
  end
23
23
 
24
+ def valid_key?(key)
25
+ to_cose_key(key).is_a?(COSE::Key::RSA)
26
+ end
27
+
24
28
  def to_pkey(key)
25
29
  case key
26
30
  when COSE::Key::RSA
@@ -36,4 +40,11 @@ end
36
40
  COSE::Algorithm.register(RSAPKCS1Algorithm.new(-257, "RS256", hash_function: "SHA256"))
37
41
  COSE::Algorithm.register(RSAPKCS1Algorithm.new(-258, "RS384", hash_function: "SHA384"))
38
42
  COSE::Algorithm.register(RSAPKCS1Algorithm.new(-259, "RS512", hash_function: "SHA512"))
43
+
44
+ # Patch openssl-signature_algorithm gem to support discouraged/deprecated RSA-PKCS#1 with SHA-1
45
+ # (RS1 in JOSE/COSE terminology) algorithm needed for WebAuthn.
46
+ OpenSSL::SignatureAlgorithm::RSAPKCS1.const_set(
47
+ :ACCEPTED_HASH_FUNCTIONS,
48
+ OpenSSL::SignatureAlgorithm::RSAPKCS1::ACCEPTED_HASH_FUNCTIONS + ["SHA1"]
49
+ )
39
50
  COSE::Algorithm.register(RSAPKCS1Algorithm.new(-65535, "RS1", hash_function: "SHA1"))
@@ -8,6 +8,8 @@ require "webauthn/authenticator_data"
8
8
 
9
9
  module WebAuthn
10
10
  class AttestationObject
11
+ extend Forwardable
12
+
11
13
  def self.deserialize(attestation_object)
12
14
  from_map(CBOR.decode(attestation_object))
13
15
  end
@@ -35,8 +37,6 @@ module WebAuthn
35
37
  attestation_statement.valid?(authenticator_data, client_data_hash)
36
38
  end
37
39
 
38
- extend Forwardable
39
-
40
40
  def_delegators :authenticator_data, :credential, :aaguid
41
41
  def_delegators :attestation_statement, :attestation_certificate_key_id
42
42
  end
@@ -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)