webauthn 2.1.0 → 2.4.1
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 +4 -4
- data/.rubocop.yml +113 -13
- data/.travis.yml +21 -18
- data/Appraisals +4 -0
- data/CHANGELOG.md +41 -0
- data/CONTRIBUTING.md +0 -5
- data/README.md +70 -8
- data/SECURITY.md +6 -4
- data/gemfiles/openssl_2_2.gemfile +7 -0
- data/lib/cose/rsapkcs1_algorithm.rb +50 -0
- data/lib/webauthn/attestation_object.rb +43 -0
- data/lib/webauthn/attestation_statement.rb +20 -20
- data/lib/webauthn/attestation_statement/android_key.rb +28 -30
- data/lib/webauthn/attestation_statement/android_safetynet.rb +27 -7
- data/lib/webauthn/attestation_statement/base.rb +108 -10
- data/lib/webauthn/attestation_statement/fido_u2f.rb +8 -6
- data/lib/webauthn/attestation_statement/none.rb +7 -1
- data/lib/webauthn/attestation_statement/packed.rb +13 -41
- data/lib/webauthn/attestation_statement/tpm.rb +38 -75
- data/lib/webauthn/authenticator_assertion_response.rb +3 -7
- data/lib/webauthn/authenticator_attestation_response.rb +19 -84
- data/lib/webauthn/authenticator_data.rb +51 -51
- data/lib/webauthn/authenticator_data/attested_credential_data.rb +29 -50
- data/lib/webauthn/authenticator_response.rb +3 -0
- data/lib/webauthn/credential_creation_options.rb +2 -0
- data/lib/webauthn/credential_request_options.rb +2 -0
- data/lib/webauthn/fake_authenticator.rb +7 -3
- data/lib/webauthn/fake_authenticator/attestation_object.rb +7 -3
- data/lib/webauthn/fake_authenticator/authenticator_data.rb +2 -4
- data/lib/webauthn/fake_client.rb +19 -5
- data/lib/webauthn/public_key.rb +21 -2
- data/lib/webauthn/public_key_credential.rb +13 -3
- data/lib/webauthn/u2f_migrator.rb +5 -4
- data/lib/webauthn/version.rb +1 -1
- data/script/ci/install-openssl +7 -0
- data/script/ci/install-ruby +13 -0
- data/webauthn.gemspec +13 -9
- metadata +54 -41
- data/lib/android_safetynet/attestation_response.rb +0 -116
- data/lib/cose/rsassa_algorithm.rb +0 -10
- data/lib/tpm/constants.rb +0 -44
- data/lib/tpm/s_attest.rb +0 -26
- data/lib/tpm/s_attest/s_certify_info.rb +0 -14
- data/lib/tpm/sized_buffer.rb +0 -13
- data/lib/tpm/t_public.rb +0 -32
- data/lib/tpm/t_public/s_ecc_parms.rb +0 -17
- data/lib/tpm/t_public/s_rsa_parms.rb +0 -17
- data/lib/webauthn/attestation_statement/android_key/authorization_list.rb +0 -39
- data/lib/webauthn/attestation_statement/android_key/key_description.rb +0 -37
- data/lib/webauthn/attestation_statement/tpm/cert_info.rb +0 -44
- data/lib/webauthn/attestation_statement/tpm/pub_area.rb +0 -85
- data/lib/webauthn/signature_verifier.rb +0 -77
data/lib/webauthn/public_key.rb
CHANGED
@@ -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
|
-
|
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
|
@@ -28,10 +28,11 @@ module WebAuthn
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def credential
|
31
|
-
@credential ||=
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
@credential ||=
|
32
|
+
begin
|
33
|
+
hash = authenticator_data.send(:credential)
|
34
|
+
WebAuthn::AuthenticatorData::AttestedCredentialData::Credential.new(hash[:id], hash[:public_key].serialize)
|
35
|
+
end
|
35
36
|
end
|
36
37
|
|
37
38
|
def attestation_type
|
data/lib/webauthn/version.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
source "$HOME/.rvm/scripts/rvm"
|
6
|
+
|
7
|
+
if [[ "$LIBSSL" == "1.0" ]]; then
|
8
|
+
rvm use --install $RB --autolibs=read-only --disable-binary
|
9
|
+
elif [[ "$LIBSSL" == "1.1" ]]; then
|
10
|
+
rvm use --install $RB --binary --fuzzy
|
11
|
+
fi
|
12
|
+
|
13
|
+
[[ "`ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION'`" =~ "OpenSSL $LIBSSL" ]] || { echo "Wrong libssl version"; exit 1; }
|
data/webauthn.gemspec
CHANGED
@@ -22,28 +22,32 @@ Gem::Specification.new do |spec|
|
|
22
22
|
"source_code_uri" => "https://github.com/cedarcode/webauthn-ruby"
|
23
23
|
}
|
24
24
|
|
25
|
-
spec.files =
|
26
|
-
|
27
|
-
|
25
|
+
spec.files =
|
26
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
f.match(%r{^(test|spec|features|assets)/})
|
28
|
+
end
|
29
|
+
|
28
30
|
spec.bindir = "exe"
|
29
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
32
|
spec.require_paths = ["lib"]
|
31
33
|
|
32
|
-
spec.required_ruby_version = ">= 2.
|
34
|
+
spec.required_ruby_version = ">= 2.4"
|
33
35
|
|
36
|
+
spec.add_dependency "android_key_attestation", "~> 0.3.0"
|
34
37
|
spec.add_dependency "awrence", "~> 1.1"
|
35
38
|
spec.add_dependency "bindata", "~> 2.4"
|
36
39
|
spec.add_dependency "cbor", "~> 0.5.9"
|
37
|
-
spec.add_dependency "cose", "~>
|
38
|
-
spec.add_dependency "jwt", [">= 1.5", "< 3.0"]
|
40
|
+
spec.add_dependency "cose", "~> 1.1"
|
39
41
|
spec.add_dependency "openssl", "~> 2.0"
|
42
|
+
spec.add_dependency "safety_net_attestation", "~> 0.4.0"
|
40
43
|
spec.add_dependency "securecompare", "~> 1.0"
|
44
|
+
spec.add_dependency "tpm-key_attestation", "~> 0.10.0"
|
41
45
|
|
42
|
-
spec.add_development_dependency "appraisal", "~> 2.
|
46
|
+
spec.add_development_dependency "appraisal", "~> 2.3.0"
|
43
47
|
spec.add_development_dependency "bundler", ">= 1.17", "< 3.0"
|
44
48
|
spec.add_development_dependency "byebug", "~> 11.0"
|
45
49
|
spec.add_development_dependency "rake", "~> 13.0"
|
46
50
|
spec.add_development_dependency "rspec", "~> 3.8"
|
47
|
-
spec.add_development_dependency "rubocop", "0.
|
48
|
-
spec.add_development_dependency "
|
51
|
+
spec.add_development_dependency "rubocop", "0.89"
|
52
|
+
spec.add_development_dependency "rubocop-rspec", "~> 1.38.1"
|
49
53
|
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: 2.1
|
4
|
+
version: 2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gonzalo Rodriguez
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-02-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: android_key_attestation
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.3.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.3.0
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: awrence
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,48 +73,42 @@ dependencies:
|
|
59
73
|
requirements:
|
60
74
|
- - "~>"
|
61
75
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
76
|
+
version: '1.1'
|
63
77
|
type: :runtime
|
64
78
|
prerelease: false
|
65
79
|
version_requirements: !ruby/object:Gem::Requirement
|
66
80
|
requirements:
|
67
81
|
- - "~>"
|
68
82
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
83
|
+
version: '1.1'
|
70
84
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
85
|
+
name: openssl
|
72
86
|
requirement: !ruby/object:Gem::Requirement
|
73
87
|
requirements:
|
74
|
-
- - "
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '1.5'
|
77
|
-
- - "<"
|
88
|
+
- - "~>"
|
78
89
|
- !ruby/object:Gem::Version
|
79
|
-
version: '
|
90
|
+
version: '2.0'
|
80
91
|
type: :runtime
|
81
92
|
prerelease: false
|
82
93
|
version_requirements: !ruby/object:Gem::Requirement
|
83
94
|
requirements:
|
84
|
-
- - "
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
version: '1.5'
|
87
|
-
- - "<"
|
95
|
+
- - "~>"
|
88
96
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
97
|
+
version: '2.0'
|
90
98
|
- !ruby/object:Gem::Dependency
|
91
|
-
name:
|
99
|
+
name: safety_net_attestation
|
92
100
|
requirement: !ruby/object:Gem::Requirement
|
93
101
|
requirements:
|
94
102
|
- - "~>"
|
95
103
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
104
|
+
version: 0.4.0
|
97
105
|
type: :runtime
|
98
106
|
prerelease: false
|
99
107
|
version_requirements: !ruby/object:Gem::Requirement
|
100
108
|
requirements:
|
101
109
|
- - "~>"
|
102
110
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
111
|
+
version: 0.4.0
|
104
112
|
- !ruby/object:Gem::Dependency
|
105
113
|
name: securecompare
|
106
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,20 +123,34 @@ dependencies:
|
|
115
123
|
- - "~>"
|
116
124
|
- !ruby/object:Gem::Version
|
117
125
|
version: '1.0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: tpm-key_attestation
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 0.10.0
|
133
|
+
type: :runtime
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 0.10.0
|
118
140
|
- !ruby/object:Gem::Dependency
|
119
141
|
name: appraisal
|
120
142
|
requirement: !ruby/object:Gem::Requirement
|
121
143
|
requirements:
|
122
144
|
- - "~>"
|
123
145
|
- !ruby/object:Gem::Version
|
124
|
-
version: 2.
|
146
|
+
version: 2.3.0
|
125
147
|
type: :development
|
126
148
|
prerelease: false
|
127
149
|
version_requirements: !ruby/object:Gem::Requirement
|
128
150
|
requirements:
|
129
151
|
- - "~>"
|
130
152
|
- !ruby/object:Gem::Version
|
131
|
-
version: 2.
|
153
|
+
version: 2.3.0
|
132
154
|
- !ruby/object:Gem::Dependency
|
133
155
|
name: bundler
|
134
156
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,28 +219,28 @@ dependencies:
|
|
197
219
|
requirements:
|
198
220
|
- - '='
|
199
221
|
- !ruby/object:Gem::Version
|
200
|
-
version: 0.
|
222
|
+
version: '0.89'
|
201
223
|
type: :development
|
202
224
|
prerelease: false
|
203
225
|
version_requirements: !ruby/object:Gem::Requirement
|
204
226
|
requirements:
|
205
227
|
- - '='
|
206
228
|
- !ruby/object:Gem::Version
|
207
|
-
version: 0.
|
229
|
+
version: '0.89'
|
208
230
|
- !ruby/object:Gem::Dependency
|
209
|
-
name:
|
231
|
+
name: rubocop-rspec
|
210
232
|
requirement: !ruby/object:Gem::Requirement
|
211
233
|
requirements:
|
212
234
|
- - "~>"
|
213
235
|
- !ruby/object:Gem::Version
|
214
|
-
version:
|
236
|
+
version: 1.38.1
|
215
237
|
type: :development
|
216
238
|
prerelease: false
|
217
239
|
version_requirements: !ruby/object:Gem::Requirement
|
218
240
|
requirements:
|
219
241
|
- - "~>"
|
220
242
|
- !ruby/object:Gem::Version
|
221
|
-
version:
|
243
|
+
version: 1.38.1
|
222
244
|
description: |-
|
223
245
|
WebAuthn ruby server library ― Make your application a W3C Web Authentication conformant
|
224
246
|
Relying Party and allow your users to authenticate with U2F and FIDO2 authenticators.
|
@@ -247,21 +269,13 @@ files:
|
|
247
269
|
- gemfiles/cose_head.gemfile
|
248
270
|
- gemfiles/openssl_2_0.gemfile
|
249
271
|
- gemfiles/openssl_2_1.gemfile
|
272
|
+
- gemfiles/openssl_2_2.gemfile
|
250
273
|
- gemfiles/openssl_head.gemfile
|
251
|
-
- lib/
|
252
|
-
- lib/cose/rsassa_algorithm.rb
|
253
|
-
- lib/tpm/constants.rb
|
254
|
-
- lib/tpm/s_attest.rb
|
255
|
-
- lib/tpm/s_attest/s_certify_info.rb
|
256
|
-
- lib/tpm/sized_buffer.rb
|
257
|
-
- lib/tpm/t_public.rb
|
258
|
-
- lib/tpm/t_public/s_ecc_parms.rb
|
259
|
-
- lib/tpm/t_public/s_rsa_parms.rb
|
274
|
+
- lib/cose/rsapkcs1_algorithm.rb
|
260
275
|
- lib/webauthn.rb
|
276
|
+
- lib/webauthn/attestation_object.rb
|
261
277
|
- lib/webauthn/attestation_statement.rb
|
262
278
|
- lib/webauthn/attestation_statement/android_key.rb
|
263
|
-
- lib/webauthn/attestation_statement/android_key/authorization_list.rb
|
264
|
-
- lib/webauthn/attestation_statement/android_key/key_description.rb
|
265
279
|
- lib/webauthn/attestation_statement/android_safetynet.rb
|
266
280
|
- lib/webauthn/attestation_statement/base.rb
|
267
281
|
- lib/webauthn/attestation_statement/fido_u2f.rb
|
@@ -269,8 +283,6 @@ files:
|
|
269
283
|
- lib/webauthn/attestation_statement/none.rb
|
270
284
|
- lib/webauthn/attestation_statement/packed.rb
|
271
285
|
- lib/webauthn/attestation_statement/tpm.rb
|
272
|
-
- lib/webauthn/attestation_statement/tpm/cert_info.rb
|
273
|
-
- lib/webauthn/attestation_statement/tpm/pub_area.rb
|
274
286
|
- lib/webauthn/authenticator_assertion_response.rb
|
275
287
|
- lib/webauthn/authenticator_attestation_response.rb
|
276
288
|
- lib/webauthn/authenticator_data.rb
|
@@ -302,9 +314,10 @@ files:
|
|
302
314
|
- lib/webauthn/public_key_credential_with_assertion.rb
|
303
315
|
- lib/webauthn/public_key_credential_with_attestation.rb
|
304
316
|
- lib/webauthn/security_utils.rb
|
305
|
-
- lib/webauthn/signature_verifier.rb
|
306
317
|
- lib/webauthn/u2f_migrator.rb
|
307
318
|
- lib/webauthn/version.rb
|
319
|
+
- script/ci/install-openssl
|
320
|
+
- script/ci/install-ruby
|
308
321
|
- webauthn.gemspec
|
309
322
|
homepage: https://github.com/cedarcode/webauthn-ruby
|
310
323
|
licenses:
|
@@ -321,14 +334,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
321
334
|
requirements:
|
322
335
|
- - ">="
|
323
336
|
- !ruby/object:Gem::Version
|
324
|
-
version: '2.
|
337
|
+
version: '2.4'
|
325
338
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
326
339
|
requirements:
|
327
340
|
- - ">="
|
328
341
|
- !ruby/object:Gem::Version
|
329
342
|
version: '0'
|
330
343
|
requirements: []
|
331
|
-
rubygems_version: 3.
|
344
|
+
rubygems_version: 3.2.8
|
332
345
|
signing_key:
|
333
346
|
specification_version: 4
|
334
347
|
summary: WebAuthn ruby server library
|
@@ -1,116 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "base64"
|
4
|
-
require "jwt"
|
5
|
-
require "webauthn/security_utils"
|
6
|
-
|
7
|
-
module AndroidSafetynet
|
8
|
-
# Decoupled from WebAuthn, candidate for extraction
|
9
|
-
# Reference: https://developer.android.com/training/safetynet/attestation.html
|
10
|
-
class AttestationResponse
|
11
|
-
class VerificationError < StandardError; end
|
12
|
-
class LeafCertificateSubjectError < VerificationError; end
|
13
|
-
class NonceMismatchError < VerificationError; end
|
14
|
-
class SignatureError < VerificationError; end
|
15
|
-
class ResponseMissingError < VerificationError; end
|
16
|
-
class TimestampError < VerificationError; end
|
17
|
-
class TrustworthinessError < VerificationError; end
|
18
|
-
|
19
|
-
CERTIRICATE_CHAIN_HEADER = "x5c"
|
20
|
-
VALID_SUBJECT_HOSTNAME = "attest.android.com"
|
21
|
-
HEADERS_POSITION = 1
|
22
|
-
PAYLOAD_POSITION = 0
|
23
|
-
LEEWAY = 60
|
24
|
-
|
25
|
-
# FIXME: Should probably be limited to only roots published by Google
|
26
|
-
# See https://github.com/cedarcode/webauthn-ruby/issues/160#issuecomment-487941201
|
27
|
-
@trust_store = OpenSSL::X509::Store.new.tap { |trust_store| trust_store.set_default_paths }
|
28
|
-
|
29
|
-
class << self
|
30
|
-
attr_accessor :trust_store
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_reader :response
|
34
|
-
|
35
|
-
def initialize(response)
|
36
|
-
@response = response
|
37
|
-
end
|
38
|
-
|
39
|
-
def verify(nonce, trustworthiness: true)
|
40
|
-
if response
|
41
|
-
valid_nonce?(nonce) || raise(NonceMismatchError)
|
42
|
-
valid_attestation_domain? || raise(LeafCertificateSubjectError)
|
43
|
-
valid_signature? || raise(SignatureError)
|
44
|
-
valid_timestamp? || raise(TimestampError)
|
45
|
-
trustworthy? || raise(TrustworthinessError) if trustworthiness
|
46
|
-
|
47
|
-
true
|
48
|
-
else
|
49
|
-
raise(ResponseMissingError)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def cts_profile_match?
|
54
|
-
payload["ctsProfileMatch"]
|
55
|
-
end
|
56
|
-
|
57
|
-
def leaf_certificate
|
58
|
-
certificate_chain[0]
|
59
|
-
end
|
60
|
-
|
61
|
-
def certificate_chain
|
62
|
-
@certificate_chain ||= headers[CERTIRICATE_CHAIN_HEADER].map do |cert|
|
63
|
-
OpenSSL::X509::Certificate.new(Base64.strict_decode64(cert))
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def valid_timestamp?
|
68
|
-
now = Time.now
|
69
|
-
Time.at((payload["timestampMs"] / 1000.0).round).between?(now - LEEWAY, now)
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
def valid_nonce?(nonce)
|
75
|
-
WebAuthn::SecurityUtils.secure_compare(payload["nonce"], nonce)
|
76
|
-
end
|
77
|
-
|
78
|
-
def valid_attestation_domain?
|
79
|
-
common_name = leaf_certificate&.subject&.to_a&.assoc('CN')
|
80
|
-
|
81
|
-
if common_name
|
82
|
-
common_name[1] == VALID_SUBJECT_HOSTNAME
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def valid_signature?
|
87
|
-
JWT.decode(response, leaf_certificate.public_key, true, algorithms: ["ES256", "RS256"])
|
88
|
-
rescue JWT::VerificationError
|
89
|
-
false
|
90
|
-
end
|
91
|
-
|
92
|
-
def trustworthy?
|
93
|
-
!trust_store || trust_store.verify(leaf_certificate, signing_certificates)
|
94
|
-
end
|
95
|
-
|
96
|
-
def trust_store
|
97
|
-
self.class.trust_store
|
98
|
-
end
|
99
|
-
|
100
|
-
def signing_certificates
|
101
|
-
certificate_chain[1..-1]
|
102
|
-
end
|
103
|
-
|
104
|
-
def headers
|
105
|
-
jws_parts[HEADERS_POSITION]
|
106
|
-
end
|
107
|
-
|
108
|
-
def payload
|
109
|
-
jws_parts[PAYLOAD_POSITION]
|
110
|
-
end
|
111
|
-
|
112
|
-
def jws_parts
|
113
|
-
@jws_parts ||= JWT.decode(response, nil, false)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|