Skip to content

Commit

Permalink
add handling passkey aaguid
Browse files Browse the repository at this point in the history
  • Loading branch information
ritou committed Sep 27, 2023
1 parent b31c315 commit ba669b9
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 5 deletions.
49 changes: 46 additions & 3 deletions lib/web_authn_lite/attested_credential_data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,44 @@ defmodule WebAuthnLite.AttestedCredentialData do

alias WebAuthnLite.{CredentialPublicKey, CBOR}

defstruct [:aaguid, :credential_id, :credential_public_key, :raw]
defstruct [:aaguid, :authenticator_name, :credential_id, :credential_public_key, :raw]

@min_size_of_attested_credential_data 18

@type t :: %__MODULE__{
aaguid: String.t(),
authenticator_name: String.t(),
credential_id: String.t(),
credential_public_key: term,
raw: binary
}

@rounded_error {:error, :invalid_attested_credential_data}

# MEMO: aaguid list management
# Identify the Authenticator Name using publicly available metadata
# - passkey: https://raw.githubusercontent.com/passkeydeveloper/passkey-authenticator-aaguids/main/aaguid.json
# TODO: Parsing and using FIDO MDS data?
@passkey_aaguid_file_name "passkey_aaguid.json"
@passkey_aaguid_list :code.priv_dir(:web_authn_lite)
|> Path.join(@passkey_aaguid_file_name)
|> File.read!()
|> Jason.decode!()

@unknown_aaguid "00000000-0000-0000-0000-000000000000"

@spec from_binary(attested_credential_data :: binary) ::
t | {:error, :invalid_attested_credential_data} | {:error, term}
def from_binary(attested_credential_data) do
with true <- attested_credential_data |> byte_size() >= @min_size_of_attested_credential_data,
aaguid <-
attested_credential_data |> :binary.part(0, 16) |> Base.url_encode64(padding: false),
attested_credential_data |> :binary.part(0, 16) |> format_aaguid(),
authenticator_name <- lookup_authenticator_name(aaguid),
credential_id_length <-
attested_credential_data |> :binary.part(16, 2) |> :binary.decode_unsigned(),
credential_id <-
attested_credential_data |> :binary.part(18, credential_id_length)
attested_credential_data
|> :binary.part(18, credential_id_length)
|> Base.url_encode64(padding: false),
credential_public_key <-
attested_credential_data
Expand All @@ -42,6 +57,7 @@ defmodule WebAuthnLite.AttestedCredentialData do
{:ok,
%__MODULE__{
aaguid: aaguid,
authenticator_name: authenticator_name,
credential_id: credential_id,
credential_public_key: credential_public_key,
raw: attested_credential_data
Expand All @@ -51,4 +67,31 @@ defmodule WebAuthnLite.AttestedCredentialData do
_ -> @rounded_error
end
end

defp format_aaguid(<<0::128>>), do: @unknown_aaguid

defp format_aaguid(aaguid) do
with <<
part1::binary-size(8),
part2::binary-size(4),
part3::binary-size(4),
part4::binary-size(4),
part5::binary-size(12)
>> <- Base.encode16(aaguid, case: :lower),
aaguid_str <- Enum.join([part1, part2, part3, part4, part5], "-") do
aaguid_str
else
_ -> @unknown_aaguid
end
end

defp lookup_authenticator_name(@unknown_aaguid), do: nil

defp lookup_authenticator_name(aaguid) do
cond do
# passkey
Map.has_key?(@passkey_aaguid_list, aaguid) -> @passkey_aaguid_list[aaguid]["name"]
true -> nil
end
end
end
Loading

0 comments on commit ba669b9

Please sign in to comment.