-
Notifications
You must be signed in to change notification settings - Fork 53
/
authenticator_data.rb
138 lines (112 loc) · 3.11 KB
/
authenticator_data.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# frozen_string_literal: true
require "bindata"
require "webauthn/authenticator_data/attested_credential_data"
require "webauthn/error"
module WebAuthn
class AuthenticatorDataFormatError < WebAuthn::Error; end
class AuthenticatorData < BinData::Record
RP_ID_HASH_LENGTH = 32
FLAGS_LENGTH = 1
SIGN_COUNT_LENGTH = 4
endian :big
count_bytes_remaining :data_length
string :rp_id_hash, length: RP_ID_HASH_LENGTH
struct :flags do
bit1 :extension_data_included
bit1 :attested_credential_data_included
bit1 :reserved_for_future_use_2
bit1 :backup_state
bit1 :backup_eligibility
bit1 :user_verified
bit1 :reserved_for_future_use_1
bit1 :user_present
end
bit32 :sign_count
count_bytes_remaining :trailing_bytes_length
string :trailing_bytes, length: :trailing_bytes_length
def self.deserialize(data)
read(data)
rescue EOFError
raise AuthenticatorDataFormatError
end
def data
to_binary_s
end
def valid?
(!attested_credential_data_included? || attested_credential_data.valid?) &&
(!extension_data_included? || extension_data) &&
valid_length?
end
def user_flagged?
user_present? || user_verified?
end
def user_present?
flags.user_present == 1
end
def user_verified?
flags.user_verified == 1
end
def credential_backup_eligible?
flags.backup_eligibility == 1
end
def credential_backed_up?
flags.backup_state == 1
end
def attested_credential_data_included?
flags.attested_credential_data_included == 1
end
def extension_data_included?
flags.extension_data_included == 1
end
def credential
if attested_credential_data_included?
attested_credential_data.credential
end
end
def attested_credential_data
@attested_credential_data ||=
AttestedCredentialData.deserialize(trailing_bytes)
rescue AttestedCredentialDataFormatError
raise AuthenticatorDataFormatError
end
def extension_data
@extension_data ||= CBOR.decode(raw_extension_data)
end
def aaguid
raw_aaguid = attested_credential_data.raw_aaguid
unless raw_aaguid == WebAuthn::AuthenticatorData::AttestedCredentialData::ZEROED_AAGUID
attested_credential_data.aaguid
end
end
private
def valid_length?
data_length == base_length + attested_credential_data_length + extension_data_length
end
def raw_extension_data
if extension_data_included?
if attested_credential_data_included?
trailing_bytes[attested_credential_data.length..-1]
else
trailing_bytes.snapshot
end
end
end
def attested_credential_data_length
if attested_credential_data_included?
attested_credential_data.length
else
0
end
end
def extension_data_length
if extension_data_included?
raw_extension_data.length
else
0
end
end
def base_length
RP_ID_HASH_LENGTH + FLAGS_LENGTH + SIGN_COUNT_LENGTH
end
end
end