webauthn 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0b7730e28517a0a0c8490fe77a7f1826de3914f7af3ccf6aefcc1e5268e4a45
4
- data.tar.gz: 5a9433f01315b4360388d4d08667b041539f5fef43d48034d1deece03d24b48b
3
+ metadata.gz: f9b0ee13d67d762afc44c92d76d99a7a7f3500c31658a0248a6dfb4d986f3f18
4
+ data.tar.gz: 888a0fb232facc8e5d02458bc1c94f926ed4b8541cac4b3937cf7bb4098ed0f4
5
5
  SHA512:
6
- metadata.gz: cbfc86b1a82b1906a1adda4ab47e4cb7a523b520ecb533aa9587e047f463f74eccde0a88bff0ffb3acc037dc163cdbd40bad173c3e35a52492c230432897aeef
7
- data.tar.gz: 887545a11d8d387deb137d228fb2f7a0c13f4462d7ca8b9247b68be7cdb40fcf478ee7b53bb5d39d7f89b6230d8c332676c20c7f5623f272522838f14b5213ef
6
+ metadata.gz: a8f7821dbbc3ce730216ade21b37a23d6c202e1e060b90ed1bfb419c2abeed1ff6867d4ba6730de07d7b0f0eef54306358c894cac95faf90cb09af397f60f49e
7
+ data.tar.gz: ec06219c2f23352fbeec12c6bdf550b5120403c2dbbc249eb577e1eeb90f16ee1425b8ca857cdcdef884d7e2cd385e1d4e5dfb3cc9173aabc511088cf0627760
data/.gitignore CHANGED
@@ -12,4 +12,4 @@
12
12
 
13
13
  /Gemfile.lock
14
14
  /gemfiles/*.gemfile.lock
15
- /.byebug_history
15
+ .byebug_history
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
- --format documentation
1
+ --order rand
2
2
  --color
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.13.0] - 2019-04-09
4
+
5
+ ### Added
6
+
7
+ - Verify 'none' attestation statement is really empty.
8
+ - Verify 'packed' attestation statement certificates start/end dates.
9
+ - Verify 'packed' attestation statement signature algorithm.
10
+ - Verify 'fiod-u2f attestation statement AAGUID is zeroed out. Thank you @bdewater.
11
+ - Verify 'android-key' attestation statement signature algorithm.
12
+ - Verify assertion response signature algorithm.
13
+ - Verify collectedClientData.tokenBinding format.
14
+ - `WebAuthn.credential_creation_options` now accept `rp_name`, `user_id`, `user_name` and `display_name` as keyword arguments. Thank you @bdewater.
15
+
3
16
  ## [v1.12.0] - 2019-04-03
4
17
 
5
18
  ### Added
@@ -153,7 +166,8 @@ Note: Both additions should help making it compatible with Chrome for Android 70
153
166
  - `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
154
167
  - Works with ruby 2.5
155
168
 
156
- [v1.12.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.12.0...v1.12.0/
169
+ [v1.13.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.12.0...v1.13.0/
170
+ [v1.12.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.11.0...v1.12.0/
157
171
  [v1.11.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.10.0...v1.11.0/
158
172
  [v1.10.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.9.0...v1.10.0/
159
173
  [v1.9.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.8.0...v1.9.0/
data/README.md CHANGED
@@ -95,8 +95,13 @@ attestation_response = WebAuthn::AuthenticatorAttestationResponse.new(
95
95
  # the User Agent as part of the verification phase.
96
96
  original_origin = "https://www.example.com"
97
97
 
98
+ # In the case that a Relying Party ID (https://www.w3.org/TR/webauthn/#relying-party-identifier) different from `original_origin` was used on
99
+ # `navigator.credentials.create`, it needs to specified for verification.
100
+ # Otherwise, you can ignore passing in this value to the `verify` method below.
101
+ rp_id = "example.com"
102
+
98
103
  begin
99
- attestation_response.verify(original_challenge, original_origin)
104
+ attestation_response.verify(original_challenge, original_origin, rp_id: rp_id)
100
105
 
101
106
  # 1. Register the new user and
102
107
  # 2. Keep Credential ID and Credential Public Key under storage
@@ -157,6 +162,11 @@ assertion_response = WebAuthn::AuthenticatorAssertionResponse.new(
157
162
  # the User Agent as part of the verification phase.
158
163
  original_origin = "https://www.example.com"
159
164
 
165
+ # In the case that a Relying Party ID (https://www.w3.org/TR/webauthn/#relying-party-identifier) different from `original_origin` was used on
166
+ # `navigator.credentials.get`, it needs to be specified for verification.
167
+ # Otherwise, you can ignore passing in this value to the `verify` method below.`
168
+ rp_id = "example.com"
169
+
160
170
  # This hash must have the id and its corresponding public key of the
161
171
  # previously stored credential for the user that is attempting to sign in.
162
172
  allowed_credential = {
@@ -165,7 +175,7 @@ allowed_credential = {
165
175
  }
166
176
 
167
177
  begin
168
- assertion_response.verify(original_challenge, original_origin, allowed_credentials: [allowed_credential])
178
+ assertion_response.verify(original_challenge, original_origin, allowed_credentials: [allowed_credential], rp_id: rp_id)
169
179
 
170
180
  # Sign in the user
171
181
  rescue WebAuthn::VerificationError => e
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: Move this to cose gem
4
+ module COSE
5
+ # https://tools.ietf.org/html/rfc8152#section-8.1
6
+ Algorithm = Struct.new(:id, :name, :hash, :key_curve) do
7
+ @registered = {}
8
+
9
+ def self.register(id, name, hash, key_curve)
10
+ @registered[id] = COSE::Algorithm.new(id, name, hash, key_curve)
11
+ end
12
+
13
+ def self.find(id)
14
+ @registered[id]
15
+ end
16
+
17
+ def self.by_name(name)
18
+ @registered.values.detect { |algorithm| algorithm.name == name }
19
+ end
20
+
21
+ def value
22
+ id
23
+ end
24
+ end
25
+ end
26
+
27
+ COSE::Algorithm.register(-7, "ES256", "SHA256", "prime256v1")
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cose/ecdsa"
3
+ require "cose/algorithm"
4
4
  require "webauthn/authenticator_attestation_response"
5
5
  require "webauthn/authenticator_assertion_response"
6
6
  require "webauthn/security_utils"
@@ -11,18 +11,21 @@ require "securerandom"
11
11
  require "json"
12
12
 
13
13
  module WebAuthn
14
- CRED_PARAM_ES256 = { type: "public-key", alg: COSE::ECDSA::ALG_ES256 }.freeze
15
- RP_NAME = "web-server"
16
- USER_ID = "1"
17
- USER_NAME = "web-user"
14
+ CRED_PARAM_ES256 = { type: "public-key", alg: COSE::Algorithm.by_name("ES256").id }.freeze
18
15
  TYPES = { create: "webauthn.create", get: "webauthn.get" }.freeze
19
16
 
20
- def self.credential_creation_options
17
+ # TODO: make keyword arguments mandatory in next major version
18
+ def self.credential_creation_options(
19
+ rp_name: "web-server",
20
+ user_name: "web-user",
21
+ display_name: "web-user",
22
+ user_id: "1"
23
+ )
21
24
  {
22
25
  challenge: challenge,
23
26
  pubKeyCredParams: [CRED_PARAM_ES256],
24
- rp: { name: RP_NAME },
25
- user: { name: USER_NAME, displayName: USER_NAME, id: USER_ID }
27
+ rp: { name: rp_name },
28
+ user: { name: user_name, displayName: display_name, id: user_id }
26
29
  }
27
30
  end
28
31
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cose/algorithm"
3
4
  require "openssl"
4
5
  require "webauthn/attestation_statement/android_key/key_description"
5
6
  require "webauthn/attestation_statement/base"
@@ -26,11 +27,17 @@ module WebAuthn
26
27
  private
27
28
 
28
29
  def valid_signature?(authenticator_data, client_data_hash)
29
- attestation_certificate.public_key.verify(
30
- OpenSSL::Digest::SHA256.new,
31
- signature,
32
- authenticator_data.data + client_data_hash
33
- )
30
+ cose_algorithm = COSE::Algorithm.find(algorithm)
31
+
32
+ if cose_algorithm
33
+ attestation_certificate.public_key.verify(
34
+ cose_algorithm.hash,
35
+ signature,
36
+ authenticator_data.data + client_data_hash
37
+ )
38
+ else
39
+ raise "Unsupported algorithm #{algorithm}"
40
+ end
34
41
  end
35
42
 
36
43
  def matching_public_key?(authenticator_data)
@@ -87,6 +94,10 @@ module WebAuthn
87
94
  def signature
88
95
  statement["sig"]
89
96
  end
97
+
98
+ def algorithm
99
+ statement["alg"]
100
+ end
90
101
  end
91
102
  end
92
103
  end
@@ -8,12 +8,14 @@ module WebAuthn
8
8
  module AttestationStatement
9
9
  class FidoU2f < Base
10
10
  VALID_ATTESTATION_CERTIFICATE_COUNT = 1
11
- VALID_ATTESTATION_CERTIFICATE_KEY_CURVE = "prime256v1"
11
+ VALID_ATTESTATION_CERTIFICATE_ALGORITHM = COSE::Algorithm.by_name("ES256")
12
+ VALID_ATTESTED_AAGUID = 0.chr * WebAuthn::AuthenticatorData::AttestedCredentialData::AAGUID_LENGTH
12
13
 
13
14
  def valid?(authenticator_data, client_data_hash)
14
15
  valid_format? &&
15
16
  valid_certificate_public_key? &&
16
17
  valid_credential_public_key?(authenticator_data.credential.public_key) &&
18
+ valid_aaguid?(authenticator_data.attested_credential_data.aaguid) &&
17
19
  valid_signature?(authenticator_data, client_data_hash) &&
18
20
  [WebAuthn::AttestationStatement::ATTESTATION_TYPE_BASIC_OR_ATTCA, [attestation_certificate]]
19
21
  end
@@ -31,7 +33,7 @@ module WebAuthn
31
33
 
32
34
  def valid_certificate_public_key?
33
35
  certificate_public_key.is_a?(OpenSSL::PKey::EC) &&
34
- certificate_public_key.group.curve_name == VALID_ATTESTATION_CERTIFICATE_KEY_CURVE &&
36
+ certificate_public_key.group.curve_name == VALID_ATTESTATION_CERTIFICATE_ALGORITHM.key_curve &&
35
37
  certificate_public_key.check_key
36
38
  end
37
39
 
@@ -51,9 +53,13 @@ module WebAuthn
51
53
  statement["x5c"]
52
54
  end
53
55
 
56
+ def valid_aaguid?(attested_credential_data_aaguid)
57
+ attested_credential_data_aaguid == VALID_ATTESTED_AAGUID
58
+ end
59
+
54
60
  def valid_signature?(authenticator_data, client_data_hash)
55
61
  certificate_public_key.verify(
56
- "SHA256",
62
+ VALID_ATTESTATION_CERTIFICATE_ALGORITHM.hash,
57
63
  signature,
58
64
  verification_data(authenticator_data, client_data_hash)
59
65
  )
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cose/ecdsa"
3
+ require "cose/algorithm"
4
4
  require "cose/key/ec2"
5
5
  require "webauthn/attestation_statement/base"
6
6
 
@@ -25,7 +25,7 @@ module WebAuthn
25
25
  data.size >= COORDINATE_LENGTH * 2 &&
26
26
  cose_key.x.length == COORDINATE_LENGTH &&
27
27
  cose_key.y.length == COORDINATE_LENGTH &&
28
- cose_key.alg == COSE::ECDSA::ALG_ES256
28
+ cose_key.alg == COSE::Algorithm.by_name("ES256").id
29
29
  end
30
30
 
31
31
  def to_uncompressed_point
@@ -6,7 +6,11 @@ module WebAuthn
6
6
  module AttestationStatement
7
7
  class None < Base
8
8
  def valid?(*_args)
9
- [WebAuthn::AttestationStatement::ATTESTATION_TYPE_NONE, nil]
9
+ if statement == {}
10
+ [WebAuthn::AttestationStatement::ATTESTATION_TYPE_NONE, nil]
11
+ else
12
+ false
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cose/algorithm"
3
4
  require "openssl"
4
5
  require "webauthn/attestation_statement/base"
5
6
 
@@ -13,7 +14,9 @@ module WebAuthn
13
14
  check_unsupported_feature
14
15
 
15
16
  valid_format? &&
16
- valid_certificate_chain?(authenticator_data.credential) &&
17
+ valid_algorithm?(authenticator_data.credential) &&
18
+ valid_certificate_chain? &&
19
+ valid_public_keys?(authenticator_data.credential) &&
17
20
  meet_certificate_requirement? &&
18
21
  matching_aaguid?(authenticator_data.attested_credential_data.aaguid) &&
19
22
  valid_signature?(authenticator_data, client_data_hash) &&
@@ -22,6 +25,14 @@ module WebAuthn
22
25
 
23
26
  private
24
27
 
28
+ def valid_algorithm?(credential)
29
+ !self_attestation? || algorithm == COSE::Key.deserialize(credential.public_key).alg
30
+ end
31
+
32
+ def self_attestation?
33
+ !raw_attestation_certificates && !raw_ecdaa_key_id
34
+ end
35
+
25
36
  def algorithm
26
37
  statement["alg"]
27
38
  end
@@ -60,7 +71,16 @@ module WebAuthn
60
71
  attestation_certificate_chain&.first
61
72
  end
62
73
 
63
- def valid_certificate_chain?(credential)
74
+ def valid_certificate_chain?
75
+ if attestation_certificate_chain
76
+ attestation_certificate_chain[1..-1].all? { |c| certificate_in_use?(c) }
77
+ else
78
+ true
79
+ end
80
+ end
81
+
82
+ # TODO: Reevaluate this check
83
+ def valid_public_keys?(credential)
64
84
  public_keys = attestation_certificate_chain&.map(&:public_key) || [credential.public_key_object]
65
85
  public_keys.all? do |public_key|
66
86
  public_key.is_a?(OpenSSL::PKey::EC) && public_key.check_key
@@ -73,6 +93,7 @@ module WebAuthn
73
93
  subject = attestation_certificate.subject.to_a
74
94
 
75
95
  attestation_certificate.version == 2 &&
96
+ certificate_in_use?(attestation_certificate) &&
76
97
  subject.assoc('OU')&.at(1) == "Authenticator Attestation" &&
77
98
  attestation_certificate.extensions.find { |ext| ext.oid == 'basicConstraints' }&.value == 'CA:FALSE'
78
99
  else
@@ -92,12 +113,24 @@ module WebAuthn
92
113
  end
93
114
  end
94
115
 
116
+ def certificate_in_use?(certificate)
117
+ now = Time.now
118
+
119
+ certificate.not_before < now && now < certificate.not_after
120
+ end
121
+
95
122
  def valid_signature?(authenticator_data, client_data_hash)
96
- (attestation_certificate&.public_key || authenticator_data.credential.public_key_object).verify(
97
- "SHA256",
98
- signature,
99
- verification_data(authenticator_data, client_data_hash)
100
- )
123
+ cose_algorithm = COSE::Algorithm.find(algorithm)
124
+
125
+ if cose_algorithm
126
+ (attestation_certificate&.public_key || authenticator_data.credential.public_key_object).verify(
127
+ cose_algorithm.hash,
128
+ signature,
129
+ verification_data(authenticator_data, client_data_hash)
130
+ )
131
+ else
132
+ raise "Unsupported algorithm #{algorithm}"
133
+ end
101
134
  end
102
135
 
103
136
  def verification_data(authenticator_data, client_data_hash)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cose/algorithm"
3
4
  require "cose/key"
4
5
  require "webauthn/attestation_statement/fido_u2f/public_key"
5
6
  require "webauthn/authenticator_response"
@@ -21,7 +22,7 @@ module WebAuthn
21
22
  super(original_challenge, original_origin, rp_id: rp_id)
22
23
 
23
24
  verify_item(:credential, allowed_credentials)
24
- verify_item(:signature, credential_public_key(allowed_credentials))
25
+ verify_item(:signature, credential_cose_key(allowed_credentials))
25
26
 
26
27
  true
27
28
  end
@@ -34,12 +35,18 @@ module WebAuthn
34
35
 
35
36
  attr_reader :credential_id, :authenticator_data_bytes, :signature
36
37
 
37
- def valid_signature?(credential_public_key)
38
- credential_public_key.verify(
39
- "SHA256",
40
- signature,
41
- authenticator_data_bytes + client_data.hash
42
- )
38
+ def valid_signature?(credential_cose_key)
39
+ cose_algorithm = COSE::Algorithm.find(credential_cose_key.alg)
40
+
41
+ if cose_algorithm
42
+ credential_cose_key.to_pkey.verify(
43
+ cose_algorithm.hash,
44
+ signature,
45
+ authenticator_data_bytes + client_data.hash
46
+ )
47
+ else
48
+ raise "Unsupported algorithm #{credential_cose_key.alg}"
49
+ end
43
50
  end
44
51
 
45
52
  def valid_credential?(allowed_credentials)
@@ -48,7 +55,7 @@ module WebAuthn
48
55
  allowed_credential_ids.include?(credential_id)
49
56
  end
50
57
 
51
- def credential_public_key(allowed_credentials)
58
+ def credential_cose_key(allowed_credentials)
52
59
  matched_credential = allowed_credentials.find do |credential|
53
60
  credential[:id] == credential_id
54
61
  end
@@ -64,15 +71,14 @@ module WebAuthn
64
71
  # Given that the credential public key is expected to be stored long-term by the gem
65
72
  # user and later be passed as one of the allowed_credentials arguments in the
66
73
  # AuthenticatorAssertionResponse.verify call, we then need to support the two formats.
67
- group = OpenSSL::PKey::EC::Group.new("prime256v1")
68
- key = OpenSSL::PKey::EC.new(group)
69
- public_key_bn = OpenSSL::BN.new(matched_credential[:public_key], 2)
70
- public_key = OpenSSL::PKey::EC::Point.new(group, public_key_bn)
71
- key.public_key = public_key
72
-
73
- key
74
+ COSE::Key::EC2.new(
75
+ alg: COSE::Algorithm.by_name("ES256").id,
76
+ crv: 1,
77
+ x: matched_credential[:public_key][1..32],
78
+ y: matched_credential[:public_key][33..-1]
79
+ )
74
80
  else
75
- COSE::Key.deserialize(matched_credential[:public_key]).to_pkey
81
+ COSE::Key.deserialize(matched_credential[:public_key])
76
82
  end
77
83
  end
78
84
 
@@ -9,6 +9,7 @@ module WebAuthn
9
9
  class ChallengeVerificationError < VerificationError; end
10
10
  class OriginVerificationError < VerificationError; end
11
11
  class RpIdVerificationError < VerificationError; end
12
+ class TokenBindingVerificationError < VerificationError; end
12
13
  class TypeVerificationError < VerificationError; end
13
14
  class UserPresenceVerificationError < VerificationError; end
14
15
 
@@ -19,6 +20,7 @@ module WebAuthn
19
20
 
20
21
  def verify(original_challenge, original_origin, rp_id: nil)
21
22
  verify_item(:type)
23
+ verify_item(:token_binding)
22
24
  verify_item(:challenge, original_challenge)
23
25
  verify_item(:origin, original_origin)
24
26
  verify_item(:authenticator_data)
@@ -56,6 +58,10 @@ module WebAuthn
56
58
  client_data.type == type
57
59
  end
58
60
 
61
+ def valid_token_binding?
62
+ client_data.valid_token_binding_format?
63
+ end
64
+
59
65
  def valid_challenge?(original_challenge)
60
66
  WebAuthn::SecurityUtils.secure_compare(Base64.urlsafe_decode64(client_data.challenge), original_challenge)
61
67
  end
@@ -7,6 +7,8 @@ module WebAuthn
7
7
  class ClientDataMissingError < Error; end
8
8
 
9
9
  class ClientData
10
+ VALID_TOKEN_BINDING_STATUSES = ["present", "supported", "not-supported"].freeze
11
+
10
12
  def initialize(client_data_json)
11
13
  @client_data_json = client_data_json
12
14
  end
@@ -23,6 +25,18 @@ module WebAuthn
23
25
  data["origin"]
24
26
  end
25
27
 
28
+ def token_binding
29
+ data["tokenBinding"]
30
+ end
31
+
32
+ def valid_token_binding_format?
33
+ if token_binding
34
+ token_binding.is_a?(Hash) && VALID_TOKEN_BINDING_STATUSES.include?(token_binding["status"])
35
+ else
36
+ true
37
+ end
38
+ end
39
+
26
40
  def hash
27
41
  OpenSSL::Digest::SHA256.digest(client_data_json)
28
42
  end
@@ -32,7 +32,7 @@ module WebAuthn
32
32
  attestation_object
33
33
  end
34
34
 
35
- def get_assertion(rp_id:, client_data_hash:, user_present: true, user_verified: false)
35
+ def get_assertion(rp_id:, client_data_hash:, user_present: true, user_verified: false, aaguid: AAGUID)
36
36
  credential_options = credentials[rp_id]
37
37
 
38
38
  if credential_options
@@ -41,7 +41,8 @@ module WebAuthn
41
41
  authenticator_data = AuthenticatorData.new(
42
42
  rp_id_hash: hashed(rp_id),
43
43
  user_present: user_present,
44
- user_verified: user_verified
44
+ user_verified: user_verified,
45
+ aaguid: aaguid,
45
46
  ).serialize
46
47
 
47
48
  signature = credential_key.sign("SHA256", authenticator_data + client_data_hash)
@@ -7,12 +7,14 @@ require "securerandom"
7
7
  module WebAuthn
8
8
  class FakeAuthenticator
9
9
  class AuthenticatorData
10
- def initialize(rp_id_hash:, credential: nil, sign_count: 0, user_present: true, user_verified: !user_present)
10
+ def initialize(rp_id_hash:, credential: nil, sign_count: 0, user_present: true, user_verified: !user_present,
11
+ aaguid: WebAuthn::FakeAuthenticator::AAGUID)
11
12
  @rp_id_hash = rp_id_hash
12
13
  @credential = credential
13
14
  @sign_count = sign_count
14
15
  @user_present = user_present
15
16
  @user_verified = user_verified
17
+ @aaguid = aaguid
16
18
  end
17
19
 
18
20
  def serialize
@@ -45,7 +47,7 @@ module WebAuthn
45
47
  def attested_credential_data
46
48
  @attested_credential_data ||=
47
49
  if credential
48
- WebAuthn::FakeAuthenticator::AAGUID +
50
+ @aaguid +
49
51
  [credential[:id].length].pack("n*") +
50
52
  credential[:id] +
51
53
  cose_credential_public_key
@@ -8,10 +8,11 @@ module WebAuthn
8
8
  class FakeClient
9
9
  TYPES = { create: "webauthn.create", get: "webauthn.get" }.freeze
10
10
 
11
- attr_reader :origin
11
+ attr_reader :origin, :token_binding
12
12
 
13
- def initialize(origin = fake_origin, authenticator: WebAuthn::FakeAuthenticator.new)
13
+ def initialize(origin = fake_origin, token_binding: nil, authenticator: WebAuthn::FakeAuthenticator.new)
14
14
  @origin = origin
15
+ @token_binding = token_binding
15
16
  @authenticator = authenticator
16
17
  end
17
18
 
@@ -67,11 +68,17 @@ module WebAuthn
67
68
  attr_reader :authenticator
68
69
 
69
70
  def data_json_for(method, challenge)
70
- {
71
+ data = {
71
72
  type: type_for(method),
72
73
  challenge: encode(challenge),
73
74
  origin: origin
74
- }.to_json
75
+ }
76
+
77
+ if token_binding
78
+ data[:tokenBinding] = token_binding
79
+ end
80
+
81
+ data.to_json
75
82
  end
76
83
 
77
84
  def encode(data)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebAuthn
4
- VERSION = "1.12.0"
4
+ VERSION = "1.13.0"
5
5
  end
@@ -41,5 +41,5 @@ Gem::Specification.new do |spec|
41
41
  spec.add_development_dependency "byebug", "~> 11.0"
42
42
  spec.add_development_dependency "rake", "~> 12.3"
43
43
  spec.add_development_dependency "rspec", "~> 3.8"
44
- spec.add_development_dependency "rubocop", "0.65.0"
44
+ spec.add_development_dependency "rubocop", "0.67.2"
45
45
  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.12.0
4
+ version: 1.13.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-04-03 00:00:00.000000000 Z
12
+ date: 2019-04-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cbor
@@ -169,14 +169,14 @@ dependencies:
169
169
  requirements:
170
170
  - - '='
171
171
  - !ruby/object:Gem::Version
172
- version: 0.65.0
172
+ version: 0.67.2
173
173
  type: :development
174
174
  prerelease: false
175
175
  version_requirements: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - '='
178
178
  - !ruby/object:Gem::Version
179
- version: 0.65.0
179
+ version: 0.67.2
180
180
  description: Make your Ruby/Rails web server become a conformant WebAuthn Relying
181
181
  Party
182
182
  email:
@@ -200,7 +200,7 @@ files:
200
200
  - bin/setup
201
201
  - gemfiles/openssl_2_0.gemfile
202
202
  - gemfiles/openssl_2_1.gemfile
203
- - lib/cose/ecdsa.rb
203
+ - lib/cose/algorithm.rb
204
204
  - lib/webauthn.rb
205
205
  - lib/webauthn/attestation_statement.rb
206
206
  - lib/webauthn/attestation_statement/android_key.rb
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module COSE
4
- module ECDSA
5
- ALG_ES256 = -7
6
- end
7
- end