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
|
# 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_4
bit1 :reserved_for_future_use_3
bit1 :reserved_for_future_use_2
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 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
|