webauthn 1.0.0 → 1.1.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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +2 -2
- data/lib/webauthn/authenticator_assertion_response.rb +6 -6
- data/lib/webauthn/authenticator_attestation_response.rb +5 -5
- data/lib/webauthn/authenticator_data.rb +17 -11
- data/lib/webauthn/authenticator_data/attested_credential_data.rb +3 -3
- data/lib/webauthn/authenticator_response.rb +11 -9
- data/lib/webauthn/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6d2e58280b0751e346931762bbd6985f7ac0c89dc7a2ac98ae4658e98b6f68c
|
4
|
+
data.tar.gz: ca2ee35c669f2a31dd7770212deef3712b3089f34e119124977eac70f91cc3d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df657808c9a692d6f32b1256917dfb9867abd9fa6dc117059cb92f1d8cb80beb652af7d71b9881add353b20a8dad85cd00448ed8d6a9205070ed6d627882ea58
|
7
|
+
data.tar.gz: 9d417117edd82f9072dad0a98fafe4707121e2fb3cfb62678195e324d9bb68e1f00c35dbe8fc1721abd34ec1d09259decf2c620b4e56af2638cf3ec6ec98e850
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v1.1.0] - 2018-10-04
|
4
|
+
|
5
|
+
## Added
|
6
|
+
|
7
|
+
- _Registration_ ceremony
|
8
|
+
- `WebAuthn::AuthenticatorAttestationResponse.valid?` optionaly accepts rp_id. Thank you @sorah!
|
9
|
+
- _Authentication_ ceremony
|
10
|
+
- `WebAuthn::AuthenticatorAssertionResponse.valid?` optionaly accepts rp_id.
|
11
|
+
|
3
12
|
## [v1.0.0] - 2018-09-07
|
4
13
|
|
5
14
|
### Added
|
@@ -51,6 +60,7 @@
|
|
51
60
|
- `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
|
52
61
|
- Works with ruby 2.5
|
53
62
|
|
63
|
+
[v1.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v1.0.0...v1.1.0/
|
54
64
|
[v1.0.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.2.0...v1.0.0/
|
55
65
|
[v0.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.1.0...v0.2.0/
|
56
66
|
[v0.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v0.0.0...v0.1.0/
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
Easily implement WebAuthn in your ruby/rails app
|
4
4
|
|
5
5
|
[](https://rubygems.org/gems/webauthn)
|
6
|
-
[](https://travis-ci.org/cedarcode/webauthn-ruby)
|
6
|
+
[](https://travis-ci.org/cedarcode/webauthn-ruby)
|
7
7
|
|
8
8
|
## What is WebAuthn?
|
9
9
|
|
@@ -135,7 +135,7 @@ original_origin = "https://www.example.com"
|
|
135
135
|
# previously stored credential for the user that is attempting to sign in.
|
136
136
|
allowed_credential = {
|
137
137
|
id: credential_id,
|
138
|
-
|
138
|
+
public_key: credential_public_key
|
139
139
|
}
|
140
140
|
|
141
141
|
if assertion_response.valid?(original_challenge, original_origin, allowed_credential: allowed_credential)
|
@@ -12,12 +12,16 @@ module WebAuthn
|
|
12
12
|
@signature = signature
|
13
13
|
end
|
14
14
|
|
15
|
-
def valid?(original_challenge, original_origin, allowed_credentials:)
|
16
|
-
super(original_challenge, original_origin) &&
|
15
|
+
def valid?(original_challenge, original_origin, allowed_credentials:, rp_id: nil)
|
16
|
+
super(original_challenge, original_origin, rp_id: rp_id) &&
|
17
17
|
valid_credential?(allowed_credentials) &&
|
18
18
|
valid_signature?(credential_public_key(allowed_credentials))
|
19
19
|
end
|
20
20
|
|
21
|
+
def authenticator_data
|
22
|
+
@authenticator_data ||= WebAuthn::AuthenticatorData.new(authenticator_data_bytes)
|
23
|
+
end
|
24
|
+
|
21
25
|
private
|
22
26
|
|
23
27
|
attr_reader :credential_id, :authenticator_data_bytes, :signature
|
@@ -42,10 +46,6 @@ module WebAuthn
|
|
42
46
|
allowed_credential_ids.include?(credential_id)
|
43
47
|
end
|
44
48
|
|
45
|
-
def authenticator_data
|
46
|
-
@authenticator_data ||= WebAuthn::AuthenticatorData.new(authenticator_data_bytes)
|
47
|
-
end
|
48
|
-
|
49
49
|
def credential_public_key(allowed_credentials)
|
50
50
|
matched_credential = allowed_credentials.find do |credential|
|
51
51
|
credential[:id] == credential_id
|
@@ -17,7 +17,7 @@ module WebAuthn
|
|
17
17
|
@attestation_object = attestation_object
|
18
18
|
end
|
19
19
|
|
20
|
-
def valid?(original_challenge, original_origin)
|
20
|
+
def valid?(original_challenge, original_origin, rp_id: nil)
|
21
21
|
super &&
|
22
22
|
attestation_statement.valid?(authenticator_data, client_data.hash)
|
23
23
|
end
|
@@ -26,10 +26,6 @@ module WebAuthn
|
|
26
26
|
authenticator_data.credential
|
27
27
|
end
|
28
28
|
|
29
|
-
private
|
30
|
-
|
31
|
-
attr_reader :attestation_object
|
32
|
-
|
33
29
|
def attestation_statement
|
34
30
|
@attestation_statement ||=
|
35
31
|
WebAuthn::AttestationStatement.from(attestation["fmt"], attestation["attStmt"])
|
@@ -47,6 +43,10 @@ module WebAuthn
|
|
47
43
|
@attestation ||= CBOR.decode(attestation_object)
|
48
44
|
end
|
49
45
|
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :attestation_object
|
49
|
+
|
50
50
|
def type
|
51
51
|
WebAuthn::TYPES[:create]
|
52
52
|
end
|
@@ -10,6 +10,8 @@ module WebAuthn
|
|
10
10
|
FLAGS_LENGTH = 1
|
11
11
|
SIGN_COUNT_LENGTH = 4
|
12
12
|
|
13
|
+
SIGN_COUNT_POSITION = RP_ID_HASH_LENGTH + FLAGS_LENGTH
|
14
|
+
|
13
15
|
USER_PRESENT_FLAG_POSITION = 0
|
14
16
|
ATTESTED_CREDENTIAL_DATA_INCLUDED_FLAG_POSITION = 6
|
15
17
|
|
@@ -17,6 +19,8 @@ module WebAuthn
|
|
17
19
|
@data = data
|
18
20
|
end
|
19
21
|
|
22
|
+
attr_reader :data
|
23
|
+
|
20
24
|
def valid?
|
21
25
|
if attested_credential_data_included?
|
22
26
|
data.length > base_length && attested_credential_data.valid?
|
@@ -29,6 +33,10 @@ module WebAuthn
|
|
29
33
|
flags[USER_PRESENT_FLAG_POSITION] == "1"
|
30
34
|
end
|
31
35
|
|
36
|
+
def attested_credential_data_included?
|
37
|
+
flags[ATTESTED_CREDENTIAL_DATA_INCLUDED_FLAG_POSITION] == "1"
|
38
|
+
end
|
39
|
+
|
32
40
|
def rp_id_hash
|
33
41
|
@rp_id_hash ||=
|
34
42
|
if valid?
|
@@ -40,15 +48,21 @@ module WebAuthn
|
|
40
48
|
attested_credential_data.credential
|
41
49
|
end
|
42
50
|
|
43
|
-
|
44
|
-
|
45
|
-
|
51
|
+
def sign_count
|
52
|
+
@sign_count ||= data_at(SIGN_COUNT_POSITION, SIGN_COUNT_LENGTH).unpack1('L>')
|
53
|
+
end
|
46
54
|
|
47
55
|
def attested_credential_data
|
48
56
|
@attested_credential_data ||=
|
49
57
|
AttestedCredentialData.new(data_at(attested_credential_data_position))
|
50
58
|
end
|
51
59
|
|
60
|
+
def flags
|
61
|
+
@flags ||= data_at(flags_position, FLAGS_LENGTH).unpack1("b*")
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
52
66
|
def attested_credential_data_position
|
53
67
|
base_length
|
54
68
|
end
|
@@ -57,18 +71,10 @@ module WebAuthn
|
|
57
71
|
RP_ID_HASH_LENGTH + FLAGS_LENGTH + SIGN_COUNT_LENGTH
|
58
72
|
end
|
59
73
|
|
60
|
-
def flags
|
61
|
-
@flags ||= data_at(flags_position, FLAGS_LENGTH).unpack1("b*")
|
62
|
-
end
|
63
|
-
|
64
74
|
def flags_position
|
65
75
|
RP_ID_HASH_LENGTH
|
66
76
|
end
|
67
77
|
|
68
|
-
def attested_credential_data_included?
|
69
|
-
flags[ATTESTED_CREDENTIAL_DATA_INCLUDED_FLAG_POSITION] == "1"
|
70
|
-
end
|
71
|
-
|
72
78
|
def data_at(position, length = nil)
|
73
79
|
length ||= data.size - position
|
74
80
|
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "ostruct"
|
4
3
|
require "webauthn/authenticator_data/attested_credential_data/public_key_u2f"
|
5
4
|
|
6
5
|
module WebAuthn
|
@@ -12,7 +11,8 @@ module WebAuthn
|
|
12
11
|
|
13
12
|
UINT16_BIG_ENDIAN_FORMAT = "n*"
|
14
13
|
|
15
|
-
|
14
|
+
# FIXME: use keyword_init when we dropped Ruby 2.4 support
|
15
|
+
Credential = Struct.new(:id, :public_key)
|
16
16
|
|
17
17
|
def initialize(data)
|
18
18
|
@data = data
|
@@ -25,7 +25,7 @@ module WebAuthn
|
|
25
25
|
def credential
|
26
26
|
@credential ||=
|
27
27
|
if id
|
28
|
-
Credential.new(id
|
28
|
+
Credential.new(id, public_key.to_str)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -6,15 +6,19 @@ module WebAuthn
|
|
6
6
|
@client_data_json = client_data_json
|
7
7
|
end
|
8
8
|
|
9
|
-
def valid?(original_challenge, original_origin)
|
9
|
+
def valid?(original_challenge, original_origin, rp_id: nil)
|
10
10
|
valid_type? &&
|
11
11
|
valid_challenge?(original_challenge) &&
|
12
12
|
valid_origin?(original_origin) &&
|
13
|
-
valid_rp_id?(original_origin) &&
|
13
|
+
valid_rp_id?(rp_id || rp_id_from_origin(original_origin)) &&
|
14
14
|
authenticator_data.valid? &&
|
15
15
|
authenticator_data.user_present?
|
16
16
|
end
|
17
17
|
|
18
|
+
def client_data
|
19
|
+
@client_data ||= WebAuthn::ClientData.new(client_data_json)
|
20
|
+
end
|
21
|
+
|
18
22
|
private
|
19
23
|
|
20
24
|
attr_reader :client_data_json
|
@@ -23,10 +27,6 @@ module WebAuthn
|
|
23
27
|
client_data.type == type
|
24
28
|
end
|
25
29
|
|
26
|
-
def client_data
|
27
|
-
@client_data ||= WebAuthn::ClientData.new(client_data_json)
|
28
|
-
end
|
29
|
-
|
30
30
|
def valid_challenge?(original_challenge)
|
31
31
|
WebAuthn::Utils.authenticator_decode(client_data.challenge) == original_challenge
|
32
32
|
end
|
@@ -35,10 +35,12 @@ module WebAuthn
|
|
35
35
|
client_data.origin == original_origin
|
36
36
|
end
|
37
37
|
|
38
|
-
def valid_rp_id?(
|
39
|
-
|
38
|
+
def valid_rp_id?(rp_id)
|
39
|
+
OpenSSL::Digest::SHA256.digest(rp_id) == authenticator_data.rp_id_hash
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
+
def rp_id_from_origin(original_origin)
|
43
|
+
URI.parse(original_origin).host
|
42
44
|
end
|
43
45
|
|
44
46
|
def type
|
data/lib/webauthn/version.rb
CHANGED
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.
|
4
|
+
version: 1.1.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: 2018-
|
12
|
+
date: 2018-10-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cbor
|
@@ -167,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
167
|
version: '0'
|
168
168
|
requirements: []
|
169
169
|
rubyforge_project:
|
170
|
-
rubygems_version: 2.7.
|
170
|
+
rubygems_version: 2.7.6
|
171
171
|
signing_key:
|
172
172
|
specification_version: 4
|
173
173
|
summary: WebAuthn in ruby ― Ruby implementation of a WebAuthn Relying Party
|