webauthn 1.12.0 → 1.13.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: 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