{-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE StandaloneDeriving #-} -- | Stability: experimental -- This module concerns identification of authenticatiors, notably 'AAGUID', -- 'SubjectKeyIdentifier' and a generic identifier type 'AuthenticatorIdentifier' module Crypto.WebAuthn.Model.Identifier ( AuthenticatorIdentifier (..), AAGUID (..), SubjectKeyIdentifier (..), ) where import Crypto.Hash (Digest, SHA1) import Crypto.WebAuthn.Internal.ToJSONOrphans () import qualified Crypto.WebAuthn.Model.Kinds as M import Data.Aeson (KeyValue ((.=)), ToJSON (toJSON), Value (String), object) import Data.ByteArray (convert) import qualified Data.ByteString as BS import Data.Hashable (Hashable (hashWithSalt), hashUsing) import Data.UUID (UUID) -- | [(spec)](https://www.w3.org/TR/webauthn-2/#aaguid) newtype AAGUID = AAGUID {unAAGUID :: UUID} deriving (Eq, Show) deriving newtype (Hashable, ToJSON) -- | A way to identify an authenticator data AuthenticatorIdentifier (p :: M.ProtocolKind) where -- | [(spec)](https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.0-ps-20210518.html#dom-metadatastatement-aaguid) -- A known FIDO2 [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator), -- identified by a 'AAGUID'. Note that the 'AAGUID' may be zero, meaning that -- we were able to verify that the [public key credential](https://www.w3.org/TR/webauthn-2/#public-key-credential). -- was generated by a trusted [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator), -- but we don't know which model it is. AuthenticatorIdentifierFido2 :: {idAaguid :: AAGUID} -> AuthenticatorIdentifier 'M.Fido2 -- | [(spec)](https://fidoalliance.org/specs/mds/fido-metadata-statement-v3.0-ps-20210518.html#dom-metadatastatement-attestationcertificatekeyidentifiers) -- A known FIDO U2F [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator), -- identified by a 'SubjectKeyIdentifier'. Clients that don't implement CTAP2 -- (which is used to communicate with FIDO2 authenticators) will use U2F to -- communicate with the authenticator instead, which doesn't have support for 'AAGUID's. AuthenticatorIdentifierFidoU2F :: {idSubjectKeyIdentifier :: SubjectKeyIdentifier} -> AuthenticatorIdentifier 'M.FidoU2F deriving instance Show (AuthenticatorIdentifier p) deriving instance Eq (AuthenticatorIdentifier p) instance ToJSON (AuthenticatorIdentifier p) where toJSON (AuthenticatorIdentifierFido2 aaguid) = object [ "tag" .= String "AuthenticatorIdentifierFido2", "idAaguid" .= aaguid ] toJSON (AuthenticatorIdentifierFidoU2F subjectKeyIdentifier) = object [ "tag" .= String "AuthenticatorIdentifierFidoU2F", "idSubjectKeyIdentifier" .= subjectKeyIdentifier ] -- | [(spec)](https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.2) -- This type represents method 1 of computing the identifier, as used in the -- [attestationCertificateKeyIdentifiers](https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html#dom-metadatablobpayloadentry-attestationcertificatekeyidentifiers) -- field of the [Metadata Service](https://fidoalliance.org/metadata/) newtype SubjectKeyIdentifier = SubjectKeyIdentifier {unSubjectKeyIdentifier :: Digest SHA1} deriving (Eq, Show) instance ToJSON SubjectKeyIdentifier where toJSON = toJSON @BS.ByteString . convert . unSubjectKeyIdentifier instance Hashable SubjectKeyIdentifier where hashWithSalt = hashUsing @BS.ByteString (convert . unSubjectKeyIdentifier)