webauthn-0.1.0.0: src/Crypto/WebAuthn/Model/Identifier.hs
{-# 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)