webauthn 2.2.1 → 2.3.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: 1c61ea0ee6982c86b8413c42097b7ab9518c0b49e8067a89d5380ed76f214a0b
4
- data.tar.gz: 4fe7e8aa42ff3a3894c5bc162575a7f5145c2d1bff6d844c247b434c4ff86854
3
+ metadata.gz: 4094023fc463d77a38548e294121f819e874bfb1c075ca43b1fb38e41cfd53a2
4
+ data.tar.gz: f410f8d7e000822943be953265a32e8f81423908e6aff282486d5afa4ab62eb4
5
5
  SHA512:
6
- metadata.gz: 8ef6c40183c3a7f45ba73e07e96eaa9bac5c05c4a61bb80849cc1ff985b4f139eefe12fcbff0d2988ce22e8c0bc3aa05ba0f41aa5f046b41df1c004ac16b9d8d
7
- data.tar.gz: 36563d824c96cccda9281077197a4f0a98475d536f928aad5882e1e9b83c79c7f6b4b97afbd0abce8a58e3953f5fe74fa29a6d9ce644557761e94410e7158318
6
+ metadata.gz: 23ea57e2264cc45024174e8d7a54bc3d4f373cca916c4453079d5cfccf46caa4dbc5aa4013a54404121274a35e71f97f90a061062a21ca270a8b58d474345fb8
7
+ data.tar.gz: 3b49c5b5b845fdcfc3b0b647a16aeab07ad219210e8e29835d171e387d6bcc4ac5fe08a4f9d2978ee6db1022363d1c2b06fe0a163a8625038aca51e1d274e903
@@ -10,6 +10,7 @@ AllCops:
10
10
  DisabledByDefault: true
11
11
  Exclude:
12
12
  - "gemfiles/**/*"
13
+ - "vendor/**/*"
13
14
 
14
15
  Bundler:
15
16
  Enabled: true
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [v2.3.0] - 2020-06-27
4
+
5
+ ### Added
6
+
7
+ - Ability to access extension outputs with `PublicKeyCredential#client_extension_outputs` and `PublicKeyCredential#authenticator_extension_outputs` ([@santiagorodriguez96])
8
+
3
9
  ## [v2.2.1] - 2020-06-06
4
10
 
5
11
  ### Fixed
@@ -288,6 +294,7 @@ Note: Both additions should help making it compatible with Chrome for Android 70
288
294
  - `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
289
295
  - Works with ruby 2.5
290
296
 
297
+ [v2.3.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.2.1...v2.3.0/
291
298
  [v2.2.1]: https://github.com/cedarcode/webauthn-ruby/compare/v2.2.0...v2.2.1/
292
299
  [v2.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.1.0...v2.2.0/
293
300
  [v2.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v2.0.0...v2.1.0/
data/README.md CHANGED
@@ -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
@@ -3,7 +3,6 @@
3
3
  require "android_key_attestation"
4
4
  require "openssl"
5
5
  require "webauthn/attestation_statement/base"
6
- require "webauthn/signature_verifier"
7
6
 
8
7
  module WebAuthn
9
8
  module AttestationStatement
@@ -21,12 +20,6 @@ module WebAuthn
21
20
 
22
21
  private
23
22
 
24
- def valid_signature?(authenticator_data, client_data_hash)
25
- WebAuthn::SignatureVerifier
26
- .new(algorithm, attestation_certificate.public_key)
27
- .verify(signature, authenticator_data.data + client_data_hash)
28
- end
29
-
30
23
  def matching_public_key?(authenticator_data)
31
24
  attestation_certificate.public_key.to_der == authenticator_data.credential.public_key_object.to_der
32
25
  end
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cose/algorithm"
4
+ require "cose/error"
5
+ require "cose/rsapkcs1_algorithm"
3
6
  require "openssl"
4
7
  require "webauthn/authenticator_data/attested_credential_data"
5
8
  require "webauthn/error"
6
9
 
7
10
  module WebAuthn
8
11
  module AttestationStatement
12
+ class UnsupportedAlgorithm < Error; end
13
+
9
14
  ATTESTATION_TYPE_NONE = "None"
10
15
  ATTESTATION_TYPE_BASIC = "Basic"
11
16
  ATTESTATION_TYPE_SELF = "Self"
@@ -19,8 +24,6 @@ module WebAuthn
19
24
  ].freeze
20
25
 
21
26
  class Base
22
- class NotSupportedError < Error; end
23
-
24
27
  AAGUID_EXTENSION_OID = "1.3.6.1.4.1.45724.1.1.4"
25
28
 
26
29
  def initialize(statement)
@@ -147,6 +150,30 @@ module WebAuthn
147
150
  OpenSSL::ASN1.decode(ext_value.value).value
148
151
  end
149
152
 
153
+ def valid_signature?(authenticator_data, client_data_hash, public_key = attestation_certificate.public_key)
154
+ raise("Incompatible algorithm and key") unless cose_algorithm.compatible_key?(public_key)
155
+
156
+ cose_algorithm.verify(
157
+ public_key,
158
+ signature,
159
+ verification_data(authenticator_data, client_data_hash)
160
+ )
161
+ rescue COSE::Error
162
+ false
163
+ end
164
+
165
+ def verification_data(authenticator_data, client_data_hash)
166
+ authenticator_data.data + client_data_hash
167
+ end
168
+
169
+ def cose_algorithm
170
+ @cose_algorithm ||=
171
+ COSE::Algorithm.find(algorithm).tap do |alg|
172
+ alg && configuration.algorithms.include?(alg.name) ||
173
+ raise(UnsupportedAlgorithm, "Unsupported algorithm #{algorithm}")
174
+ end
175
+ end
176
+
150
177
  def configuration
151
178
  WebAuthn.configuration
152
179
  end
@@ -4,7 +4,6 @@ require "cose"
4
4
  require "openssl"
5
5
  require "webauthn/attestation_statement/base"
6
6
  require "webauthn/attestation_statement/fido_u2f/public_key"
7
- require "webauthn/signature_verifier"
8
7
 
9
8
  module WebAuthn
10
9
  module AttestationStatement
@@ -48,10 +47,8 @@ module WebAuthn
48
47
  attested_credential_data_aaguid == WebAuthn::AuthenticatorData::AttestedCredentialData::ZEROED_AAGUID
49
48
  end
50
49
 
51
- def valid_signature?(authenticator_data, client_data_hash)
52
- WebAuthn::SignatureVerifier
53
- .new(VALID_ATTESTATION_CERTIFICATE_ALGORITHM, certificate_public_key)
54
- .verify(signature, verification_data(authenticator_data, client_data_hash))
50
+ def algorithm
51
+ VALID_ATTESTATION_CERTIFICATE_ALGORITHM.id
55
52
  end
56
53
 
57
54
  def verification_data(authenticator_data, client_data_hash)
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "openssl"
4
4
  require "webauthn/attestation_statement/base"
5
- require "webauthn/signature_verifier"
6
5
 
7
6
  module WebAuthn
8
7
  # Implements https://www.w3.org/TR/2018/CR-webauthn-20180807/#packed-attestation
@@ -53,15 +52,6 @@ module WebAuthn
53
52
  end
54
53
  end
55
54
 
56
- def valid_signature?(authenticator_data, client_data_hash)
57
- signature_verifier = WebAuthn::SignatureVerifier.new(
58
- algorithm,
59
- attestation_certificate&.public_key || authenticator_data.credential.public_key_object
60
- )
61
-
62
- signature_verifier.verify(signature, authenticator_data.data + client_data_hash)
63
- end
64
-
65
55
  def attestation_type
66
56
  if attestation_trust_path
67
57
  WebAuthn::AttestationStatement::ATTESTATION_TYPE_BASIC_OR_ATTCA # FIXME: use metadata if available
@@ -69,6 +59,14 @@ module WebAuthn
69
59
  WebAuthn::AttestationStatement::ATTESTATION_TYPE_SELF
70
60
  end
71
61
  end
62
+
63
+ def valid_signature?(authenticator_data, client_data_hash)
64
+ super(
65
+ authenticator_data,
66
+ client_data_hash,
67
+ attestation_certificate&.public_key || authenticator_data.credential.public_key_object
68
+ )
69
+ end
72
70
  end
73
71
  end
74
72
  end
@@ -4,7 +4,6 @@ require "cose/algorithm"
4
4
  require "openssl"
5
5
  require "tpm/key_attestation"
6
6
  require "webauthn/attestation_statement/base"
7
- require "webauthn/signature_verifier"
8
7
 
9
8
  module WebAuthn
10
9
  module AttestationStatement
@@ -3,7 +3,6 @@
3
3
  require "webauthn/authenticator_data"
4
4
  require "webauthn/authenticator_response"
5
5
  require "webauthn/encoder"
6
- require "webauthn/signature_verifier"
7
6
  require "webauthn/public_key"
8
7
 
9
8
  module WebAuthn
@@ -54,9 +53,7 @@ module WebAuthn
54
53
  attr_reader :authenticator_data_bytes, :signature
55
54
 
56
55
  def valid_signature?(webauthn_public_key)
57
- WebAuthn::SignatureVerifier
58
- .new(webauthn_public_key.alg, webauthn_public_key.pkey)
59
- .verify(signature, authenticator_data_bytes + client_data.hash)
56
+ webauthn_public_key.verify(signature, authenticator_data_bytes + client_data.hash)
60
57
  end
61
58
 
62
59
  def valid_sign_count?(stored_sign_count)
@@ -18,7 +18,8 @@ module WebAuthn
18
18
  user_present: true,
19
19
  user_verified: false,
20
20
  attested_credential_data: true,
21
- sign_count: nil
21
+ sign_count: nil,
22
+ extensions: nil
22
23
  )
23
24
  credential_id, credential_key, credential_sign_count = new_credential
24
25
  sign_count ||= credential_sign_count
@@ -37,7 +38,8 @@ module WebAuthn
37
38
  user_present: user_present,
38
39
  user_verified: user_verified,
39
40
  attested_credential_data: attested_credential_data,
40
- sign_count: sign_count
41
+ sign_count: sign_count,
42
+ extensions: extensions
41
43
  ).serialize
42
44
  end
43
45
 
@@ -47,7 +49,8 @@ module WebAuthn
47
49
  user_present: true,
48
50
  user_verified: false,
49
51
  aaguid: AuthenticatorData::AAGUID,
50
- sign_count: nil
52
+ sign_count: nil,
53
+ extensions: nil
51
54
  )
52
55
  credential_options = credentials[rp_id]
53
56
 
@@ -63,6 +66,7 @@ module WebAuthn
63
66
  aaguid: aaguid,
64
67
  credential: nil,
65
68
  sign_count: sign_count || credential_sign_count,
69
+ extensions: extensions
66
70
  ).serialize
67
71
 
68
72
  signature = credential_key.sign("SHA256", authenticator_data + client_data_hash)
@@ -14,7 +14,8 @@ module WebAuthn
14
14
  user_present: true,
15
15
  user_verified: false,
16
16
  attested_credential_data: true,
17
- sign_count: 0
17
+ sign_count: 0,
18
+ extensions: nil
18
19
  )
19
20
  @client_data_hash = client_data_hash
20
21
  @rp_id_hash = rp_id_hash
@@ -24,6 +25,7 @@ module WebAuthn
24
25
  @user_verified = user_verified
25
26
  @attested_credential_data = attested_credential_data
26
27
  @sign_count = sign_count
28
+ @extensions = extensions
27
29
  end
28
30
 
29
31
  def serialize
@@ -44,7 +46,8 @@ module WebAuthn
44
46
  :user_present,
45
47
  :user_verified,
46
48
  :attested_credential_data,
47
- :sign_count
49
+ :sign_count,
50
+ :extensions
48
51
  )
49
52
 
50
53
  def authenticator_data
@@ -60,7 +63,8 @@ module WebAuthn
60
63
  credential: credential_data,
61
64
  user_present: user_present,
62
65
  user_verified: user_verified,
63
- sign_count: 0
66
+ sign_count: 0,
67
+ extensions: extensions
64
68
  )
65
69
  end
66
70
  end
@@ -29,7 +29,8 @@ module WebAuthn
29
29
  rp_id: nil,
30
30
  user_present: true,
31
31
  user_verified: false,
32
- attested_credential_data: true
32
+ attested_credential_data: true,
33
+ extensions: nil
33
34
  )
34
35
  rp_id ||= URI.parse(origin).host
35
36
 
@@ -41,7 +42,8 @@ module WebAuthn
41
42
  client_data_hash: client_data_hash,
42
43
  user_present: user_present,
43
44
  user_verified: user_verified,
44
- attested_credential_data: attested_credential_data
45
+ attested_credential_data: attested_credential_data,
46
+ extensions: extensions
45
47
  )
46
48
 
47
49
  id =
@@ -58,6 +60,7 @@ module WebAuthn
58
60
  "type" => "public-key",
59
61
  "id" => internal_encoder.encode(id),
60
62
  "rawId" => encoder.encode(id),
63
+ "clientExtensionResults" => extensions,
61
64
  "response" => {
62
65
  "attestationObject" => encoder.encode(attestation_object),
63
66
  "clientDataJSON" => encoder.encode(client_data_json)
@@ -65,7 +68,12 @@ module WebAuthn
65
68
  }
66
69
  end
67
70
 
68
- def get(challenge: fake_challenge, rp_id: nil, user_present: true, user_verified: false, sign_count: nil)
71
+ def get(challenge: fake_challenge,
72
+ rp_id: nil,
73
+ user_present: true,
74
+ user_verified: false,
75
+ sign_count: nil,
76
+ extensions: nil)
69
77
  rp_id ||= URI.parse(origin).host
70
78
 
71
79
  client_data_json = data_json_for(:get, encoder.decode(challenge))
@@ -77,12 +85,14 @@ module WebAuthn
77
85
  user_present: user_present,
78
86
  user_verified: user_verified,
79
87
  sign_count: sign_count,
88
+ extensions: extensions
80
89
  )
81
90
 
82
91
  {
83
92
  "type" => "public-key",
84
93
  "id" => internal_encoder.encode(assertion[:credential_id]),
85
94
  "rawId" => encoder.encode(assertion[:credential_id]),
95
+ "clientExtensionResults" => extensions,
86
96
  "response" => {
87
97
  "clientDataJSON" => encoder.encode(client_data_json),
88
98
  "authenticatorData" => encoder.encode(assertion[:authenticator_data]),
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "webauthn/attestation_statement/fido_u2f/public_key"
4
- require "cose/key"
5
3
  require "cose/algorithm"
4
+ require "cose/error"
5
+ require "cose/key"
6
+ require "cose/rsapkcs1_algorithm"
7
+ require "webauthn/attestation_statement/fido_u2f/public_key"
6
8
 
7
9
  module WebAuthn
8
10
  class PublicKey
11
+ class UnsupportedAlgorithm < Error; end
12
+
9
13
  def self.deserialize(public_key)
10
14
  cose_key =
11
15
  if WebAuthn::AttestationStatement::FidoU2f::PublicKey.uncompressed_point?(public_key)
@@ -45,5 +49,20 @@ module WebAuthn
45
49
  def alg
46
50
  @cose_key.alg
47
51
  end
52
+
53
+ def verify(signature, verification_data)
54
+ cose_algorithm.verify(pkey, signature, verification_data)
55
+ rescue COSE::Error
56
+ false
57
+ end
58
+
59
+ private
60
+
61
+ def cose_algorithm
62
+ @cose_algorithm ||= COSE::Algorithm.find(alg) || raise(
63
+ UnsupportedAlgorithm,
64
+ "The public key algorithm #{alg} is not among the available COSE algorithms"
65
+ )
66
+ end
48
67
  end
49
68
  end
@@ -4,21 +4,23 @@ require "webauthn/encoder"
4
4
 
5
5
  module WebAuthn
6
6
  class PublicKeyCredential
7
- attr_reader :type, :id, :raw_id, :response
7
+ attr_reader :type, :id, :raw_id, :client_extension_outputs, :response
8
8
 
9
9
  def self.from_client(credential)
10
10
  new(
11
11
  type: credential["type"],
12
12
  id: credential["id"],
13
13
  raw_id: WebAuthn.configuration.encoder.decode(credential["rawId"]),
14
+ client_extension_outputs: credential["clientExtensionResults"],
14
15
  response: response_class.from_client(credential["response"])
15
16
  )
16
17
  end
17
18
 
18
- def initialize(type:, id:, raw_id:, response:)
19
+ def initialize(type:, id:, raw_id:, client_extension_outputs: {}, response:)
19
20
  @type = type
20
21
  @id = id
21
22
  @raw_id = raw_id
23
+ @client_extension_outputs = client_extension_outputs
22
24
  @response = response
23
25
  end
24
26
 
@@ -30,7 +32,11 @@ module WebAuthn
30
32
  end
31
33
 
32
34
  def sign_count
33
- response&.authenticator_data&.sign_count
35
+ authenticator_data&.sign_count
36
+ end
37
+
38
+ def authenticator_extension_outputs
39
+ authenticator_data.extension_data if authenticator_data&.extension_data_included?
34
40
  end
35
41
 
36
42
  private
@@ -43,6 +49,10 @@ module WebAuthn
43
49
  raw_id && id && raw_id == WebAuthn.standard_encoder.decode(id)
44
50
  end
45
51
 
52
+ def authenticator_data
53
+ response&.authenticator_data
54
+ end
55
+
46
56
  def encoder
47
57
  WebAuthn.configuration.encoder
48
58
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebAuthn
4
- VERSION = "2.2.1"
4
+ VERSION = "2.3.0"
5
5
  end
@@ -43,7 +43,7 @@ Gem::Specification.new do |spec|
43
43
  spec.add_dependency "securecompare", "~> 1.0"
44
44
  spec.add_dependency "tpm-key_attestation", "~> 0.9.0"
45
45
 
46
- spec.add_development_dependency "appraisal", "~> 2.2.0"
46
+ spec.add_development_dependency "appraisal", "~> 2.3.0"
47
47
  spec.add_development_dependency "bundler", ">= 1.17", "< 3.0"
48
48
  spec.add_development_dependency "byebug", "~> 11.0"
49
49
  spec.add_development_dependency "rake", "~> 13.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webauthn
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.3.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: 2020-06-06 00:00:00.000000000 Z
12
+ date: 2020-06-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: android_key_attestation
@@ -143,14 +143,14 @@ dependencies:
143
143
  requirements:
144
144
  - - "~>"
145
145
  - !ruby/object:Gem::Version
146
- version: 2.2.0
146
+ version: 2.3.0
147
147
  type: :development
148
148
  prerelease: false
149
149
  version_requirements: !ruby/object:Gem::Requirement
150
150
  requirements:
151
151
  - - "~>"
152
152
  - !ruby/object:Gem::Version
153
- version: 2.2.0
153
+ version: 2.3.0
154
154
  - !ruby/object:Gem::Dependency
155
155
  name: bundler
156
156
  requirement: !ruby/object:Gem::Requirement
@@ -314,7 +314,6 @@ files:
314
314
  - lib/webauthn/public_key_credential_with_assertion.rb
315
315
  - lib/webauthn/public_key_credential_with_attestation.rb
316
316
  - lib/webauthn/security_utils.rb
317
- - lib/webauthn/signature_verifier.rb
318
317
  - lib/webauthn/u2f_migrator.rb
319
318
  - lib/webauthn/version.rb
320
319
  - script/ci/install-openssl
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "cose"
4
- require "cose/rsapkcs1_algorithm"
5
- require "openssl"
6
- require "webauthn/error"
7
-
8
- module WebAuthn
9
- class SignatureVerifier
10
- class UnsupportedAlgorithm < Error; end
11
-
12
- def initialize(algorithm, public_key)
13
- @algorithm = algorithm
14
- @public_key = public_key
15
-
16
- validate
17
- end
18
-
19
- def verify(signature, verification_data)
20
- cose_algorithm.verify(public_key, signature, verification_data)
21
- rescue COSE::Error
22
- false
23
- end
24
-
25
- private
26
-
27
- attr_reader :algorithm, :public_key
28
-
29
- def cose_algorithm
30
- case algorithm
31
- when COSE::Algorithm::Base
32
- algorithm
33
- else
34
- COSE::Algorithm.find(algorithm)
35
- end
36
- end
37
-
38
- def validate
39
- if !cose_algorithm
40
- raise UnsupportedAlgorithm, "Unsupported algorithm #{algorithm}"
41
- elsif !supported_algorithms.include?(cose_algorithm.name)
42
- raise UnsupportedAlgorithm, "Unsupported algorithm #{algorithm}"
43
- elsif !cose_algorithm.compatible_key?(public_key)
44
- raise("Incompatible algorithm and key")
45
- end
46
- end
47
-
48
- def supported_algorithms
49
- WebAuthn.configuration.algorithms
50
- end
51
- end
52
- end