packages feed

webauthn 0.3.0.0 → 0.4.0.0

raw patch · 46 files changed

+3074/−2459 lines, 46 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Crypto.WebAuthn.AttestationStatementFormat.FidoU2F: CredentialPublicKeyNotECDSA :: PublicKey -> VerificationError
- Crypto.WebAuthn.Cose.Algorithm: CoseHashAlgECDSASHA256 :: CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: CoseHashAlgECDSASHA384 :: CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: CoseHashAlgECDSASHA512 :: CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: CoseHashAlgRSASHA1 :: CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: CoseHashAlgRSASHA256 :: CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: CoseHashAlgRSASHA384 :: CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: CoseHashAlgRSASHA512 :: CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: CoseSignAlgECDSA :: CoseHashAlgECDSA -> CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: CoseSignAlgEdDSA :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: CoseSignAlgRSA :: CoseHashAlgRSA -> CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: data CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: data CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: data CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: fromCoseSignAlg :: Num p => CoseSignAlg -> p
- Crypto.WebAuthn.Cose.Algorithm: instance Codec.Serialise.Class.Serialise Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Classes.Ord Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Classes.Ord Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Classes.Ord Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Show.Show Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Show.Show Crypto.WebAuthn.Cose.Algorithm.CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Algorithm: instance GHC.Show.Show Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmES256 :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmES384 :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmES512 :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmEdDSA :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmRS1 :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmRS256 :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmRS384 :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: pattern CoseAlgorithmRS512 :: CoseSignAlg
- Crypto.WebAuthn.Cose.Algorithm: toCoseSignAlg :: (Eq a, Num a, Show a) => a -> Either Text CoseSignAlg
- Crypto.WebAuthn.Cose.Internal.Verify: PublicKeyECDSA :: CoseCurveECDSA -> ByteString -> ByteString -> PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: PublicKeyEdDSA :: CoseCurveEdDSA -> ByteString -> PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: PublicKeyRSA :: Integer -> Integer -> PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: [ecdsaCurve] :: PublicKey -> CoseCurveECDSA
- Crypto.WebAuthn.Cose.Internal.Verify: [ecdsaX] :: PublicKey -> ByteString
- Crypto.WebAuthn.Cose.Internal.Verify: [ecdsaY] :: PublicKey -> ByteString
- Crypto.WebAuthn.Cose.Internal.Verify: [eddsaCurve] :: PublicKey -> CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Internal.Verify: [eddsaX] :: PublicKey -> ByteString
- Crypto.WebAuthn.Cose.Internal.Verify: [rsaE] :: PublicKey -> Integer
- Crypto.WebAuthn.Cose.Internal.Verify: [rsaN] :: PublicKey -> Integer
- Crypto.WebAuthn.Cose.Internal.Verify: data PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: fromCose :: CosePublicKey -> PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: fromCryptCurveECDSA :: CurveName -> Either Text CoseCurveECDSA
- Crypto.WebAuthn.Cose.Internal.Verify: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.Internal.Verify.PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.Internal.Verify.PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.Internal.Verify.PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: instance GHC.Show.Show Crypto.WebAuthn.Cose.Internal.Verify.PublicKey
- Crypto.WebAuthn.Cose.Internal.Verify: toCryptCurveECDSA :: CoseCurveECDSA -> CurveName
- Crypto.WebAuthn.Cose.Key: CoseCurveEd25519 :: CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: CoseCurveP256 :: CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: CoseCurveP384 :: CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: CoseCurveP521 :: CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: CosePublicKeyECDSA :: CoseHashAlgECDSA -> CoseCurveECDSA -> ByteString -> ByteString -> CosePublicKey
- Crypto.WebAuthn.Cose.Key: CosePublicKeyEdDSA :: CoseCurveEdDSA -> ByteString -> CosePublicKey
- Crypto.WebAuthn.Cose.Key: CosePublicKeyRSA :: CoseHashAlgRSA -> Integer -> Integer -> CosePublicKey
- Crypto.WebAuthn.Cose.Key: [ecdsaCurve] :: CosePublicKey -> CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: [ecdsaHash] :: CosePublicKey -> CoseHashAlgECDSA
- Crypto.WebAuthn.Cose.Key: [ecdsaX] :: CosePublicKey -> ByteString
- Crypto.WebAuthn.Cose.Key: [ecdsaY] :: CosePublicKey -> ByteString
- Crypto.WebAuthn.Cose.Key: [eddsaCurve] :: CosePublicKey -> CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: [eddsaX] :: CosePublicKey -> ByteString
- Crypto.WebAuthn.Cose.Key: [rsaE] :: CosePublicKey -> Integer
- Crypto.WebAuthn.Cose.Key: [rsaHash] :: CosePublicKey -> CoseHashAlgRSA
- Crypto.WebAuthn.Cose.Key: [rsaN] :: CosePublicKey -> Integer
- Crypto.WebAuthn.Cose.Key: data CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: data CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: data CosePublicKey
- Crypto.WebAuthn.Cose.Key: instance Codec.Serialise.Class.Serialise Crypto.WebAuthn.Cose.Key.CosePublicKey
- Crypto.WebAuthn.Cose.Key: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.Key.CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.Key.CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.Key.CosePublicKey
- Crypto.WebAuthn.Cose.Key: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.Key.CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.Key.CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.Key.CosePublicKey
- Crypto.WebAuthn.Cose.Key: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.Key.CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.Key.CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.Key.CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.Key.CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.Key.CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.Key.CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.Key.CosePublicKey
- Crypto.WebAuthn.Cose.Key: instance GHC.Show.Show Crypto.WebAuthn.Cose.Key.CoseCurveECDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Show.Show Crypto.WebAuthn.Cose.Key.CoseCurveEdDSA
- Crypto.WebAuthn.Cose.Key: instance GHC.Show.Show Crypto.WebAuthn.Cose.Key.CosePublicKey
- Crypto.WebAuthn.Cose.Key: keySignAlg :: CosePublicKey -> CoseSignAlg
- Crypto.WebAuthn.Model.Types: instance GHC.Enum.Bounded Crypto.WebAuthn.Model.Types.AuthenticatorTransport
- Crypto.WebAuthn.Model.Types: instance GHC.Enum.Enum Crypto.WebAuthn.Model.Types.AuthenticatorTransport
- Crypto.WebAuthn.Model.Types: stripRawCredential :: forall c raw. SingI c => Credential c raw -> Credential c 'False
- Crypto.WebAuthn.Model.WebIDL: data IDLCredentialAuthentication
- Crypto.WebAuthn.Model.WebIDL: data IDLCredentialOptionsAuthentication
- Crypto.WebAuthn.Model.WebIDL: data IDLCredentialOptionsRegistration
- Crypto.WebAuthn.Model.WebIDL: data IDLCredentialRegistration
- Crypto.WebAuthn.Model.WebIDL: decodeCredentialAuthentication :: IDLCredentialAuthentication -> Either Text (Credential 'Authentication 'True)
- Crypto.WebAuthn.Model.WebIDL: decodeCredentialRegistration :: SupportedAttestationStatementFormats -> IDLCredentialRegistration -> Either Text (Credential 'Registration 'True)
- Crypto.WebAuthn.Model.WebIDL: encodeCredentialOptionsAuthentication :: CredentialOptions 'Authentication -> IDLCredentialOptionsAuthentication
- Crypto.WebAuthn.Model.WebIDL: encodeCredentialOptionsRegistration :: CredentialOptions 'Registration -> IDLCredentialOptionsRegistration
- Crypto.WebAuthn.Model.WebIDL: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.IDLCredentialAuthentication
- Crypto.WebAuthn.Model.WebIDL: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.IDLCredentialRegistration
- Crypto.WebAuthn.Model.WebIDL: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.IDLCredentialAuthentication
- Crypto.WebAuthn.Model.WebIDL: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.IDLCredentialOptionsAuthentication
- Crypto.WebAuthn.Model.WebIDL: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.IDLCredentialOptionsRegistration
- Crypto.WebAuthn.Model.WebIDL: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.IDLCredentialRegistration
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.IDLCredentialAuthentication
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.IDLCredentialOptionsAuthentication
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.IDLCredentialOptionsRegistration
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.IDLCredentialRegistration
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.IDLCredentialAuthentication
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.IDLCredentialOptionsAuthentication
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.IDLCredentialOptionsRegistration
- Crypto.WebAuthn.Model.WebIDL: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.IDLCredentialRegistration
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding: decodeAttestationObject :: SupportedAttestationStatementFormats -> ByteString -> Either Text (AttestationObject 'True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding: decodeAuthenticatorData :: forall c. SingI c => ByteString -> Either Text (AuthenticatorData c 'True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding: decodeCollectedClientData :: forall (c :: CeremonyKind). SingI c => ByteString -> Either Text (CollectedClientData c 'True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding.ClientDataJSON
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding.ClientDataJSON
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding: encodeAttestationObject :: AttestationObject 'True -> ByteString
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding: encodeCollectedClientData :: forall (c :: CeremonyKind). SingI c => CollectedClientData c 'True -> ByteString
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding: encodeRawAuthenticatorData :: forall c raw. SingI c => AuthenticatorData c raw -> AuthenticatorData c 'True
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding: encodeRawCollectedClientData :: forall c raw. SingI c => CollectedClientData c raw -> CollectedClientData c 'True
- Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding: encodeRawCredential :: forall (c :: CeremonyKind) raw. SingI c => Credential c raw -> Credential c 'True
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: class Convert hs where {
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.AttestationObject 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.AuthenticatorData 'Crypto.WebAuthn.Model.Kinds.Authentication raw)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Authentication raw)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Registration raw)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.CollectedClientData c 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Authentication raw)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Registration raw)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Authentication)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Registration)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.AssertionSignature
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.AttestationConveyancePreference
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientInputs
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientOutputs
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.AuthenticatorAttachment
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.Challenge
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.CredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.CredentialId
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.CredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.CredentialType
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.CredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.RelyingPartyName
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.ResidentKeyRequirement
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.RpId
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.Timeout
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.UserAccountDisplayName
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.UserAccountName
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.UserHandle
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert Crypto.WebAuthn.Model.Types.UserVerificationRequirement
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert [Crypto.WebAuthn.Model.Types.AuthenticatorTransport]
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert [Crypto.WebAuthn.Model.Types.CredentialDescriptor]
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert [Crypto.WebAuthn.Model.Types.CredentialParameters]
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: instance Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert hs => Crypto.WebAuthn.Model.WebIDL.Internal.Convert.Convert (GHC.Maybe.Maybe hs)
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: type family IDL hs :: Type;
- Crypto.WebAuthn.Model.WebIDL.Internal.Convert: }
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: class Convert a => Decode a
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: class Convert a => DecodeCreated a
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: decode :: (Decode a, Coercible (IDL a) a) => IDL a -> Either Text a
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: decodeCreated :: DecodeCreated a => SupportedAttestationStatementFormats -> IDL a -> Either Text a
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode (Crypto.WebAuthn.Model.Types.AuthenticatorData 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Authentication)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Registration)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.AssertionSignature
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.AttestationConveyancePreference
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientOutputs
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.Challenge
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.CredentialId
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.CredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.CredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.RelyingPartyName
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.RpId
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.Timeout
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.UserAccountDisplayName
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.UserAccountName
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.UserHandle
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode Crypto.WebAuthn.Model.Types.UserVerificationRequirement
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode [Crypto.WebAuthn.Model.Types.AuthenticatorTransport]
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode [Crypto.WebAuthn.Model.Types.CredentialDescriptor]
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode [Crypto.WebAuthn.Model.Types.CredentialParameters]
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode a => Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode (GHC.Maybe.Maybe a)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.DecodeCreated (Crypto.WebAuthn.Model.Types.AttestationObject 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.DecodeCreated (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.DecodeCreated (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Decoding: instance Data.Singletons.Internal.SingI c => Crypto.WebAuthn.Model.WebIDL.Internal.Decoding.Decode (Crypto.WebAuthn.Model.Types.CollectedClientData c 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: class Convert a => Encode a
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: encode :: (Encode a, Coercible a (IDL a)) => a -> IDL a
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.AttestationObject 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Authentication)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Registration)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.AttestationConveyancePreference
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientInputs
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.AuthenticatorAttachment
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.Challenge
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.CredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.CredentialId
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.CredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.CredentialType
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.CredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.RelyingPartyName
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.ResidentKeyRequirement
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.RpId
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.Timeout
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.UserAccountDisplayName
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.UserAccountName
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.UserHandle
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode Crypto.WebAuthn.Model.Types.UserVerificationRequirement
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode [Crypto.WebAuthn.Model.Types.AuthenticatorTransport]
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode [Crypto.WebAuthn.Model.Types.CredentialDescriptor]
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode [Crypto.WebAuthn.Model.Types.CredentialParameters]
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode hs => Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (GHC.Maybe.Maybe hs)
- Crypto.WebAuthn.Model.WebIDL.Internal.Encoding: instance Data.Singletons.Internal.SingI c => Crypto.WebAuthn.Model.WebIDL.Internal.Encoding.Encode (Crypto.WebAuthn.Model.Types.CollectedClientData c 'GHC.Types.True)
- Crypto.WebAuthn.Model.WebIDL.Types: AuthenticatorAssertionResponse :: ArrayBuffer -> ArrayBuffer -> ArrayBuffer -> Maybe ArrayBuffer -> AuthenticatorAssertionResponse
- Crypto.WebAuthn.Model.WebIDL.Types: AuthenticatorAttestationResponse :: ArrayBuffer -> ArrayBuffer -> Maybe [DOMString] -> AuthenticatorAttestationResponse
- Crypto.WebAuthn.Model.WebIDL.Types: AuthenticatorSelectionCriteria :: Maybe DOMString -> Maybe DOMString -> Maybe Boolean -> Maybe DOMString -> AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: PublicKeyCredential :: ArrayBuffer -> response -> Map Text Value -> PublicKeyCredential response
- Crypto.WebAuthn.Model.WebIDL.Types: PublicKeyCredentialCreationOptions :: PublicKeyCredentialRpEntity -> PublicKeyCredentialUserEntity -> BufferSource -> [PublicKeyCredentialParameters] -> Maybe UnsignedLong -> Maybe [PublicKeyCredentialDescriptor] -> Maybe AuthenticatorSelectionCriteria -> Maybe DOMString -> Maybe (Map Text Value) -> PublicKeyCredentialCreationOptions
- Crypto.WebAuthn.Model.WebIDL.Types: PublicKeyCredentialDescriptor :: DOMString -> BufferSource -> Maybe [DOMString] -> PublicKeyCredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Types: PublicKeyCredentialParameters :: DOMString -> COSEAlgorithmIdentifier -> PublicKeyCredentialParameters
- Crypto.WebAuthn.Model.WebIDL.Types: PublicKeyCredentialRequestOptions :: BufferSource -> Maybe UnsignedLong -> Maybe USVString -> Maybe [PublicKeyCredentialDescriptor] -> Maybe DOMString -> Maybe (Map Text Value) -> PublicKeyCredentialRequestOptions
- Crypto.WebAuthn.Model.WebIDL.Types: PublicKeyCredentialRpEntity :: Maybe DOMString -> DOMString -> PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: PublicKeyCredentialUserEntity :: BufferSource -> DOMString -> DOMString -> PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:alg:PublicKeyCredentialParameters] :: PublicKeyCredentialParameters -> COSEAlgorithmIdentifier
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:allowCredentials:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe [PublicKeyCredentialDescriptor]
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:attestation:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:attestationObject:AuthenticatorAttestationResponse] :: AuthenticatorAttestationResponse -> ArrayBuffer
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:authenticatorAttachment:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:authenticatorData:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> ArrayBuffer
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:authenticatorSelection:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:challenge:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> BufferSource
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:challenge:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> BufferSource
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:clientDataJSON:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> ArrayBuffer
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:clientDataJSON:AuthenticatorAttestationResponse] :: AuthenticatorAttestationResponse -> ArrayBuffer
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:clientExtensionResults:PublicKeyCredential] :: PublicKeyCredential response -> Map Text Value
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:displayName:PublicKeyCredentialUserEntity] :: PublicKeyCredentialUserEntity -> DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:excludeCredentials:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe [PublicKeyCredentialDescriptor]
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:extensions:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe (Map Text Value)
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:extensions:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe (Map Text Value)
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:id:PublicKeyCredentialDescriptor] :: PublicKeyCredentialDescriptor -> BufferSource
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:id:PublicKeyCredentialRpEntity] :: PublicKeyCredentialRpEntity -> Maybe DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:id:PublicKeyCredentialUserEntity] :: PublicKeyCredentialUserEntity -> BufferSource
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:littype:PublicKeyCredentialDescriptor] :: PublicKeyCredentialDescriptor -> DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:littype:PublicKeyCredentialParameters] :: PublicKeyCredentialParameters -> DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:name:PublicKeyCredentialRpEntity] :: PublicKeyCredentialRpEntity -> DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:name:PublicKeyCredentialUserEntity] :: PublicKeyCredentialUserEntity -> DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:pubKeyCredParams:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> [PublicKeyCredentialParameters]
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:rawId:PublicKeyCredential] :: PublicKeyCredential response -> ArrayBuffer
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:requireResidentKey:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe Boolean
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:residentKey:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:response:PublicKeyCredential] :: PublicKeyCredential response -> response
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:rp:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:rpId:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe USVString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:signature:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> ArrayBuffer
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:timeout:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe UnsignedLong
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:timeout:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe UnsignedLong
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:transports:AuthenticatorAttestationResponse] :: AuthenticatorAttestationResponse -> Maybe [DOMString]
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:transports:PublicKeyCredentialDescriptor] :: PublicKeyCredentialDescriptor -> Maybe [DOMString]
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:user:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:userHandle:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> Maybe ArrayBuffer
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:userVerification:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: [$sel:userVerification:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe DOMString
- Crypto.WebAuthn.Model.WebIDL.Types: data AuthenticatorAssertionResponse
- Crypto.WebAuthn.Model.WebIDL.Types: data AuthenticatorAttestationResponse
- Crypto.WebAuthn.Model.WebIDL.Types: data AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: data PublicKeyCredential response
- Crypto.WebAuthn.Model.WebIDL.Types: data PublicKeyCredentialCreationOptions
- Crypto.WebAuthn.Model.WebIDL.Types: data PublicKeyCredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Types: data PublicKeyCredentialParameters
- Crypto.WebAuthn.Model.WebIDL.Types: data PublicKeyCredentialRequestOptions
- Crypto.WebAuthn.Model.WebIDL.Types: data PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: data PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAssertionResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAttestationResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialCreationOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialParameters
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRequestOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.FromJSON.FromJSON response => Data.Aeson.Types.FromJSON.FromJSON (Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredential response)
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAssertionResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAttestationResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialCreationOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialParameters
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRequestOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance Data.Aeson.Types.ToJSON.ToJSON response => Data.Aeson.Types.ToJSON.ToJSON (Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredential response)
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAssertionResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAttestationResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialCreationOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialParameters
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRequestOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Classes.Eq response => GHC.Classes.Eq (Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredential response)
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic (Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredential response)
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAssertionResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAttestationResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialCreationOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialParameters
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRequestOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Generics.Generic Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAssertionResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorAttestationResponse
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.AuthenticatorSelectionCriteria
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialCreationOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialDescriptor
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialParameters
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRequestOptions
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialRpEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredentialUserEntity
- Crypto.WebAuthn.Model.WebIDL.Types: instance GHC.Show.Show response => GHC.Show.Show (Crypto.WebAuthn.Model.WebIDL.Types.PublicKeyCredential response)
- Crypto.WebAuthn.Model.WebIDL.Types: type COSEAlgorithmIdentifier = Long
- Crypto.WebAuthn.Operation.Authentication: AuthenticationDisallowedCredential :: [CredentialDescriptor] -> Credential 'Authentication 'True -> AuthenticationError
- Crypto.WebAuthn.Operation.Authentication: AuthenticationInvalidSignature :: PublicKey -> ByteString -> AssertionSignature -> Text -> AuthenticationError
- Crypto.WebAuthn.Operation.Registration: RegistrationUndesiredPublicKeyAlgorithm :: CoseSignAlg -> [CoseSignAlg] -> RegistrationError
- Crypto.WebAuthn.WebIDL: URLEncodedBase64 :: ByteString -> BufferSource
- Crypto.WebAuthn.WebIDL: [unUrlEncodedBase64] :: BufferSource -> ByteString
- Crypto.WebAuthn.WebIDL: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.WebIDL.BufferSource
- Crypto.WebAuthn.WebIDL: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.WebIDL.BufferSource
- Crypto.WebAuthn.WebIDL: instance GHC.Classes.Eq Crypto.WebAuthn.WebIDL.BufferSource
- Crypto.WebAuthn.WebIDL: instance GHC.Show.Show Crypto.WebAuthn.WebIDL.BufferSource
- Crypto.WebAuthn.WebIDL: newtype BufferSource
- Crypto.WebAuthn.WebIDL: type ArrayBuffer = BufferSource
- Crypto.WebAuthn.WebIDL: type Boolean = Bool
- Crypto.WebAuthn.WebIDL: type DOMString = Text
- Crypto.WebAuthn.WebIDL: type Double = Double
- Crypto.WebAuthn.WebIDL: type Long = Int32
- Crypto.WebAuthn.WebIDL: type Octet = Word8
- Crypto.WebAuthn.WebIDL: type USVString = Text
- Crypto.WebAuthn.WebIDL: type UnsignedLong = Word32
- Crypto.WebAuthn.WebIDL: type UnsignedLongLong = Word64
- Crypto.WebAuthn.WebIDL: type UnsignedShort = Word16
+ Crypto.WebAuthn.AttestationStatementFormat.FidoU2F: CredentialPublicKeyNotCoseEC2 :: CosePublicKey -> VerificationError
+ Crypto.WebAuthn.Cose.PublicKey: CoseCurveEd25519 :: CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: CoseCurveP256 :: CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: CoseCurveP384 :: CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: CoseCurveP521 :: CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: PublicKeyECDSA :: CoseCurveECDSA -> Integer -> Integer -> UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: PublicKeyEdDSA :: CoseCurveEdDSA -> ByteString -> UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: PublicKeyRSA :: Integer -> Integer -> UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: [ecdsaCurve] :: UncheckedPublicKey -> CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: [ecdsaX] :: UncheckedPublicKey -> Integer
+ Crypto.WebAuthn.Cose.PublicKey: [ecdsaY] :: UncheckedPublicKey -> Integer
+ Crypto.WebAuthn.Cose.PublicKey: [eddsaCurve] :: UncheckedPublicKey -> CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: [eddsaX] :: UncheckedPublicKey -> ByteString
+ Crypto.WebAuthn.Cose.PublicKey: [rsaE] :: UncheckedPublicKey -> Integer
+ Crypto.WebAuthn.Cose.PublicKey: [rsaN] :: UncheckedPublicKey -> Integer
+ Crypto.WebAuthn.Cose.PublicKey: checkPublicKey :: UncheckedPublicKey -> Either Text PublicKey
+ Crypto.WebAuthn.Cose.PublicKey: coordinateSizeECDSA :: CoseCurveECDSA -> Int
+ Crypto.WebAuthn.Cose.PublicKey: coordinateSizeEdDSA :: CoseCurveEdDSA -> Int
+ Crypto.WebAuthn.Cose.PublicKey: data CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: data CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: data PublicKey
+ Crypto.WebAuthn.Cose.PublicKey: data UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: fromCryptCurveECDSA :: CurveName -> Either Text CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.PublicKey.CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.PublicKey.CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.PublicKey.PublicKey
+ Crypto.WebAuthn.Cose.PublicKey: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.PublicKey.UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.PublicKey.CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.PublicKey.CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.PublicKey.PublicKey
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.PublicKey.UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.PublicKey.CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.PublicKey.CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.PublicKey.CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.PublicKey.CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.PublicKey.CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.PublicKey.CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.PublicKey.UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Show.Show Crypto.WebAuthn.Cose.PublicKey.CoseCurveECDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Show.Show Crypto.WebAuthn.Cose.PublicKey.CoseCurveEdDSA
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Show.Show Crypto.WebAuthn.Cose.PublicKey.PublicKey
+ Crypto.WebAuthn.Cose.PublicKey: instance GHC.Show.Show Crypto.WebAuthn.Cose.PublicKey.UncheckedPublicKey
+ Crypto.WebAuthn.Cose.PublicKey: pattern PublicKey :: UncheckedPublicKey -> PublicKey
+ Crypto.WebAuthn.Cose.PublicKey: toCryptCurveECDSA :: CoseCurveECDSA -> CurveName
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: data PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: instance Codec.Serialise.Class.Serialise Crypto.WebAuthn.Cose.PublicKeyWithSignAlg.CosePublicKey
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.PublicKeyWithSignAlg.PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.PublicKeyWithSignAlg.PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.PublicKeyWithSignAlg.PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: instance GHC.Show.Show Crypto.WebAuthn.Cose.PublicKeyWithSignAlg.PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: makePublicKeyWithSignAlg :: PublicKey -> CoseSignAlg -> Either Text PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: pattern PublicKeyWithSignAlg :: PublicKey -> CoseSignAlg -> PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.PublicKeyWithSignAlg: type CosePublicKey = PublicKeyWithSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: CoseHashAlgECDSASHA256 :: CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: CoseHashAlgECDSASHA384 :: CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: CoseHashAlgECDSASHA512 :: CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: CoseHashAlgRSASHA1 :: CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: CoseHashAlgRSASHA256 :: CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: CoseHashAlgRSASHA384 :: CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: CoseHashAlgRSASHA512 :: CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: CoseSignAlgECDSA :: CoseHashAlgECDSA -> CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: CoseSignAlgEdDSA :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: CoseSignAlgRSA :: CoseHashAlgRSA -> CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: data CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: data CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: data CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: fromCoseSignAlg :: Num p => CoseSignAlg -> p
+ Crypto.WebAuthn.Cose.SignAlg: instance Codec.Serialise.Class.Serialise Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Classes.Eq Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Classes.Ord Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Classes.Ord Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Classes.Ord Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Enum.Bounded Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Enum.Enum Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Generics.Generic Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Show.Show Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgECDSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Show.Show Crypto.WebAuthn.Cose.SignAlg.CoseHashAlgRSA
+ Crypto.WebAuthn.Cose.SignAlg: instance GHC.Show.Show Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmES256 :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmES384 :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmES512 :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmEdDSA :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmRS1 :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmRS256 :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmRS384 :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: pattern CoseAlgorithmRS512 :: CoseSignAlg
+ Crypto.WebAuthn.Cose.SignAlg: toCoseSignAlg :: (Eq a, Num a, Show a) => a -> Either Text CoseSignAlg
+ Crypto.WebAuthn.Encoding.Binary: decodeAttestationObject :: SupportedAttestationStatementFormats -> ByteString -> Either Text (AttestationObject 'True)
+ Crypto.WebAuthn.Encoding.Binary: decodeAuthenticatorData :: forall (c :: CeremonyKind). SingI c => ByteString -> Either Text (AuthenticatorData c 'True)
+ Crypto.WebAuthn.Encoding.Binary: decodeCollectedClientData :: forall (c :: CeremonyKind). SingI c => ByteString -> Either Text (CollectedClientData c 'True)
+ Crypto.WebAuthn.Encoding.Binary: encodeAttestationObject :: AttestationObject 'True -> ByteString
+ Crypto.WebAuthn.Encoding.Binary: encodeRawAttestationObject :: AttestationObject raw -> AttestationObject 'True
+ Crypto.WebAuthn.Encoding.Binary: encodeRawAttestedCredentialData :: AttestedCredentialData c raw -> AttestedCredentialData c 'True
+ Crypto.WebAuthn.Encoding.Binary: encodeRawAuthenticatorData :: forall (c :: CeremonyKind) raw. SingI c => AuthenticatorData c raw -> AuthenticatorData c 'True
+ Crypto.WebAuthn.Encoding.Binary: encodeRawAuthenticatorResponse :: AuthenticatorResponse c raw -> AuthenticatorResponse c 'True
+ Crypto.WebAuthn.Encoding.Binary: encodeRawCollectedClientData :: forall (c :: CeremonyKind) raw. SingI c => CollectedClientData c raw -> CollectedClientData c 'True
+ Crypto.WebAuthn.Encoding.Binary: encodeRawCredential :: Credential c raw -> Credential c 'True
+ Crypto.WebAuthn.Encoding.Binary: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Binary.ClientDataJSON
+ Crypto.WebAuthn.Encoding.Binary: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Binary.ClientDataJSON
+ Crypto.WebAuthn.Encoding.Binary: stripRawAttestationObject :: AttestationObject raw -> AttestationObject 'False
+ Crypto.WebAuthn.Encoding.Binary: stripRawAttestedCredentialData :: AttestedCredentialData c raw -> AttestedCredentialData c 'False
+ Crypto.WebAuthn.Encoding.Binary: stripRawAuthenticatorData :: AuthenticatorData c raw -> AuthenticatorData c 'False
+ Crypto.WebAuthn.Encoding.Binary: stripRawAuthenticatorResponse :: AuthenticatorResponse c raw -> AuthenticatorResponse c 'False
+ Crypto.WebAuthn.Encoding.Binary: stripRawCollectedClientData :: CollectedClientData c raw -> CollectedClientData c 'False
+ Crypto.WebAuthn.Encoding.Binary: stripRawCredential :: Credential c raw -> Credential c 'False
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: AuthenticatorAssertionResponse :: Base64UrlString -> Base64UrlString -> Base64UrlString -> Maybe Base64UrlString -> AuthenticatorAssertionResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: AuthenticatorAttestationResponse :: Base64UrlString -> Base64UrlString -> Maybe [Text] -> AuthenticatorAttestationResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: AuthenticatorSelectionCriteria :: Maybe Text -> Maybe Text -> Maybe Bool -> Maybe Text -> AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: Base64UrlString :: ByteString -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: PublicKeyCredential :: Base64UrlString -> response -> Map Text Value -> PublicKeyCredential response
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: PublicKeyCredentialCreationOptions :: PublicKeyCredentialRpEntity -> PublicKeyCredentialUserEntity -> Base64UrlString -> [PublicKeyCredentialParameters] -> Maybe Word32 -> Maybe [PublicKeyCredentialDescriptor] -> Maybe AuthenticatorSelectionCriteria -> Maybe Text -> Maybe (Map Text Value) -> PublicKeyCredentialCreationOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: PublicKeyCredentialDescriptor :: Text -> Base64UrlString -> Maybe [Text] -> PublicKeyCredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: PublicKeyCredentialParameters :: Text -> COSEAlgorithmIdentifier -> PublicKeyCredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: PublicKeyCredentialRequestOptions :: Base64UrlString -> Maybe Word32 -> Maybe Text -> Maybe [PublicKeyCredentialDescriptor] -> Maybe Text -> Maybe (Map Text Value) -> PublicKeyCredentialRequestOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: PublicKeyCredentialRpEntity :: Maybe Text -> Text -> PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: PublicKeyCredentialUserEntity :: Base64UrlString -> Text -> Text -> PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:alg:PublicKeyCredentialParameters] :: PublicKeyCredentialParameters -> COSEAlgorithmIdentifier
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:allowCredentials:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe [PublicKeyCredentialDescriptor]
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:attestation:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:attestationObject:AuthenticatorAttestationResponse] :: AuthenticatorAttestationResponse -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:authenticatorAttachment:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:authenticatorData:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:authenticatorSelection:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:challenge:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:challenge:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:clientDataJSON:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:clientDataJSON:AuthenticatorAttestationResponse] :: AuthenticatorAttestationResponse -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:clientExtensionResults:PublicKeyCredential] :: PublicKeyCredential response -> Map Text Value
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:displayName:PublicKeyCredentialUserEntity] :: PublicKeyCredentialUserEntity -> Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:excludeCredentials:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe [PublicKeyCredentialDescriptor]
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:extensions:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe (Map Text Value)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:extensions:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe (Map Text Value)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:id:PublicKeyCredentialDescriptor] :: PublicKeyCredentialDescriptor -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:id:PublicKeyCredentialRpEntity] :: PublicKeyCredentialRpEntity -> Maybe Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:id:PublicKeyCredentialUserEntity] :: PublicKeyCredentialUserEntity -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:littype:PublicKeyCredentialDescriptor] :: PublicKeyCredentialDescriptor -> Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:littype:PublicKeyCredentialParameters] :: PublicKeyCredentialParameters -> Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:name:PublicKeyCredentialRpEntity] :: PublicKeyCredentialRpEntity -> Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:name:PublicKeyCredentialUserEntity] :: PublicKeyCredentialUserEntity -> Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:pubKeyCredParams:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> [PublicKeyCredentialParameters]
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:rawId:PublicKeyCredential] :: PublicKeyCredential response -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:requireResidentKey:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe Bool
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:residentKey:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:response:PublicKeyCredential] :: PublicKeyCredential response -> response
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:rp:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:rpId:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:signature:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:timeout:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> Maybe Word32
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:timeout:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe Word32
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:transports:AuthenticatorAttestationResponse] :: AuthenticatorAttestationResponse -> Maybe [Text]
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:transports:PublicKeyCredentialDescriptor] :: PublicKeyCredentialDescriptor -> Maybe [Text]
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:unBase64UrlString:Base64UrlString] :: Base64UrlString -> ByteString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:user:PublicKeyCredentialCreationOptions] :: PublicKeyCredentialCreationOptions -> PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:userHandle:AuthenticatorAssertionResponse] :: AuthenticatorAssertionResponse -> Maybe Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:userVerification:AuthenticatorSelectionCriteria] :: AuthenticatorSelectionCriteria -> Maybe Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: [$sel:userVerification:PublicKeyCredentialRequestOptions] :: PublicKeyCredentialRequestOptions -> Maybe Text
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: class Encode a => Decode m a
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: class Encode a where {
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data AuthenticatorAssertionResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data AuthenticatorAttestationResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data PublicKeyCredential response
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data PublicKeyCredentialCreationOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data PublicKeyCredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data PublicKeyCredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data PublicKeyCredentialRequestOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: data PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: decode :: (Decode m a, MonadError Text m, Coercible (JSON a) a) => JSON a -> m a
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: encode :: (Encode a, Coercible a (JSON a)) => a -> JSON a
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance (Data.Traversable.Traversable f, Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m a) => Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (f a)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance (GHC.Base.Functor f, Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode a) => Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (f a)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Control.Monad.Reader.Class.MonadReader Crypto.WebAuthn.Model.Types.SupportedAttestationStatementFormats m => Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.AttestationObject 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Control.Monad.Reader.Class.MonadReader Crypto.WebAuthn.Model.Types.SupportedAttestationStatementFormats m => Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Control.Monad.Reader.Class.MonadReader Crypto.WebAuthn.Model.Types.SupportedAttestationStatementFormats m => Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.AuthenticatorData 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Authentication)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Registration)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.AssertionSignature
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.AttestationConveyancePreference
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientInputs
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientOutputs
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.AuthenticatorAttachment
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.AuthenticatorTransport
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.Challenge
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.CredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.CredentialId
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.CredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.CredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.CredentialType
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.CredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.RelyingPartyName
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.ResidentKeyRequirement
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.RpId
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.Timeout
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.UserAccountDisplayName
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.UserAccountName
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.UserHandle
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m Crypto.WebAuthn.Model.Types.UserVerificationRequirement
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.AttestationObject 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.AuthenticatorData 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.AuthenticatorResponse 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Authentication 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.Credential 'Crypto.WebAuthn.Model.Kinds.Registration 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Authentication)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.CredentialOptions 'Crypto.WebAuthn.Model.Kinds.Registration)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Cose.SignAlg.CoseSignAlg
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.AssertionSignature
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.AttestationConveyancePreference
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientInputs
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.AuthenticationExtensionsClientOutputs
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.AuthenticatorAttachment
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.AuthenticatorTransport
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.Challenge
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.CredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.CredentialId
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.CredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.CredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.CredentialType
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.CredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.RelyingPartyName
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.ResidentKeyRequirement
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.RpId
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.Timeout
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.UserAccountDisplayName
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.UserAccountName
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.UserHandle
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode Crypto.WebAuthn.Model.Types.UserVerificationRequirement
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAssertionResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAttestationResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialCreationOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRequestOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON response => Data.Aeson.Types.FromJSON.FromJSON (Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredential response)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAssertionResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAttestationResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialCreationOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRequestOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON response => Data.Aeson.Types.ToJSON.ToJSON (Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredential response)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Singletons.Internal.SingI c => Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Decode m (Crypto.WebAuthn.Model.Types.CollectedClientData c 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance Data.Singletons.Internal.SingI c => Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Encode (Crypto.WebAuthn.Model.Types.CollectedClientData c 'GHC.Types.True)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAssertionResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAttestationResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialCreationOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRequestOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Classes.Eq response => GHC.Classes.Eq (Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredential response)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic (Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredential response)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAssertionResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAttestationResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialCreationOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRequestOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Generics.Generic Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAssertionResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorAttestationResponse
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.AuthenticatorSelectionCriteria
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialCreationOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialDescriptor
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialParameters
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRequestOptions
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialRpEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredentialUserEntity
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: instance GHC.Show.Show response => GHC.Show.Show (Crypto.WebAuthn.Encoding.Internal.WebAuthnJson.PublicKeyCredential response)
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: newtype Base64UrlString
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: type COSEAlgorithmIdentifier = Int32
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: type family JSON a :: Type;
+ Crypto.WebAuthn.Encoding.Internal.WebAuthnJson: }
+ Crypto.WebAuthn.Encoding.Strings: decodeAttestationConveyancePreference :: Text -> Either Text AttestationConveyancePreference
+ Crypto.WebAuthn.Encoding.Strings: decodeAuthenticatorAttachment :: Text -> Either Text AuthenticatorAttachment
+ Crypto.WebAuthn.Encoding.Strings: decodeAuthenticatorTransport :: Text -> AuthenticatorTransport
+ Crypto.WebAuthn.Encoding.Strings: decodeCredentialType :: Text -> Either Text CredentialType
+ Crypto.WebAuthn.Encoding.Strings: decodeResidentKeyRequirement :: Text -> Either Text ResidentKeyRequirement
+ Crypto.WebAuthn.Encoding.Strings: decodeUserVerificationRequirement :: Text -> Either Text UserVerificationRequirement
+ Crypto.WebAuthn.Encoding.Strings: encodeAttestationConveyancePreference :: AttestationConveyancePreference -> Text
+ Crypto.WebAuthn.Encoding.Strings: encodeAuthenticatorAttachment :: AuthenticatorAttachment -> Text
+ Crypto.WebAuthn.Encoding.Strings: encodeAuthenticatorTransport :: AuthenticatorTransport -> Text
+ Crypto.WebAuthn.Encoding.Strings: encodeCredentialType :: CredentialType -> Text
+ Crypto.WebAuthn.Encoding.Strings: encodeResidentKeyRequirement :: ResidentKeyRequirement -> Text
+ Crypto.WebAuthn.Encoding.Strings: encodeUserVerificationRequirement :: UserVerificationRequirement -> Text
+ Crypto.WebAuthn.Encoding.WebAuthnJson: data WJCredentialAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: data WJCredentialOptionsAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: data WJCredentialOptionsRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: data WJCredentialRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance Data.Aeson.Types.FromJSON.FromJSON Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialOptionsAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialOptionsRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance Data.Aeson.Types.ToJSON.ToJSON Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialOptionsAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialOptionsRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Classes.Eq Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialOptionsAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialOptionsRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: instance GHC.Show.Show Crypto.WebAuthn.Encoding.WebAuthnJson.WJCredentialRegistration
+ Crypto.WebAuthn.Encoding.WebAuthnJson: wjDecodeCredentialAuthentication :: WJCredentialAuthentication -> Either Text (Credential 'Authentication 'True)
+ Crypto.WebAuthn.Encoding.WebAuthnJson: wjDecodeCredentialRegistration :: WJCredentialRegistration -> Either Text (Credential 'Registration 'True)
+ Crypto.WebAuthn.Encoding.WebAuthnJson: wjDecodeCredentialRegistration' :: SupportedAttestationStatementFormats -> WJCredentialRegistration -> Either Text (Credential 'Registration 'True)
+ Crypto.WebAuthn.Encoding.WebAuthnJson: wjEncodeCredentialOptionsAuthentication :: CredentialOptions 'Authentication -> WJCredentialOptionsAuthentication
+ Crypto.WebAuthn.Encoding.WebAuthnJson: wjEncodeCredentialOptionsRegistration :: CredentialOptions 'Registration -> WJCredentialOptionsRegistration
+ Crypto.WebAuthn.Metadata.WebIDL: type Boolean = Bool
+ Crypto.WebAuthn.Metadata.WebIDL: type DOMString = Text
+ Crypto.WebAuthn.Metadata.WebIDL: type Double = Double
+ Crypto.WebAuthn.Metadata.WebIDL: type Long = Int32
+ Crypto.WebAuthn.Metadata.WebIDL: type Octet = Word8
+ Crypto.WebAuthn.Metadata.WebIDL: type USVString = Text
+ Crypto.WebAuthn.Metadata.WebIDL: type UnsignedLong = Word32
+ Crypto.WebAuthn.Metadata.WebIDL: type UnsignedLongLong = Word64
+ Crypto.WebAuthn.Metadata.WebIDL: type UnsignedShort = Word16
+ Crypto.WebAuthn.Model.Defaults: ascResidentKeyDefault :: Maybe Bool -> ResidentKeyRequirement
+ Crypto.WebAuthn.Model.Defaults: ascUserVerificationDefault :: UserVerificationRequirement
+ Crypto.WebAuthn.Model.Defaults: coaAllowCredentialsDefault :: [CredentialDescriptor]
+ Crypto.WebAuthn.Model.Defaults: coaUserVerificationDefault :: UserVerificationRequirement
+ Crypto.WebAuthn.Model.Defaults: corAttestationDefault :: AttestationConveyancePreference
+ Crypto.WebAuthn.Model.Defaults: corExcludeCredentialsDefault :: [CredentialDescriptor]
+ Crypto.WebAuthn.Model.Types: AuthenticatorTransportUnknown :: Text -> AuthenticatorTransport
+ Crypto.WebAuthn.Operation.Authentication: AuthenticationCredentialDisallowed :: [CredentialDescriptor] -> Credential 'Authentication 'True -> AuthenticationError
+ Crypto.WebAuthn.Operation.Authentication: AuthenticationSignatureInvalid :: Text -> AuthenticationError
+ Crypto.WebAuthn.Operation.Authentication: [aeAllowedCredentials] :: AuthenticationError -> [CredentialDescriptor]
+ Crypto.WebAuthn.Operation.Authentication: [aeAuthenticatorUser] :: AuthenticationError -> UserHandle
+ Crypto.WebAuthn.Operation.Authentication: [aeCreatedChallenge] :: AuthenticationError -> Challenge
+ Crypto.WebAuthn.Operation.Authentication: [aeExpectedOrigin] :: AuthenticationError -> Origin
+ Crypto.WebAuthn.Operation.Authentication: [aeExpectedRpIdHash] :: AuthenticationError -> RpIdHash
+ Crypto.WebAuthn.Operation.Authentication: [aeIdentifiedUser] :: AuthenticationError -> UserHandle
+ Crypto.WebAuthn.Operation.Authentication: [aeReceivedChallenge] :: AuthenticationError -> Challenge
+ Crypto.WebAuthn.Operation.Authentication: [aeReceivedCredential] :: AuthenticationError -> Credential 'Authentication 'True
+ Crypto.WebAuthn.Operation.Authentication: [aeReceivedOrigin] :: AuthenticationError -> Origin
+ Crypto.WebAuthn.Operation.Authentication: [aeReceivedRpIdHash] :: AuthenticationError -> RpIdHash
+ Crypto.WebAuthn.Operation.Authentication: [aeRegisteredUser] :: AuthenticationError -> UserHandle
+ Crypto.WebAuthn.Operation.Registration: RegistrationPublicKeyAlgorithmDisallowed :: [CoseSignAlg] -> CoseSignAlg -> RegistrationError
+ Crypto.WebAuthn.Operation.Registration: [reAllowedSigningAlgorithms] :: RegistrationError -> [CoseSignAlg]
+ Crypto.WebAuthn.Operation.Registration: [reCreatedChallenge] :: RegistrationError -> Challenge
+ Crypto.WebAuthn.Operation.Registration: [reExpectedOrigin] :: RegistrationError -> Origin
+ Crypto.WebAuthn.Operation.Registration: [reExpectedRpIdHash] :: RegistrationError -> RpIdHash
+ Crypto.WebAuthn.Operation.Registration: [reReceivedChallenge] :: RegistrationError -> Challenge
+ Crypto.WebAuthn.Operation.Registration: [reReceivedOrigin] :: RegistrationError -> Origin
+ Crypto.WebAuthn.Operation.Registration: [reReceivedRpIdHash] :: RegistrationError -> RpIdHash
+ Crypto.WebAuthn.Operation.Registration: [reReceivedSigningAlgorithm] :: RegistrationError -> CoseSignAlg
- Crypto.WebAuthn.Cose.Internal.Verify: verify :: CoseSignAlg -> PublicKey -> ByteString -> ByteString -> Either Text ()
+ Crypto.WebAuthn.Cose.Internal.Verify: verify :: PublicKeyWithSignAlg -> ByteString -> ByteString -> Either Text ()
- Crypto.WebAuthn.Model.Types: CollectedClientData :: Challenge -> Origin -> Bool -> RawField raw -> CollectedClientData (c :: CeremonyKind) raw
+ Crypto.WebAuthn.Model.Types: CollectedClientData :: Challenge -> Origin -> Maybe Bool -> RawField raw -> CollectedClientData (c :: CeremonyKind) raw
- Crypto.WebAuthn.Model.Types: [AuthenticatorResponseAuthentication] :: {araClientData :: CollectedClientData 'Authentication raw " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson) This attribute, inherited from `[AuthenticatorResponse](https://www.w3.org/TR/webauthn-2/#authenticatorresponse)`, contains the [JSON-compatible serialization of client data](https://www.w3.org/TR/webauthn-2/#collectedclientdata-json-compatible-serialization-of-client-data) (see [§ 6.5 Attestation](https://www.w3.org/TR/webauthn-2/#sctn-attestation)) passed to the authenticator by the client in order to generate this credential. The exact JSON serialization MUST be preserved, as the [hash of the serialized client data](https://www.w3.org/TR/webauthn-2/#collectedclientdata-hash-of-the-serialized-client-data) has been computed over it.", araAuthenticatorData :: AuthenticatorData 'Authentication raw " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata) This attribute contains the [authenticator data](https://www.w3.org/TR/webauthn-2/#authenticator-data) returned by the authenticator. See [§ 6.1 Authenticator Data](https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data).", araSignature :: AssertionSignature " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-signature) This attribute contains the raw signature returned from the authenticator. See [§ 6.3.3 The authenticatorGetAssertion Operation](https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion).", araUserHandle :: Maybe UserHandle " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-userhandle) This attribute contains the [user handle](https://www.w3.org/TR/webauthn-2/#user-handle) returned from the authenticator, or null if the authenticator did not return a [user handle](https://www.w3.org/TR/webauthn-2/#user-handle). See [§ 6.3.3 The authenticatorGetAssertion Operation](https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion)."} -> AuthenticatorResponse 'Authentication raw
+ Crypto.WebAuthn.Model.Types: [AuthenticatorResponseAuthentication] :: {araClientData :: CollectedClientData 'Authentication raw " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson) This attribute, inherited from `[AuthenticatorResponse](https://www.w3.org/TR/webauthn-2/#authenticatorresponse)`, contains the [JSON-compatible serialization of client data](https://www.w3.org/TR/webauthn-2/#collectedclientdata-json-compatible-serialization-of-client-data) (see [§ 6.5 Attestation](https://www.w3.org/TR/webauthn-2/#sctn-attestation)) passed to the authenticator by the client in order to generate this credential. The exact JSON serialization MUST be preserved, as the [hash of the serialized client data](https://www.w3.org/TR/webauthn-2/#collectedclientdata-hash-of-the-serialized-client-data) has been computed over it.", araAuthenticatorData :: AuthenticatorData 'Authentication raw " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata) This attribute contains the [authenticator data](https://www.w3.org/TR/webauthn-2/#authenticator-data) returned by the authenticator. See [§ 6.1 Authenticator Data](https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data).", araSignature :: AssertionSignature " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-signature) This attribute contains the raw [assertion signature](https://www.w3.org/TR/webauthn-2/#assertion-signature) returned from the authenticator. See [§ 6.3.3 The authenticatorGetAssertion Operation](https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion).", araUserHandle :: Maybe UserHandle " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-userhandle) This attribute contains the [user handle](https://www.w3.org/TR/webauthn-2/#user-handle) returned from the authenticator, or null if the authenticator did not return a [user handle](https://www.w3.org/TR/webauthn-2/#user-handle). See [§ 6.3.3 The authenticatorGetAssertion Operation](https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion)."} -> AuthenticatorResponse 'Authentication raw
- Crypto.WebAuthn.Model.Types: [CredentialOptionsAuthentication] :: {coaChallenge :: Challenge " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-challenge) This member represents a challenge that the selected [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator) signs, along with other data, when producing an [authentication assertion](https://www.w3.org/TR/webauthn-2/#authentication-assertion). See the [§ 13.4.3 Cryptographic Challenges](https://www.w3.org/TR/webauthn-2/#sctn-cryptographic-challenges) security consideration.", coaTimeout :: Maybe Timeout " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-timeout) This OPTIONAL member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. The value is treated as a hint, and MAY be overridden by the [client](https://www.w3.org/TR/webauthn-2/#client).", coaRpId :: Maybe RpId " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-rpid) This OPTIONAL member specifies the [relying party identifier](https://www.w3.org/TR/webauthn-2/#relying-party-identifier) claimed by the caller. If omitted, its value will be the `[CredentialsContainer](https://w3c.github.io/webappsec-credential-management/#credentialscontainer)` object’s [relevant settings object](https://html.spec.whatwg.org/multipage/webappapis.html#relevant-settings-object)'s [origin](https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-origin)'s [effective domain](https://html.spec.whatwg.org/multipage/origin.html#concept-origin-effective-domain).", coaAllowCredentials :: [CredentialDescriptor] " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-allowcredentials) This OPTIONAL member contains a list of 'CredentialDescriptor' objects representing [public key credentials](https://www.w3.org/TR/webauthn-2/#public-key-credential) acceptable to the caller, in descending order of the caller’s preference (the first item in the list is the most preferred credential, and so on down the list).", coaUserVerification :: UserVerificationRequirement " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-userverification) This OPTIONAL member describes the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)'s requirements regarding [user verification](https://www.w3.org/TR/webauthn-2/#user-verification) for the `[get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)` operation.", coaExtensions :: Maybe AuthenticationExtensionsClientInputs " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-extensions) This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator. For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension. TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model#extensions"."} -> CredentialOptions 'Authentication
+ Crypto.WebAuthn.Model.Types: [CredentialOptionsAuthentication] :: {coaChallenge :: Challenge " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-challenge) This member represents a challenge that the selected [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator) signs, along with other data, when producing an [authentication assertion](https://www.w3.org/TR/webauthn-2/#authentication-assertion). See the [§ 13.4.3 Cryptographic Challenges](https://www.w3.org/TR/webauthn-2/#sctn-cryptographic-challenges) security consideration.", coaTimeout :: Maybe Timeout " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-timeout) This OPTIONAL member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. The value is treated as a hint, and MAY be overridden by the [client](https://www.w3.org/TR/webauthn-2/#client).", coaRpId :: Maybe RpId " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-rpid) This OPTIONAL member specifies the [relying party identifier](https://www.w3.org/TR/webauthn-2/#relying-party-identifier) claimed by the caller. If omitted, its value will be the `[CredentialsContainer](https://w3c.github.io/webappsec-credential-management/#credentialscontainer)` object’s [relevant settings object](https://html.spec.whatwg.org/multipage/webappapis.html#relevant-settings-object)'s [origin](https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-origin)'s [effective domain](https://html.spec.whatwg.org/multipage/origin.html#concept-origin-effective-domain).", coaAllowCredentials :: [CredentialDescriptor] " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-allowcredentials) This OPTIONAL member contains a list of 'CredentialDescriptor' objects representing [public key credentials](https://www.w3.org/TR/webauthn-2/#public-key-credential) acceptable to the caller, in descending order of the caller’s preference (the first item in the list is the most preferred credential, and so on down the list). The default value of this field is 'Crypto.WebAuthn.Model.Defaults.coaAllowCredentialsDefault'.", coaUserVerification :: UserVerificationRequirement " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-userverification) This OPTIONAL member describes the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)'s requirements regarding [user verification](https://www.w3.org/TR/webauthn-2/#user-verification) for the `[get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)` operation. The default value of this field is 'Crypto.WebAuthn.Model.Defaults.coaUserVerificationDefault'.", coaExtensions :: Maybe AuthenticationExtensionsClientInputs " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-extensions) This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator. For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension. TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model.Types#extensions"."} -> CredentialOptions 'Authentication
- Crypto.WebAuthn.Model.Types: [CredentialOptionsRegistration] :: {corRp :: CredentialRpEntity " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-rp) This member contains data about the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party) responsible for the request.", corUser :: CredentialUserEntity " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-user) This member contains data about the user account for which the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party) is requesting attestation.", corChallenge :: Challenge " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-challenge) This member contains a challenge intended to be used for generating the newly created credential’s attestation object. See the [§ 13.4.3 Cryptographic Challenges](https://www.w3.org/TR/webauthn-2/#sctn-cryptographic-challenges) security consideration.", corPubKeyCredParams :: [CredentialParameters] " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-pubkeycredparams) This member contains information about the desired properties of the credential to be created. The sequence is ordered from most preferred to least preferred. The [client](https://www.w3.org/TR/webauthn-2/#client) makes a best-effort to create the most preferred credential that it can.", corTimeout :: Maybe Timeout " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-timeout) This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a hint, and MAY be overridden by the [client](https://www.w3.org/TR/webauthn-2/#client).", corExcludeCredentials :: [CredentialDescriptor] " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-excludecredentials) This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party) that wish to limit the creation of multiple credentials for the same account on a single authenticator. The [client](https://www.w3.org/TR/webauthn-2/#client) is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter.", corAuthenticatorSelection :: Maybe AuthenticatorSelectionCriteria " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection) This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party) that wish to select the appropriate authenticators to participate in the [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create) operation.", corAttestation :: AttestationConveyancePreference " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-attestation) This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party) that wish to express their preference for [attestation conveyance](https://www.w3.org/TR/webauthn-2/#attestation-conveyance).", corExtensions :: Maybe AuthenticationExtensionsClientInputs " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-extensions) This member contains additional parameters requesting additional processing by the client and authenticator. For example, the caller may request that only authenticators with certain capabilities be used to create the credential, or that particular information be returned in the [attestation object](https://www.w3.org/TR/webauthn-2/#attestation-object). Some extensions are defined in [§ 9 WebAuthn Extensions](https://www.w3.org/TR/webauthn-2/#sctn-extensions); consult the IANA "WebAuthn Extension Identifiers" registry [IANA-WebAuthn-Registries](https://www.w3.org/TR/webauthn-2/#biblio-iana-webauthn-registries) established by [RFC8809](https://www.w3.org/TR/webauthn-2/#biblio-rfc8809) for an up-to-date list of registered [WebAuthn Extensions](https://www.w3.org/TR/webauthn-2/#webauthn-extensions). TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model#extensions"."} -> CredentialOptions 'Registration
+ Crypto.WebAuthn.Model.Types: [CredentialOptionsRegistration] :: {corRp :: CredentialRpEntity " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-rp) This member contains data about the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party) responsible for the request.", corUser :: CredentialUserEntity " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-user) This member contains data about the user account for which the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party) is requesting attestation.", corChallenge :: Challenge " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-challenge) This member contains a challenge intended to be used for generating the newly created credential’s attestation object. See the [§ 13.4.3 Cryptographic Challenges](https://www.w3.org/TR/webauthn-2/#sctn-cryptographic-challenges) security consideration.", corPubKeyCredParams :: [CredentialParameters] " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-pubkeycredparams) This member contains information about the desired properties of the credential to be created. The sequence is ordered from most preferred to least preferred. The [client](https://www.w3.org/TR/webauthn-2/#client) makes a best-effort to create the most preferred credential that it can.", corTimeout :: Maybe Timeout " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-timeout) This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a hint, and MAY be overridden by the [client](https://www.w3.org/TR/webauthn-2/#client).", corExcludeCredentials :: [CredentialDescriptor] " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-excludecredentials) This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party) that wish to limit the creation of multiple credentials for the same account on a single authenticator. The [client](https://www.w3.org/TR/webauthn-2/#client) is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter. The default value of this field is 'Crypto.WebAuthn.Model.Defaults.corExcludeCredentials'.", corAuthenticatorSelection :: Maybe AuthenticatorSelectionCriteria " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection) This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party) that wish to select the appropriate authenticators to participate in the [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create) operation.", corAttestation :: AttestationConveyancePreference " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-attestation) This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party) that wish to express their preference for [attestation conveyance](https://www.w3.org/TR/webauthn-2/#attestation-conveyance). The default value of this field is 'Crypto.WebAuthn.Model.Defaults.corAttestationDefault'.", corExtensions :: Maybe AuthenticationExtensionsClientInputs " [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-extensions) This member contains additional parameters requesting additional processing by the client and authenticator. For example, the caller may request that only authenticators with certain capabilities be used to create the credential, or that particular information be returned in the [attestation object](https://www.w3.org/TR/webauthn-2/#attestation-object). Some extensions are defined in [§ 9 WebAuthn Extensions](https://www.w3.org/TR/webauthn-2/#sctn-extensions); consult the IANA "WebAuthn Extension Identifiers" registry [IANA-WebAuthn-Registries](https://www.w3.org/TR/webauthn-2/#biblio-iana-webauthn-registries) established by [RFC8809](https://www.w3.org/TR/webauthn-2/#biblio-rfc8809) for an up-to-date list of registered [WebAuthn Extensions](https://www.w3.org/TR/webauthn-2/#webauthn-extensions). TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model.Types#extensions"."} -> CredentialOptions 'Registration
- Crypto.WebAuthn.Model.Types: [ccdCrossOrigin] :: CollectedClientData (c :: CeremonyKind) raw -> Bool
+ Crypto.WebAuthn.Model.Types: [ccdCrossOrigin] :: CollectedClientData (c :: CeremonyKind) raw -> Maybe Bool

Files

changelog.md view
@@ -1,3 +1,38 @@+### 0.4.0.0++* [#129](https://github.com/tweag/webauthn/pull/129) Rename and expand+  documentation for authentication/registration errors.+* [#136](https://github.com/tweag/webauthn/pull/136) Improve the safety and+  remove duplication of the public key interface. More checks are being done+  now, preventing invalid public keys from being constructed.+* [#140](https://github.com/tweag/webauthn/pull/140) Introduction of new+  serialization-related modules, all reexported via `Crypto.WebAuthn`:+  - `Crypto.WebAuthn.Model.Defaults` for defaults of optional fields+  - `Crypto.WebAuthn.Encoding.Strings` for string serializations of enumerations+  - `Crypto.WebAuthn.Encoding.Binary` for binary serializations+* [#140](https://github.com/tweag/webauthn/pull/140) Backwards-incompatible+  changes/fixes regarding serialization:+  - Fix unknown `AuthenticatorTransport` values being ignored. This breaks+    backwards compatibility when the received `AuthenticatorTransport`s are+    inspected and stored in the database. Users are encouraged to serialize+    individual `AuthenticatorTransport`s to strings using the new+    `encodeAuthenticatorTransport`. The [example+    server](https://github.com/tweag/webauthn/tree/master/server) has been+    updated to store all encoded `AuthenticatorTransport`s as a CBOR-encoded+    bytestring in the database, but other schemes to store multiple transports+    can also be employed.+  - Rename webauthn-json decoding/encoding functions to have a "wj" prefix like+    `wjEncodeCredentialOptionsRegistration`. The types they interact with have+    changed their prefix from `IDL` to `WJ` as well+  - Introduce `wjDecodeCredentialRegistration'` (with a tick) to take a+    `SupportedAttestationStatementFormats` argument, while the unticked version+    doesn't take such an argument anymore. In the future only the unticked+    version is expected to stay backwards-compatible.+  - `ccdCrossOrigin`s type was corrected from `Bool` to `Maybe Bool`, where+    `Nothing` has the same semantics as `Just False`. This is necessary for+    compatibility with WebAuthn Level 1 clients, which don't set this field++ ### 0.3.0.0  * [#125](https://github.com/tweag/webauthn/pull/125) Some small metadata type
src/Crypto/WebAuthn.hs view
@@ -100,18 +100,24 @@     -- | A set of types representing credential options ('CredentialOptions')     -- and their resulting credentials responses ('Credential'), used in     -- [step 2](#step-2) and [step 4](#step-4#) respectively.-    ---    -- Also includes a set of functions for indirectly encoding credential-    -- options to JSON ('encodeCredentialOptionsRegistration',-    -- 'encodeCredentialOptionsAuthentication') and indirectly decoding-    -- credential responses from JSON ('decodeCredentialRegistration',-    -- 'decodeCredentialAuthentication'), using the same encoding as-    -- [webauthn-json](https://github.com/github/webauthn-json) which can be-    -- used on the JavaScript side. This is needed to construct the response-    -- for [step 2](#step-2) and to deconstruct the request in-    -- [step 4](#step-4) respectively.     module Crypto.WebAuthn.Model, +    -- * WebAuthn Encoding++    -- | Includes everything needed to encode\/decode WebAuthn types between+    -- serializations and Haskell types defined in "Crypto.WebAuthn.Model".+    -- Most notably this includes encoding and decoding functions for messages+    -- exchanged with the+    -- [webauthn-json](https://github.com/github/webauthn-json) JavaScript+    -- library: Encoding 'CredentialOptions' to intermediate JSON-serializable+    -- types using 'wjEncodeCredentialOptionsRegistration' and+    -- 'wjEncodeCredentialOptionsAuthentication', which can be used for [step+    -- 2](#step-2). Also decoding 'Credential's from intermediate+    -- JSON-deserializable types using 'wjDecodeCredentialRegistration' and+    -- 'wjDecodeCredentialAuthentication', which can be used for [step+    -- 4](#step-4).+    module Crypto.WebAuthn.Encoding,+     -- * Attestation Statement Formats      -- | In case of a [registration ceremony](https://www.w3.org/TR/webauthn-2/#registration),@@ -122,8 +128,9 @@     --     -- This module contains the 'allSupportedFormats' value, which contains     -- implementations of all standard attestation statement formats supported-    -- by this library. It can be passed to the 'decodeCredentialRegistration'-    -- to enable all these formats.+    -- by this library. It can be manually passed to the+    -- 'wjDecodeCredentialRegistration'' to enable only specific formats or add+    -- support for additional ones.     module Crypto.WebAuthn.AttestationStatementFormat,      -- * Operations@@ -159,6 +166,7 @@ where  import Crypto.WebAuthn.AttestationStatementFormat+import Crypto.WebAuthn.Encoding import Crypto.WebAuthn.Metadata import Crypto.WebAuthn.Model import Crypto.WebAuthn.Operation
src/Crypto/WebAuthn/AttestationStatementFormat/AndroidKey.hs view
@@ -18,8 +18,10 @@ import Control.Exception (Exception) import Control.Monad (forM, unless, void, when) import Crypto.Hash (Digest, SHA256, digestFromByteString)-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose+import qualified Crypto.WebAuthn.Cose.PublicKey as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import Crypto.WebAuthn.Internal.Utils (failure) import qualified Crypto.WebAuthn.Model.Types as M import Data.ASN1.Parse (ParseASN1, getNext, getNextContainerMaybe, hasNext, onNextContainer, onNextContainerMaybe, runParseASN1)@@ -155,10 +157,11 @@ data Statement = Statement   { sig :: ByteString,     x5c :: NonEmpty X509.SignedCertificate,-    alg :: Cose.CoseSignAlg,-    -- | Holds the parsed attestation extension of the above X509 certificate-    -- Not part of the spec, but prevents parsing in the AndroidKey.verify function-    pubKey :: Cose.PublicKey,+    -- | Holds both the "alg" from the statement and the public key from the+    -- X.509 certificate+    pubKeyAndAlg :: Cose.PublicKeyWithSignAlg,+    -- | Holds the parsed attestation extension of the above X509 certificate,+    -- prevents having to parse it in the AndroidKey.verify function     attExt :: ExtAttestation   }   deriving (Eq, Show)@@ -166,7 +169,7 @@ instance ToJSON Statement where   toJSON Statement {..} =     object-      [ "alg" .= alg,+      [ "alg" .= Cose.signAlg pubKeyAndAlg,         "sig" .= sig,         "x5c" .= x5c       ]@@ -250,13 +253,15 @@          pubKey <- Cose.fromX509 $ X509.certPubKey cert +        pubKeyAndAlg <- Cose.makePublicKeyWithSignAlg pubKey alg+         pure Statement {..}       _ -> Left $ "CBOR map didn't have expected value types (alg: int, sig: bytes, x5c: nonempty list): " <> Text.pack (show xs)    asfEncode _ Statement {..} =     CBOR.TMap       [ (CBOR.TString "sig", CBOR.TBytes sig),-        (CBOR.TString "alg", CBOR.TInt $ Cose.fromCoseSignAlg alg),+        (CBOR.TString "alg", CBOR.TInt $ Cose.fromCoseSignAlg $ Cose.signAlg pubKeyAndAlg),         ( CBOR.TString "x5c",           CBOR.TList $             map (CBOR.TBytes . X509.encodeSignedObject) $ toList x5c@@ -273,13 +278,14 @@     -- 2. Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash using the     -- public key in the first certificate in x5c with the algorithm specified in alg.     let signedData = rawData <> convert (M.unClientDataHash clientDataHash)-    case Cose.verify alg pubKey signedData sig of+    case Cose.verify pubKeyAndAlg signedData sig of       Right () -> pure ()       Left err -> failure $ VerificationFailure err      -- 3. Verify that the public key in the first certificate in x5c matches the credentialPublicKey in the     -- attestedCredentialData in authenticatorData.-    let credentialPublicKey = Cose.fromCose (M.acdCredentialPublicKey adAttestedCredentialData)+    let credentialPublicKey = Cose.publicKey (M.acdCredentialPublicKey adAttestedCredentialData)+        pubKey = Cose.publicKey pubKeyAndAlg     unless (credentialPublicKey == pubKey) . failure $ PublicKeyMismatch credentialPublicKey pubKey      -- 4. Verify that the attestationChallenge field in the attestation certificate extension data is identical to
src/Crypto/WebAuthn/AttestationStatementFormat/Apple.hs view
@@ -22,6 +22,8 @@ import Control.Monad.Cont (unless) import Crypto.Hash (Digest, SHA256, digestFromByteString, hash) import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose+import qualified Crypto.WebAuthn.Cose.PublicKey as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose import Crypto.WebAuthn.Internal.Utils (failure) import qualified Crypto.WebAuthn.Model.Types as M import qualified Data.ASN1.Parse as ASN1@@ -161,7 +163,7 @@        -- 5. Verify that the credential public key equals the Subject Public Key       -- of credCert.-      let credentialPublicKey = Cose.fromCose $ M.acdCredentialPublicKey credData+      let credentialPublicKey = Cose.publicKey $ M.acdCredentialPublicKey credData       unless (credentialPublicKey == pubKey) . failure $ PublicKeyMismatch credentialPublicKey pubKey        -- 6. If successful, return implementation-specific values representing
src/Crypto/WebAuthn/AttestationStatementFormat/FidoU2F.hs view
@@ -12,17 +12,19 @@   ) where +import qualified Codec.CBOR.Read as CBOR import qualified Codec.CBOR.Term as CBOR import Control.Exception (Exception) import Control.Monad (unless) import Crypto.PubKey.ECC.Types (CurveName (SEC_p256r1))-import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose import Crypto.WebAuthn.Internal.Utils (failure) import qualified Crypto.WebAuthn.Model.Types as M import Data.Aeson (ToJSON, object, toJSON, (.=)) import Data.Bifunctor (first) import qualified Data.ByteArray as BA import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS import Data.HashMap.Strict ((!?)) import qualified Data.Text as Text import qualified Data.X509 as X509@@ -40,9 +42,9 @@ data VerificationError   = -- | The public key in the certificate was not an EC Key or the curve was not the p256 curve     CertificatePublicKeyInvalid X509.PubKey-  | -- | The credential public key is not an ECDSA key-    CredentialPublicKeyNotECDSA Cose.PublicKey-  | -- | The x and/or y coordinates of the credential public key don't have a length of 32 bytes+  | -- | The COSE encoding of the credential public key does not have key type EC2+    CredentialPublicKeyNotCoseEC2 Cose.CosePublicKey+  | -- | The x and/or y coordinates of the credential public key are longer than 32 bytes     CoordinateSizeInvalid       { -- | Actual length in bytes of the x coordinate         xLength :: Int,@@ -129,12 +131,12 @@       -- If size differs or "-3" key is not found, terminate this algorithm and       -- return an appropriate error.       -- NOTE: Already done during decoding of the COSE public key-      case Cose.fromCose acdCredentialPublicKey of-        Cose.PublicKeyECDSA {ecdsaX = xb, ecdsaY = yb} -> do-          let xlen = BS.length xb-              ylen = BS.length yb-          unless (xlen == 32 && ylen == 32) $ failure $ CoordinateSizeInvalid xlen ylen-+      case extractPublicKey . M.unRaw $ acdCredentialPublicKeyBytes of+        Nothing -> failure $ CredentialPublicKeyNotCoseEC2 acdCredentialPublicKey+        Just (xb, yb) -> do+          -- We decode the x and y values in an earlier stage of the process. In order to construct the publicKeyU2F, we have to reencode the value.+          unless (BS.length xb == 32 && BS.length yb == 32) $+            failure $ CoordinateSizeInvalid (BS.length xb) (BS.length yb)           -- 4.c Let publicKeyU2F be the concatenation 0x04 || x || y.           let publicKeyU2F = BS.singleton 0x04 <> xb <> yb @@ -155,7 +157,6 @@             X509.SignaturePass -> pure ()             X509.SignatureFailed e -> failure $ SignatureInvalid e           pure ()-        key -> failure $ CredentialPublicKeyNotECDSA key        -- 7. Optionally, inspect x5c and consult externally provided knowledge to       -- determine whether attStmt conveys a Basic or AttCA attestation.@@ -172,3 +173,21 @@ -- SomeAttestationStatementFormat type. format :: M.SomeAttestationStatementFormat format = M.SomeAttestationStatementFormat Format++-- [(spec)](https://www.iana.org/assignments/cose/cose.xhtml)+-- This function assumes the provided key is an ECC key, which is a valid+-- assumption as we have already verified that in step 2.b+-- Any non ECC key would result in another error here, which is fine.+extractPublicKey :: BS.ByteString -> Maybe (BS.ByteString, BS.ByteString)+extractPublicKey keyBS = do+  (rest, result) <- either (const Nothing) pure $ CBOR.deserialiseFromBytes CBOR.decodeTerm $ LBS.fromStrict keyBS+  unless (LBS.null rest) Nothing+  pairs <- case result of+    CBOR.TMap pairs -> return pairs+    _ -> Nothing+  let xKey = -2+  let yKey = -3+  case (CBOR.TInt xKey `lookup` pairs, CBOR.TInt yKey `lookup` pairs) of+    (Just (CBOR.TBytes x), Just (CBOR.TBytes y)) -> do+      pure (x, y)+    _ -> Nothing
src/Crypto/WebAuthn/AttestationStatementFormat/Packed.hs view
@@ -15,9 +15,9 @@ import qualified Codec.CBOR.Term as CBOR import Control.Exception (Exception) import Control.Monad (forM, unless, when)-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import Crypto.WebAuthn.Internal.Utils (IdFidoGenCeAAGUID (IdFidoGenCeAAGUID), failure) import Crypto.WebAuthn.Model (AAGUID) import qualified Crypto.WebAuthn.Model.Types as M@@ -141,12 +141,12 @@         Nothing -> do           -- Validate that alg matches the algorithm of the credentialPublicKey in authenticatorData.           let key = M.acdCredentialPublicKey credData-              signAlg = Cose.keySignAlg key+              signAlg = Cose.signAlg key           when (stmtAlg /= signAlg) . failure $ AlgorithmMismatch stmtAlg signAlg            -- Verify that sig is a valid signature over the concatenation of           -- authenticatorData and clientDataHash using the credential public key with alg.-          case Cose.verify signAlg (Cose.fromCose key) signedData stmtSig of+          case Cose.verify key signedData stmtSig of             Right () -> pure ()             Left err -> failure $ InvalidSignature err 
src/Crypto/WebAuthn/AttestationStatementFormat/TPM.hs view
@@ -22,9 +22,10 @@ import Crypto.Hash (SHA1 (SHA1), SHA256 (SHA256), hashWith) import qualified Crypto.Hash as Hash import Crypto.Number.Serialize (os2ip)-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKey as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import Crypto.WebAuthn.Internal.Utils (IdFidoGenCeAAGUID (IdFidoGenCeAAGUID), failure) import Crypto.WebAuthn.Model.Identifier (AAGUID) import qualified Crypto.WebAuthn.Model.Types as M@@ -205,9 +206,10 @@  -- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-tpm-attestation) data Statement = Statement-  { alg :: Cose.CoseSignAlg,-    x5c :: NE.NonEmpty X509.SignedCertificate,-    aikCert :: X509.SignedCertificate,+  { x5c :: NE.NonEmpty X509.SignedCertificate,+    aikCert :: X509.Certificate,+    -- Combined aikCert public key and the "alg" statement key+    aikPubKeyAndAlg :: Cose.PublicKeyWithSignAlg,     subjectAlternativeName :: SubjectAlternativeName,     aaguidExt :: Maybe IdFidoGenCeAAGUID,     extendedKeyUsage :: [X509.ExtKeyUsagePurpose],@@ -225,7 +227,7 @@   toJSON Statement {..} =     object       [ "ver" .= String "2.0",-        "alg" .= alg,+        "alg" .= Cose.signAlg aikPubKeyAndAlg,         "x5c" .= x5c,         "sig" .= sig,         "certInfo" .= certInfo,@@ -357,7 +359,7 @@     case (xs !? "ver", xs !? "alg", xs !? "x5c", xs !? "sig", xs !? "certInfo", xs !? "pubArea") of       (Just (CBOR.TString "2.0"), Just (CBOR.TInt algId), Just (CBOR.TList (NE.nonEmpty -> Just x5cRaw)), Just (CBOR.TBytes sig), Just (CBOR.TBytes certInfoRaw), Just (CBOR.TBytes pubAreaRaw)) ->         do-          x5c@(aikCert :| _) <- forM x5cRaw $ \case+          x5c@(signedAikCert :| _) <- forM x5cRaw $ \case             CBOR.TBytes certBytes ->               first (("Failed to decode signed certificate: " <>) . Text.pack) (X509.decodeSignedCertificate certBytes)             cert ->@@ -374,21 +376,24 @@             Right (_, _, res) -> pure res           pubAreaKey <- extractPublicKey pubArea -          let cert = X509.getCertificate aikCert+          let aikCert = X509.getCertificate signedAikCert -          subjectAlternativeName <- case X509.extensionGetE (X509.certExtensions cert) of+          aikCertPubKey <- Cose.fromX509 $ X509.certPubKey aikCert+          aikPubKeyAndAlg <- Cose.makePublicKeyWithSignAlg aikCertPubKey alg++          subjectAlternativeName <- case X509.extensionGetE (X509.certExtensions aikCert) of             Just (Right ext) -> pure ext             Just (Left err) -> Left $ "Failed to decode certificate subject alternative name extension: " <> Text.pack err             Nothing -> Left "Certificate subject alternative name extension is missing"-          aaguidExt <- case X509.extensionGetE (X509.certExtensions cert) of+          aaguidExt <- case X509.extensionGetE (X509.certExtensions aikCert) of             Just (Right ext) -> pure $ Just ext             Just (Left err) -> Left $ "Failed to decode certificate aaguid extension: " <> Text.pack err             Nothing -> pure Nothing-          X509.ExtExtendedKeyUsage extendedKeyUsage <- case X509.extensionGetE (X509.certExtensions cert) of+          X509.ExtExtendedKeyUsage extendedKeyUsage <- case X509.extensionGetE (X509.certExtensions aikCert) of             Just (Right ext) -> pure ext             Just (Left err) -> Left $ "Failed to decode certificate extended key usage extension: " <> Text.pack err             Nothing -> Left "Certificate extended key usage extension is missing"-          X509.ExtBasicConstraints basicConstraintsCA _ <- case X509.extensionGetE (X509.certExtensions cert) of+          X509.ExtBasicConstraints basicConstraintsCA _ <- case X509.extensionGetE (X509.certExtensions aikCert) of             Just (Right ext) -> pure ext             Just (Left err) -> Left $ "Failed to decode certificate basic constraints extension: " <> Text.pack err             Nothing -> Left "Certificate basic constraints extension is missing"@@ -476,7 +481,7 @@             tpmtpParameters = TPMSRSAParms {..},             tpmtpUnique = TPM2BPublicKeyRSA nb           } =-          pure+          Cose.checkPublicKey             Cose.PublicKeyRSA               { rsaN = os2ip nb,                 rsaE = toInteger tpmsrpExponent@@ -487,18 +492,18 @@             tpmtpParameters = TPMSECCParms {..},             tpmtpUnique = TPMSECCPoint {..}           } =-          pure+          Cose.checkPublicKey             Cose.PublicKeyECDSA               { ecdsaCurve = tpmsepCurveId,-                ecdsaX = tpmseX,-                ecdsaY = tpmseY+                ecdsaX = os2ip tpmseX,+                ecdsaY = os2ip tpmseY               }       extractPublicKey key = Left $ "Unsupported TPM public key: " <> Text.pack (show key)    asfEncode _ Statement {..} =     CBOR.TMap       [ (CBOR.TString "ver", CBOR.TString "2.0"),-        (CBOR.TString "alg", CBOR.TInt $ Cose.fromCoseSignAlg alg),+        (CBOR.TString "alg", CBOR.TInt $ Cose.fromCoseSignAlg $ Cose.signAlg aikPubKeyAndAlg),         ( CBOR.TString "x5c",           CBOR.TList $ map (CBOR.TBytes . X509.encodeSignedObject) $ NE.toList x5c         ),@@ -522,7 +527,7 @@       -- 2. Verify that the public key specified by the parameters and unique       -- fields of pubArea is identical to the credentialPublicKey in the       -- attestedCredentialData in authenticatorData.-      let pubKey = Cose.fromCose $ M.acdCredentialPublicKey adAttestedCredentialData+      let pubKey = Cose.publicKey $ M.acdCredentialPublicKey adAttestedCredentialData       unless (pubAreaKey == pubKey) . failure $ PublicKeyMismatch pubAreaKey pubKey        -- 3. Concatenate authenticatorData and clientDataHash to form attToBeSigned.@@ -539,7 +544,7 @@        -- 4.3 Verify that extraData is set to the hash of attToBeSigned using       -- the hash algorithm employed in "alg".-      case hashWithCorrectAlgorithm alg attToBeSigned of+      case hashWithCorrectAlgorithm (Cose.signAlg aikPubKeyAndAlg) attToBeSigned of         Just attHash -> do           let extraData = tpmsaExtraData certInfo           unless (attHash == extraData) . failure $ HashMismatch attHash extraData@@ -580,22 +585,19 @@        -- 4.8 Verify the sig is a valid signature over certInfo using the       -- attestation public key in aikCert with the algorithm specified in alg.-      let unsignedAikCert = X509.getCertificate aikCert-      case Cose.fromX509 $ X509.certPubKey unsignedAikCert of-        Right certPubKey -> case Cose.verify alg certPubKey certInfoRaw sig of-          Right () -> pure ()-          Left err -> failure $ VerificationFailure err-        Left err -> failure $ PublicKeyInvalid err+      case Cose.verify aikPubKeyAndAlg certInfoRaw sig of+        Right () -> pure ()+        Left err -> failure $ VerificationFailure err        -- 4.9 Verify that aikCert meets the requirements in § 8.3.1 TPM Attestation       -- Statement Certificate Requirements.        -- 4.9.1 Version MUST be set to 3.       -- Version ::= INTEGER { v1(0), v2(1), v3(2) }, see https://datatracker.ietf.org/doc/html/rfc5280.html#section-4.1-      let version = X509.certVersion unsignedAikCert+      let version = X509.certVersion aikCert       unless (version == 2) . failure $ CertificateVersionInvalid version       -- 4.9.2. Subject field MUST be set to empty.-      let subject = X509.getDistinguishedElements $ X509.certSubjectDN unsignedAikCert+      let subject = X509.getDistinguishedElements $ X509.certSubjectDN aikCert       unless (null subject) . failure $ SubjectFieldNotEmpty subject       -- 4.9.3 The Subject Alternative Name extension MUST be set as defined in       -- [TPMv2-EK-Profile] section 3.2.9.
− src/Crypto/WebAuthn/Cose/Algorithm.hs
@@ -1,240 +0,0 @@-{-# LANGUAGE PatternSynonyms #-}---- | Stability: experimental--- This module contains definitions for [COSE registry](https://www.iana.org/assignments/cose/cose.xhtml)--- entries that are relevant for Webauthn COSE public keys. All the types in--- this module implement the 'Serialise' class, mapping them to the respective--- CBOR values/labels.------ This modules sometimes uses this--- [CBOR Grammar](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-13#section-1.4)--- to describe CBOR value types corresponding to CBOR parameters-module Crypto.WebAuthn.Cose.Algorithm-  ( -- * COSE Algorithms-    CoseSignAlg-      ( ..,-        CoseAlgorithmEdDSA,-        CoseAlgorithmES256,-        CoseAlgorithmES384,-        CoseAlgorithmES512,-        CoseAlgorithmRS256,-        CoseAlgorithmRS384,-        CoseAlgorithmRS512,-        CoseAlgorithmRS1-      ),-    fromCoseSignAlg,-    toCoseSignAlg,--    -- * Hash Algorithms-    CoseHashAlgECDSA (..),-    CoseHashAlgRSA (..),-  )-where--import Codec.CBOR.Decoding (decodeIntCanonical)-import Codec.CBOR.Encoding (encodeInt)-import Codec.Serialise (Serialise)-import Codec.Serialise.Class (decode, encode)-import Data.Aeson (ToJSON)-import Data.Text (Text)-import qualified Data.Text as Text-import GHC.Generics (Generic)---- | [(spec)](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- All the entries from the [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- limited to the ones that are currently needed for Webauthn. Notably we only--- care about asymmetric signature algorithms-data CoseSignAlg-  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2)-    -- EdDSA-    ---    -- [RFC8032](https://datatracker.ietf.org/doc/html/rfc8032) describes the elliptic curve signature scheme Edwards-curve-    -- Digital Signature Algorithm (EdDSA).  In that document, the signature-    -- algorithm is instantiated using parameters for edwards25519 and-    -- edwards448 curves.  The document additionally describes two variants-    -- of the EdDSA algorithm: Pure EdDSA, where no hash function is applied-    -- to the content before signing, and HashEdDSA, where a hash function-    -- is applied to the content before signing and the result of that hash-    -- function is signed.  For EdDSA, the content to be signed (either the-    -- message or the pre-hash value) is processed twice inside of the-    -- signature algorithm.  For use with COSE, only the pure EdDSA version-    -- is used.-    ---    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2.1)-    CoseSignAlgEdDSA-  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)-    -- ECDSA-    ---    -- ECDSA [DSS] defines a signature algorithm using ECC.  Implementations-    -- SHOULD use a deterministic version of ECDSA such as the one defined-    -- in [RFC6979].-    ---    -- The ECDSA signature algorithm is parameterized with a hash function-    -- (h).  In the event that the length of the hash function output is-    -- greater than the group of the key, the leftmost bytes of the hash-    -- output are used.-    -- ECDSA w/ SHA-256-    ---    -- This document defines ECDSA to work only with the curves P-256,-    -- P-384, and P-521. Future documents may define it to work with other-    -- curves and points in the future.-    ---    -- In order to promote interoperability, it is suggested that SHA-256 be-    -- used only with curve P-256, SHA-384 be used only with curve P-384,-    -- and SHA-512 be used with curve P-521.  This is aligned with the-    -- recommendation in [Section 4 of RFC5480](https://datatracker.ietf.org/doc/html/rfc5480#section-4)-    ---    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1.1)-    CoseSignAlgECDSA CoseHashAlgECDSA-  | -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)-    -- The RSASSA-PKCS1-v1_5 signature algorithm is defined in-    -- [RFC8017](https://www.rfc-editor.org/rfc/rfc8812.html#RFC8017).-    -- The RSASSA-PKCS1-v1_5 signature algorithm is parameterized with a hash function (h).-    ---    -- A key of size 2048 bits or larger MUST be used with these algorithms.-    ---    -- Security considerations are [here](https://www.rfc-editor.org/rfc/rfc8812.html#section-5)-    CoseSignAlgRSA CoseHashAlgRSA-  deriving (Eq, Show, Ord, Generic, ToJSON)---- | Hash algorithms that can be used with the ECDSA signature algorithm-data CoseHashAlgECDSA-  = -- | SHA-256-    CoseHashAlgECDSASHA256-  | -- | SHA-384-    CoseHashAlgECDSASHA384-  | -- | SHA-512-    CoseHashAlgECDSASHA512-  deriving (Eq, Show, Ord, Enum, Bounded, Generic, ToJSON)---- | Hash algorithms that can be used with the RSA signature algorithm-data CoseHashAlgRSA-  = -- | SHA-1 (deprecated)-    CoseHashAlgRSASHA1-  | -- | SHA-256-    CoseHashAlgRSASHA256-  | -- | SHA-384-    CoseHashAlgRSASHA384-  | -- | SHA-512-    CoseHashAlgRSASHA512-  deriving (Eq, Show, Ord, Enum, Bounded, Generic, ToJSON)---- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @EdDSA@. Alias for 'CoseSignAlgEdDSA'------ * Name: EdDSA--- * Description: EdDSA--- * Recommended: Yes-pattern CoseAlgorithmEdDSA :: CoseSignAlg-pattern CoseAlgorithmEdDSA = CoseSignAlgEdDSA---- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @ES256@. Alias for @'CoseSignAlgECDSA' 'CoseHashAlgECDSASHA256'@------ * Name: ES256--- * Description: ECDSA w/ SHA-256--- * Recommended: Yes-pattern CoseAlgorithmES256 :: CoseSignAlg-pattern CoseAlgorithmES256 = CoseSignAlgECDSA CoseHashAlgECDSASHA256---- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @ES384@. Alias for @'CoseSignAlgECDSA' 'CoseHashAlgECDSASHA384'@------ * Name: ES384--- * Description: ECDSA w/ SHA-384--- * Recommended: Yes-pattern CoseAlgorithmES384 :: CoseSignAlg-pattern CoseAlgorithmES384 = CoseSignAlgECDSA CoseHashAlgECDSASHA384---- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @ES512@. Alias for @'CoseSignAlgECDSA' 'CoseHashAlgECDSASHA512'@------ * Name: ES512--- * Description: ECDSA w/ SHA-512--- * Recommended: Yes-pattern CoseAlgorithmES512 :: CoseSignAlg-pattern CoseAlgorithmES512 = CoseSignAlgECDSA CoseHashAlgECDSASHA512---- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @RS256@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA256'@------ * Name: RS256--- * Description: RSASSA-PKCS1-v1_5 using SHA-256--- * Recommended: No-pattern CoseAlgorithmRS256 :: CoseSignAlg-pattern CoseAlgorithmRS256 = CoseSignAlgRSA CoseHashAlgRSASHA256---- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @RS384@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA384'@------ * Name: RS384--- * Description: RSASSA-PKCS1-v1_5 using SHA-384--- * Recommended: No-pattern CoseAlgorithmRS384 :: CoseSignAlg-pattern CoseAlgorithmRS384 = CoseSignAlgRSA CoseHashAlgRSASHA384---- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @RS512@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA512'@------ * Name: RS512--- * Description: RSASSA-PKCS1-v1_5 using SHA-512--- * Recommended: No-pattern CoseAlgorithmRS512 :: CoseSignAlg-pattern CoseAlgorithmRS512 = CoseSignAlgRSA CoseHashAlgRSASHA512---- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)--- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)--- entry @RS1@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA1'@------ * Name: RS1--- * Description: RSASSA-PKCS1-v1_5 using SHA-1--- * Recommended: Deprecated-pattern CoseAlgorithmRS1 :: CoseSignAlg-pattern CoseAlgorithmRS1 = CoseSignAlgRSA CoseHashAlgRSASHA1---- | Serialises COSE Algorithms using the @Value@ column from the--- [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms).--- This uses the 'fromCoseSignAlg' and 'toCoseSignAlg' functions to do the--- encoding and decoding respectively.-instance Serialise CoseSignAlg where-  encode = encodeInt . fromCoseSignAlg-  decode = do-    int <- decodeIntCanonical-    case toCoseSignAlg int of-      Right res -> pure res-      Left err -> fail $ Text.unpack err---- | Converts a 'CoseSignAlg' to the corresponding integer value from the--- [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms).--- The inverse operation is 'toCoseSignAlg'-fromCoseSignAlg :: Num p => CoseSignAlg -> p-fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA1) = -65535-fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA512) = -259-fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA384) = -258-fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA256) = -257-fromCoseSignAlg (CoseSignAlgECDSA CoseHashAlgECDSASHA512) = -36-fromCoseSignAlg (CoseSignAlgECDSA CoseHashAlgECDSASHA384) = -35-fromCoseSignAlg CoseSignAlgEdDSA = -8-fromCoseSignAlg (CoseSignAlgECDSA CoseHashAlgECDSASHA256) = -7---- | Converts an integer value to the corresponding 'CoseSignAlg' from the--- [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms).--- Returns an error if the integer doesn't represent a known algorithm.--- The inverse operation is 'fromCoseSignAlg'-toCoseSignAlg :: (Eq a, Num a, Show a) => a -> Either Text CoseSignAlg-toCoseSignAlg (-65535) = pure (CoseSignAlgRSA CoseHashAlgRSASHA1)-toCoseSignAlg (-259) = pure (CoseSignAlgRSA CoseHashAlgRSASHA512)-toCoseSignAlg (-258) = pure (CoseSignAlgRSA CoseHashAlgRSASHA384)-toCoseSignAlg (-257) = pure (CoseSignAlgRSA CoseHashAlgRSASHA256)-toCoseSignAlg (-36) = pure (CoseSignAlgECDSA CoseHashAlgECDSASHA512)-toCoseSignAlg (-35) = pure (CoseSignAlgECDSA CoseHashAlgECDSASHA384)-toCoseSignAlg (-8) = pure CoseSignAlgEdDSA-toCoseSignAlg (-7) = pure (CoseSignAlgECDSA CoseHashAlgECDSASHA256)-toCoseSignAlg value = Left $ "Unknown COSE algorithm value " <> Text.pack (show value)
src/Crypto/WebAuthn/Cose/Internal/Verify.hs view
@@ -11,19 +11,17 @@ -- * 'Cose.CosePublicKey', which is a combination of a 'Cose.CoseSignAlg' along with --   a public key that can be used with it. This is what the COSE_Key --   CBOR structure decodes to--- * 'PublicKey', only the public key part of 'Cose.CosePublicKey'+-- * 'Cose.PublicKey', only the public key part of 'Cose.CosePublicKey' -- -- The following main operations are supported for these types: -- -- * 'Cose.CosePublicKey' can be totally decomposed into a 'Cose.CoseSignAlg'---   with 'Cose.keySignAlg' and a 'PublicKey' with 'fromCose'--- * A 'PublicKey' can be created from an X.509 public key with 'fromX509'--- * A 'Cose.CoseSignAlg' and a 'PublicKey' can be used to verify a signature+--   with 'Cose.signAlg' and a 'Cose.PublicKey' with 'Cose.publicKey'+-- * A 'Cose.PublicKey' can be created from an X.509 public key with 'fromX509'+-- * A 'Cose.CoseSignAlg' and a 'Cose.PublicKey' can be used to verify a signature --   with 'verify' module Crypto.WebAuthn.Cose.Internal.Verify   ( -- * Public Key-    PublicKey (..),-    fromCose,     fromX509,      -- * Signature verification@@ -34,205 +32,147 @@     toCryptHashECDSA,     SomeHashAlgorithmASN1 (..),     toCryptHashRSA,--    -- * Conversions from/to cryptonite elliptic curves-    toCryptCurveECDSA,-    fromCryptCurveECDSA,   ) where  import Crypto.Error (CryptoFailable (CryptoFailed, CryptoPassed)) import qualified Crypto.Hash as Hash-import Crypto.Number.Serialize (i2osp, i2ospOf, os2ip)+import Crypto.Number.Serialize (i2osp) import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.Ed25519 as Ed25519 import qualified Crypto.PubKey.RSA as RSA import qualified Crypto.PubKey.RSA.PKCS15 as RSA-import qualified Crypto.WebAuthn.Cose.Algorithm as A-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKey as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import Crypto.WebAuthn.Internal.ToJSONOrphans () import qualified Data.ASN1.BinaryEncoding as ASN1 import qualified Data.ASN1.Encoding as ASN1 import qualified Data.ASN1.Types as ASN1-import Data.Aeson (ToJSON) import Data.ByteArray (convert) import qualified Data.ByteString as BS import Data.Text (Text) import qualified Data.Text as Text import qualified Data.X509 as X509 import qualified Data.X509.EC as X509-import GHC.Generics (Generic) --- | Same as 'Cose.CosePublicKey', but without signature algorithm parameters, i.e.--- hash algorithms.-data PublicKey-  = -- | See 'Cose.CosePublicKeyEdDSA'-    PublicKeyEdDSA-      { -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)-        -- The elliptic curve to use-        eddsaCurve :: Cose.CoseCurveEdDSA,-        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)-        -- This contains the public key bytes-        eddsaX :: BS.ByteString-      }-  | -- | See 'Cose.CosePublicKeyECDSA'-    PublicKeyECDSA-      { -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)-        -- The elliptic curve to use-        ecdsaCurve :: Cose.CoseCurveECDSA,-        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)-        -- This contains the x-coordinate for the EC point. The integer is-        -- converted to a byte string as defined in [SEC1]. Leading zero-        -- octets MUST be preserved.-        ecdsaX :: BS.ByteString,-        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)-        -- This contains the value of the-        -- y-coordinate for the EC point. When encoding the value y, the-        -- integer is converted to an byte string (as defined in-        -- [SEC1](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#ref-SEC1))-        -- and encoded as a CBOR bstr. Leading zero octets MUST be-        -- preserved.-        ecdsaY :: BS.ByteString-      }-  | -- | See 'Cose.CosePublicKeyRSA'-    PublicKeyRSA-      { -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)-        -- The RSA modulus n is a product of u distinct odd primes-        -- r_i, i = 1, 2, ..., u, where u >= 2-        rsaN :: Integer,-        -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)-        -- The RSA public exponent e is an integer between 3 and n - 1 satisfying-        -- GCD(e,\\lambda(n)) = 1, where \\lambda(n) = LCM(r_1 - 1, ..., r_u - 1)-        rsaE :: Integer-      }-  deriving (Eq, Show, Generic, ToJSON)---- | Turns a 'Cose.CosePublicKey' into a 'PublicKey' by removing the hash functions-fromCose :: Cose.CosePublicKey -> PublicKey-fromCose Cose.CosePublicKeyEdDSA {..} = PublicKeyEdDSA {..}-fromCose Cose.CosePublicKeyECDSA {..} = PublicKeyECDSA {..}-fromCose Cose.CosePublicKeyRSA {..} = PublicKeyRSA {..}---- | Turns a X.509 certificates 'X509.PubKey' into a 'PublicKey'-fromX509 :: X509.PubKey -> Either Text PublicKey+-- | Turns a X.509 certificates 'X509.PubKey' into a 'Cose.PublicKey'+fromX509 :: X509.PubKey -> Either Text Cose.PublicKey fromX509 (X509.PubKeyEd25519 key) =-  Right $-    PublicKeyEdDSA+  Cose.checkPublicKey+    Cose.PublicKeyEdDSA       { eddsaCurve = Cose.CoseCurveEd25519,         eddsaX = convert key       } fromX509 (X509.PubKeyEC X509.PubKeyEC_Named {..}) = do   let curve = ECC.getCurveByName pubkeyEC_name-  ecdsaCurve <- fromCryptCurveECDSA pubkeyEC_name+  ecdsaCurve <- Cose.fromCryptCurveECDSA pubkeyEC_name   point <- case X509.unserializePoint curve pubkeyEC_pub of     Nothing -> Left "Failed to unserialize ECDSA point in X509 certificate"     Just res -> pure res-  -- Round up to a full byte-  let byteSize = (ECC.curveSizeBits curve + 7) `div` 8-  case point of-    ECC.Point x y -> do-      ecdsaX <- case i2ospOf byteSize x of-        Nothing -> Left $ "Failed to convert ECDSA x coordinate integer " <> Text.pack (show x) <> " to bytes of size " <> Text.pack (show byteSize)-        Just res -> pure res-      ecdsaY <- case i2ospOf byteSize y of-        Nothing -> Left $ "Failed to convert ECDSA y coordinate integer " <> Text.pack (show y) <> " to bytes of size " <> Text.pack (show byteSize)-        Just res -> pure res-      Right $ PublicKeyECDSA {..}+  unchecked <- case point of+    ECC.Point ecdsaX ecdsaY -> Right $ Cose.PublicKeyECDSA {..}     ECC.PointO -> Left "The infinity point is not supported"+  Cose.checkPublicKey unchecked fromX509 (X509.PubKeyRSA RSA.PublicKey {..}) =-  Right-    PublicKeyRSA+  Cose.checkPublicKey+    Cose.PublicKeyRSA       { rsaN = public_n,         rsaE = public_e       } fromX509 key = Left $ "X509 public key algorithm is not supported: " <> Text.pack (show (X509.pubkeyToAlg key)) --- | Verifies an asymmetric signature for a message using a 'Cose.CoseSignAlg'--- and a 'PublicKey'. Returns an error if the signature algorithm doesn't--- match. Also returns an error if the signature wasn't valid or for other--- errors.-verify :: A.CoseSignAlg -> PublicKey -> BS.ByteString -> BS.ByteString -> Either Text ()-verify A.CoseSignAlgEdDSA PublicKeyEdDSA {eddsaCurve = Cose.CoseCurveEd25519, ..} msg sig = do-  key <- case Ed25519.publicKey eddsaX of-    CryptoFailed err -> Left $ "Failed to create Ed25519 public key: " <> Text.pack (show err)-    CryptoPassed res -> pure res-  sig <- case Ed25519.signature sig of-    CryptoFailed err -> Left $ "Failed to create Ed25519 signature: " <> Text.pack (show err)-    CryptoPassed res -> pure res-  if Ed25519.verify key msg sig-    then Right ()-    else Left "EdDSA Signature invalid"-verify (A.CoseSignAlgECDSA (toCryptHashECDSA -> SomeHashAlgorithm hash)) PublicKeyECDSA {..} msg sig = do-  let key =-        ECDSA.PublicKey-          { public_curve = ECC.getCurveByName $ toCryptCurveECDSA ecdsaCurve,-            public_q = ECC.Point (os2ip ecdsaX) (os2ip ecdsaY)-          }+-- | Verifies an asymmetric signature for a message using a+-- 'Cose.PublicKeyWithSignAlg' Returns an error if the signature algorithm+-- doesn't match. Also returns an error if the signature wasn't valid or for+-- other errors.+verify :: Cose.PublicKeyWithSignAlg -> BS.ByteString -> BS.ByteString -> Either Text ()+verify+  Cose.PublicKeyWithSignAlg+    { publicKey = Cose.PublicKey Cose.PublicKeyEdDSA {eddsaCurve = Cose.CoseCurveEd25519, ..},+      signAlg = Cose.CoseSignAlgEdDSA+    }+  msg+  sig = do+    key <- case Ed25519.publicKey eddsaX of+      CryptoFailed err -> Left $ "Failed to create Ed25519 public key: " <> Text.pack (show err)+      CryptoPassed res -> pure res+    sig <- case Ed25519.signature sig of+      CryptoFailed err -> Left $ "Failed to create Ed25519 signature: " <> Text.pack (show err)+      CryptoPassed res -> pure res+    if Ed25519.verify key msg sig+      then Right ()+      else Left "EdDSA Signature invalid"+verify+  Cose.PublicKeyWithSignAlg+    { publicKey = Cose.PublicKey Cose.PublicKeyECDSA {..},+      signAlg = Cose.CoseSignAlgECDSA (toCryptHashECDSA -> SomeHashAlgorithm hash)+    }+  msg+  sig = do+    let curveName = Cose.toCryptCurveECDSA ecdsaCurve+        public_curve = ECC.getCurveByName curveName+        public_q = ECC.Point ecdsaX ecdsaY -  -- https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types-  -- > For COSEAlgorithmIdentifier -7 (ES256), and other ECDSA-based algorithms,-  -- the `sig` value MUST be encoded as an ASN.1 DER Ecdsa-Sig-Value, as defined-  -- in [RFC3279](https://www.w3.org/TR/webauthn-2/#biblio-rfc3279) section 2.2.3.-  sig <- case ASN1.decodeASN1' ASN1.DER sig of-    Left err -> Left $ "Failed to decode ECDSA DER value: " <> Text.pack (show err)-    -- Ecdsa-Sig-Value in https://datatracker.ietf.org/doc/html/rfc3279#section-2.2.3-    Right [ASN1.Start ASN1.Sequence, ASN1.IntVal r, ASN1.IntVal s, ASN1.End ASN1.Sequence] ->-      pure $ ECDSA.Signature r s-    Right asns -> Left $ "Unexpected ECDSA ASN.1 structure: " <> Text.pack (show asns)+    -- This check is already done in checkPublicKey+    --unless (ECC.isPointValid public_curve public_q) $+    --  Left $ "ECDSA point is not valid for curve " <> Text.pack (show curveName) <> ": " <> Text.pack (show public_q)+    let key = ECDSA.PublicKey {..} -  if ECDSA.verify hash key sig msg-    then Right ()-    else Left "ECDSA Signature invalid"-verify (A.CoseSignAlgRSA (toCryptHashRSA -> SomeHashAlgorithmASN1 hash)) PublicKeyRSA {..} msg sig = do-  let key =-        RSA.PublicKey-          { -- https://www.rfc-editor.org/rfc/rfc8017#section-8.2.2-            -- > k is the length in octets of the RSA modulus n-            ---            -- > Length checking: If the length of the signature S is not k-            -- > octets, output "invalid signature" and stop.-            -- This is done by the RSA.verify call-            public_size = BS.length (i2osp rsaN),-            public_n = rsaN,-            public_e = rsaE-          }-  if RSA.verify (Just hash) key msg sig-    then Right ()-    else Left "RSA Signature invalid"-verify sigAlg pubKey _ _ =-  Left $ "Unsupported combination of signature algorithm " <> Text.pack (show sigAlg) <> " and public key " <> Text.pack (show pubKey)+    -- https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types+    -- > For COSEAlgorithmIdentifier -7 (ES256), and other ECDSA-based algorithms,+    -- the `sig` value MUST be encoded as an ASN.1 DER Ecdsa-Sig-Value, as defined+    -- in [RFC3279](https://www.w3.org/TR/webauthn-2/#biblio-rfc3279) section 2.2.3.+    sig <- case ASN1.decodeASN1' ASN1.DER sig of+      Left err -> Left $ "Failed to decode ECDSA DER value: " <> Text.pack (show err)+      -- Ecdsa-Sig-Value in https://datatracker.ietf.org/doc/html/rfc3279#section-2.2.3+      Right [ASN1.Start ASN1.Sequence, ASN1.IntVal r, ASN1.IntVal s, ASN1.End ASN1.Sequence] ->+        pure $ ECDSA.Signature r s+      Right asns -> Left $ "Unexpected ECDSA ASN.1 structure: " <> Text.pack (show asns) +    if ECDSA.verify hash key sig msg+      then Right ()+      else Left "ECDSA Signature invalid"+verify+  Cose.PublicKeyWithSignAlg+    { publicKey = Cose.PublicKey Cose.PublicKeyRSA {..},+      signAlg = Cose.CoseSignAlgRSA (toCryptHashRSA -> SomeHashAlgorithmASN1 hash)+    }+  msg+  sig = do+    let key =+          RSA.PublicKey+            { -- https://www.rfc-editor.org/rfc/rfc8017#section-8.2.2+              -- > k is the length in octets of the RSA modulus n+              --+              -- > Length checking: If the length of the signature S is not k+              -- > octets, output "invalid signature" and stop.+              -- This is done by the RSA.verify call+              public_size = BS.length (i2osp rsaN),+              public_n = rsaN,+              public_e = rsaE+            }+    if RSA.verify (Just hash) key msg sig+      then Right ()+      else Left "RSA Signature invalid"+verify key _ _ = error $ "PublicKeyWithSignAlg invariant violated for public key " <> show key <> ". This should not occur unless the PublicKeyWithSignAlg module has a bug"+ -- | Some cryptonite 'Hash.HashAlgorithm' type, used as a return value of 'toCryptHashECDSA' data SomeHashAlgorithm = forall a. Hash.HashAlgorithm a => SomeHashAlgorithm a  -- | Returns the cryptonite 'SomeHashAlgorithm' corresponding to this hash algorithm-toCryptHashECDSA :: A.CoseHashAlgECDSA -> SomeHashAlgorithm-toCryptHashECDSA A.CoseHashAlgECDSASHA256 = SomeHashAlgorithm Hash.SHA256-toCryptHashECDSA A.CoseHashAlgECDSASHA384 = SomeHashAlgorithm Hash.SHA384-toCryptHashECDSA A.CoseHashAlgECDSASHA512 = SomeHashAlgorithm Hash.SHA512+toCryptHashECDSA :: Cose.CoseHashAlgECDSA -> SomeHashAlgorithm+toCryptHashECDSA Cose.CoseHashAlgECDSASHA256 = SomeHashAlgorithm Hash.SHA256+toCryptHashECDSA Cose.CoseHashAlgECDSASHA384 = SomeHashAlgorithm Hash.SHA384+toCryptHashECDSA Cose.CoseHashAlgECDSASHA512 = SomeHashAlgorithm Hash.SHA512  -- | Some cryptonite 'RSA.HashAlgorithmASN1' type, used as a return value of 'toCryptHashRSA' data SomeHashAlgorithmASN1 = forall a. RSA.HashAlgorithmASN1 a => SomeHashAlgorithmASN1 a  -- | Returns the cryptonite 'SomeHashAlgorithmASN1' corresponding to this hash algorithm-toCryptHashRSA :: A.CoseHashAlgRSA -> SomeHashAlgorithmASN1-toCryptHashRSA A.CoseHashAlgRSASHA1 = SomeHashAlgorithmASN1 Hash.SHA1-toCryptHashRSA A.CoseHashAlgRSASHA256 = SomeHashAlgorithmASN1 Hash.SHA256-toCryptHashRSA A.CoseHashAlgRSASHA384 = SomeHashAlgorithmASN1 Hash.SHA384-toCryptHashRSA A.CoseHashAlgRSASHA512 = SomeHashAlgorithmASN1 Hash.SHA512---- | Converts a 'Cose.CoseCurveECDSA' to an 'ECC.CurveName'. The inverse--- function is 'fromCryptCurveECDSA'-toCryptCurveECDSA :: Cose.CoseCurveECDSA -> ECC.CurveName-toCryptCurveECDSA Cose.CoseCurveP256 = ECC.SEC_p256r1-toCryptCurveECDSA Cose.CoseCurveP384 = ECC.SEC_p384r1-toCryptCurveECDSA Cose.CoseCurveP521 = ECC.SEC_p521r1---- | Tries to converts a 'ECC.CurveName' to an 'Cose.CoseCurveECDSA'. The inverse--- function is 'toCryptCurveECDSA'-fromCryptCurveECDSA :: ECC.CurveName -> Either Text Cose.CoseCurveECDSA-fromCryptCurveECDSA ECC.SEC_p256r1 = Right Cose.CoseCurveP256-fromCryptCurveECDSA ECC.SEC_p384r1 = Right Cose.CoseCurveP384-fromCryptCurveECDSA ECC.SEC_p521r1 = Right Cose.CoseCurveP521-fromCryptCurveECDSA curve = Left $ "Curve " <> Text.pack (show curve) <> " is not a supported COSE ECDSA public key curve"+toCryptHashRSA :: Cose.CoseHashAlgRSA -> SomeHashAlgorithmASN1+toCryptHashRSA Cose.CoseHashAlgRSASHA1 = SomeHashAlgorithmASN1 Hash.SHA1+toCryptHashRSA Cose.CoseHashAlgRSASHA256 = SomeHashAlgorithmASN1 Hash.SHA256+toCryptHashRSA Cose.CoseHashAlgRSASHA384 = SomeHashAlgorithmASN1 Hash.SHA384+toCryptHashRSA Cose.CoseHashAlgRSASHA512 = SomeHashAlgorithmASN1 Hash.SHA512
− src/Crypto/WebAuthn/Cose/Key.hs
@@ -1,297 +0,0 @@-{-# LANGUAGE RecordWildCards #-}---- | Stability: experimental--- This module contains a partial implementation of the--- [COSE_Key](https://datatracker.ietf.org/doc/html/rfc8152#section-7) format,--- limited to what is needed for Webauthn, and in a structured way.-module Crypto.WebAuthn.Cose.Key-  ( -- * COSE public Key-    CosePublicKey (..),-    keySignAlg,--    -- * COSE Elliptic Curves-    CoseCurveEdDSA (..),-    CoseCurveECDSA (..),-  )-where--import Codec.CBOR.Decoding (Decoder, TokenType (TypeBool, TypeBytes), decodeBytesCanonical, decodeMapLenCanonical, peekTokenType)-import Codec.CBOR.Encoding (Encoding, encodeBytes, encodeMapLen)-import Codec.Serialise (Serialise (decode, encode))-import Control.Monad (unless)-import Crypto.Number.Serialize (i2osp, os2ip)-import qualified Crypto.WebAuthn.Cose.Algorithm as A-import qualified Crypto.WebAuthn.Cose.Internal.Registry as R-import Crypto.WebAuthn.Internal.ToJSONOrphans ()-import Data.Aeson (ToJSON)-import qualified Data.ByteString as BS-import GHC.Generics (Generic)---- | [(spec)](https://www.w3.org/TR/webauthn-2/#credentialpublickey)--- A structured representation of a [COSE_Key](https://datatracker.ietf.org/doc/html/rfc8152#section-7)--- limited to what is know to be necessary for Webauthn public keys for the--- [credentialPublicKey](https://www.w3.org/TR/webauthn-2/#credentialpublickey) field.--- Constructors represent signature algorithms.-data CosePublicKey-  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2)-    -- EdDSA Signature Algorithm-    ---    -- [RFC8032](https://datatracker.ietf.org/doc/html/rfc8032) describes the-    -- elliptic curve signature scheme Edwards-curve-    -- Digital Signature Algorithm (EdDSA). In that document, the signature-    -- algorithm is instantiated using parameters for edwards25519 and-    -- edwards448 curves. The document additionally describes two variants-    -- of the EdDSA algorithm: Pure EdDSA, where no hash function is applied-    -- to the content before signing, and HashEdDSA, where a hash function-    -- is applied to the content before signing and the result of that hash-    -- function is signed. For EdDSA, the content to be signed (either the-    -- message or the pre-hash value) is processed twice inside of the-    -- signature algorithm. For use with COSE, only the pure EdDSA version-    -- is used.-    ---    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2.1)-    CosePublicKeyEdDSA-      { -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)-        -- The elliptic curve to use-        eddsaCurve :: CoseCurveEdDSA,-        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)-        -- This contains the public key bytes-        eddsaX :: BS.ByteString-      }-  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)-    -- ECDSA Signature Algorithm-    ---    -- This document defines ECDSA to work only with the curves P-256,-    -- P-384, and P-521. Future documents may define it to work with other-    -- curves and points in the future.-    ---    -- In order to promote interoperability, it is suggested that SHA-256 be-    -- used only with curve P-256, SHA-384 be used only with curve P-384,-    -- and SHA-512 be used with curve P-521. This is aligned with the recommendation in-    -- [Section 4 of RFC5480](https://datatracker.ietf.org/doc/html/rfc5480#section-4).-    ---    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1.1)-    CosePublicKeyECDSA-      { -- | The hash function to use-        ecdsaHash :: A.CoseHashAlgECDSA,-        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)-        -- The elliptic curve to use-        ecdsaCurve :: CoseCurveECDSA,-        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)-        -- This contains the x-coordinate for the EC point. The integer is-        -- converted to a byte string as defined in [SEC1]. Leading zero-        -- octets MUST be preserved.-        ecdsaX :: BS.ByteString,-        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)-        -- This contains the value of the-        -- y-coordinate for the EC point. When encoding the value y, the-        -- integer is converted to an byte string (as defined in-        -- [SEC1](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#ref-SEC1))-        -- and encoded as a CBOR bstr. Leading zero octets MUST be-        -- preserved.-        ecdsaY :: BS.ByteString-      }-  | -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)-    -- [RSASSA-PKCS1-v1_5](https://www.rfc-editor.org/rfc/rfc8017#section-8.2) Signature Algorithm-    ---    -- A key of size 2048 bits or larger MUST be used with these algorithms.-    -- Security considerations are [here](https://www.rfc-editor.org/rfc/rfc8812.html#section-5)-    CosePublicKeyRSA-      { -- | The hash function to use-        rsaHash :: A.CoseHashAlgRSA,-        -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)-        -- The RSA modulus n is a product of u distinct odd primes-        -- r_i, i = 1, 2, ..., u, where u >= 2-        rsaN :: Integer,-        -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)-        -- The RSA public exponent e is an integer between 3 and n - 1 satisfying-        -- GCD(e,\\lambda(n)) = 1, where \\lambda(n) = LCM(r_1 - 1, ..., r_u - 1)-        rsaE :: Integer-      }-  deriving (Eq, Show, Generic, ToJSON)---- | CBOR encoding as a [COSE_Key](https://tools.ietf.org/html/rfc8152#section-7)--- using the [CTAP2 canonical CBOR encoding form](https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#ctap2-canonical-cbor-encoding-form)-instance Serialise CosePublicKey where-  encode key = case key of-    CosePublicKeyEdDSA {..} ->-      common R.CoseKeyTypeOKP-        <> encode R.CoseKeyTypeParameterOKPCrv-        <> encode (fromCurveEdDSA eddsaCurve)-        <> encode R.CoseKeyTypeParameterOKPX-        <> encodeBytes eddsaX-    CosePublicKeyECDSA {..} ->-      common R.CoseKeyTypeEC2-        <> encode R.CoseKeyTypeParameterEC2Crv-        <> encode (fromCurveECDSA ecdsaCurve)-        -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1-        -- > Leading zero octets MUST be preserved.-        <> encode R.CoseKeyTypeParameterEC2X-        <> encodeBytes ecdsaX-        <> encode R.CoseKeyTypeParameterEC2Y-        <> encodeBytes ecdsaY-    CosePublicKeyRSA {..} ->-      common R.CoseKeyTypeRSA-        -- https://www.rfc-editor.org/rfc/rfc8230.html#section-4-        -- > The octet sequence MUST utilize the minimum-        -- number of octets needed to represent the value.-        <> encode R.CoseKeyTypeParameterRSAN-        <> encodeBytes (i2osp rsaN)-        <> encode R.CoseKeyTypeParameterRSAE-        <> encodeBytes (i2osp rsaE)-    where-      alg = keySignAlg key-      common :: R.CoseKeyType -> Encoding-      common kty =-        encodeMapLen (R.parameterCount kty)-          <> encode R.CoseKeyCommonParameterKty-          <> encode kty-          <> encode R.CoseKeyCommonParameterAlg-          <> encode alg--  -- NOTE: CBOR itself doesn't give an ordering of map keys, but the CTAP2 canonical CBOR encoding form does:-  -- > The keys in every map must be sorted lowest value to highest. The sorting rules are:-  -- >-  -- > * If the major types are different, the one with the lower value in numerical order sorts earlier.-  -- > * If two keys have different lengths, the shorter one sorts earlier;-  -- > * If two keys have the same length, the one with the lower value in (byte-wise) lexical order sorts earlier.-  ---  -- This has the effect that numeric keys are sorted like 1, 2, 3, ..., -1, -2, -3, ...-  -- Which aligns very nicely with the fact that common parameters use positive-  -- values and can therefore be decoded first, while key type specific-  -- parameters use negative values-  decode = do-    n <- fromIntegral <$> decodeMapLenCanonical-    -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-15#section-7.1-    -- This parameter MUST be present in a key object.-    decodeExpected R.CoseKeyCommonParameterKty-    kty <- decode-    -- https://www.w3.org/TR/webauthn-2/#credentialpublickey-    -- The COSE_Key-encoded credential public key MUST contain the "alg"-    -- parameter and MUST NOT contain any other OPTIONAL parameters.-    decodeExpected R.CoseKeyCommonParameterAlg-    alg <- decode--    decodeKey n kty alg-    where-      decodeKey :: Word -> R.CoseKeyType -> A.CoseSignAlg -> Decoder s CosePublicKey-      decodeKey n kty alg = case alg of-        A.CoseSignAlgEdDSA -> decodeEdDSAKey-        A.CoseSignAlgECDSA hash -> decodeECDSAKey hash-        A.CoseSignAlgRSA hash -> decodeRSAKey hash-        where-          -- [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-15#section-7.1)-          -- Implementations MUST verify that the key type is appropriate for-          -- the algorithm being processed.-          checkKty :: R.CoseKeyType -> Decoder s ()-          checkKty expectedKty = do-            unless (expectedKty == kty) $-              fail $-                "Expected COSE key type "-                  <> show expectedKty-                  <> " for COSE algorithm "-                  <> show alg-                  <> " but got COSE key type "-                  <> show kty-                  <> " instead"-            unless (R.parameterCount kty == n) $-              fail $-                "Expected CBOR map to contain "-                  <> show (R.parameterCount kty)-                  <> " parameters for COSE key type "-                  <> show kty-                  <> " but got "-                  <> show n-                  <> " parameters instead"--          decodeEdDSAKey :: Decoder s CosePublicKey-          decodeEdDSAKey = do-            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2-            -- > The 'kty' field MUST be present, and it MUST be 'OKP' (Octet Key Pair).-            checkKty R.CoseKeyTypeOKP-            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2-            decodeExpected R.CoseKeyTypeParameterOKPCrv-            eddsaCurve <- toCurveEdDSA <$> decode-            decodeExpected R.CoseKeyTypeParameterOKPX-            eddsaX <- decodeBytesCanonical-            pure $ CosePublicKeyEdDSA {..}--          decodeECDSAKey :: A.CoseHashAlgECDSA -> Decoder s CosePublicKey-          decodeECDSAKey ecdsaHash = do-            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1-            -- > The 'kty' field MUST be present, and it MUST be 'EC2'.-            checkKty R.CoseKeyTypeEC2-            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1-            decodeExpected R.CoseKeyTypeParameterEC2Crv-            ecdsaCurve <- toCurveECDSA <$> decode-            decodeExpected R.CoseKeyTypeParameterEC2X-            ecdsaX <- decodeBytesCanonical-            decodeExpected R.CoseKeyTypeParameterEC2Y-            ecdsaY <--              peekTokenType >>= \case-                TypeBytes -> decodeBytesCanonical-                -- TODO: Implement this-                TypeBool -> fail "Compressed EC2 y coordinate not yet supported"-                typ -> fail $ "Unexpected type in EC2 y parameter: " <> show typ-            pure $ CosePublicKeyECDSA {..}--          decodeRSAKey :: A.CoseHashAlgRSA -> Decoder s CosePublicKey-          decodeRSAKey rsaHash = do-            -- https://www.rfc-editor.org/rfc/rfc8812.html#section-2-            -- > Implementations need to check that the key type is 'RSA' when creating or verifying a signature.-            checkKty R.CoseKeyTypeRSA-            -- https://www.rfc-editor.org/rfc/rfc8230.html#section-4-            decodeExpected R.CoseKeyTypeParameterRSAN-            rsaN <- os2ip <$> decodeBytesCanonical-            decodeExpected R.CoseKeyTypeParameterRSAE-            rsaE <- os2ip <$> decodeBytesCanonical-            pure $ CosePublicKeyRSA {..}---- | Decode a value and ensure it's the same as the value that was given-decodeExpected :: (Show a, Eq a, Serialise a) => a -> Decoder s ()-decodeExpected expected = do-  actual <- decode-  unless (expected == actual) $-    fail $ "Expected " <> show expected <> " but got " <> show actual---- | The COSE signing algorithm corresponding to a COSE public key-keySignAlg :: CosePublicKey -> A.CoseSignAlg-keySignAlg CosePublicKeyEdDSA {} = A.CoseSignAlgEdDSA-keySignAlg CosePublicKeyECDSA {..} = A.CoseSignAlgECDSA ecdsaHash-keySignAlg CosePublicKeyRSA {..} = A.CoseSignAlgRSA rsaHash---- | COSE elliptic curves that can be used with EdDSA-data CoseCurveEdDSA-  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)-    -- Ed25519 for use w/ EdDSA only-    CoseCurveEd25519-  deriving (Eq, Show, Enum, Bounded, Generic, ToJSON)--fromCurveEdDSA :: CoseCurveEdDSA -> R.CoseEllipticCurveOKP-fromCurveEdDSA CoseCurveEd25519 = R.CoseEllipticCurveEd25519--toCurveEdDSA :: R.CoseEllipticCurveOKP -> CoseCurveEdDSA-toCurveEdDSA R.CoseEllipticCurveEd25519 = CoseCurveEd25519---- | COSE elliptic curves that can be used with ECDSA-data CoseCurveECDSA-  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)-    -- NIST P-256 also known as secp256r1-    CoseCurveP256-  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)-    -- NIST P-384 also known as secp384r1-    CoseCurveP384-  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)-    -- NIST P-521 also known as secp521r1-    CoseCurveP521-  deriving (Eq, Show, Enum, Bounded, Generic, ToJSON)--fromCurveECDSA :: CoseCurveECDSA -> R.CoseEllipticCurveEC2-fromCurveECDSA CoseCurveP256 = R.CoseEllipticCurveEC2P256-fromCurveECDSA CoseCurveP384 = R.CoseEllipticCurveEC2P384-fromCurveECDSA CoseCurveP521 = R.CoseEllipticCurveEC2P521--toCurveECDSA :: R.CoseEllipticCurveEC2 -> CoseCurveECDSA-toCurveECDSA R.CoseEllipticCurveEC2P256 = CoseCurveP256-toCurveECDSA R.CoseEllipticCurveEC2P384 = CoseCurveP384-toCurveECDSA R.CoseEllipticCurveEC2P521 = CoseCurveP521
+ src/Crypto/WebAuthn/Cose/PublicKey.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RecordWildCards #-}++-- | Stability: experimental+-- This module contains a partial implementation of the+-- [COSE_Key](https://datatracker.ietf.org/doc/html/rfc8152#section-7) format,+-- limited to what is needed for Webauthn, and in a structured way.+module Crypto.WebAuthn.Cose.PublicKey+  ( -- * Public key+    UncheckedPublicKey (..),+    checkPublicKey,+    PublicKey (PublicKey),++    -- * COSE Elliptic Curves+    CoseCurveEdDSA (..),+    coordinateSizeEdDSA,+    CoseCurveECDSA (..),+    toCryptCurveECDSA,+    fromCryptCurveECDSA,+    coordinateSizeECDSA,+  )+where++import qualified Crypto.PubKey.ECC.Prim as ECC+import qualified Crypto.PubKey.ECC.Types as ECC+import qualified Crypto.PubKey.Ed25519 as Ed25519+import Crypto.WebAuthn.Internal.ToJSONOrphans ()+import Data.Aeson (ToJSON)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Base16 as Base16+import Data.Text (Text)+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import GHC.Generics (Generic)++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#credentialpublickey)+-- A structured representation of a [COSE_Key](https://datatracker.ietf.org/doc/html/rfc8152#section-7)+-- limited to what is know to be necessary for Webauthn public keys for the+-- [credentialPublicKey](https://www.w3.org/TR/webauthn-2/#credentialpublickey) field,+-- and without any signing algorithm parameters like hashes. Due to the raw+-- nature of parameters, this type is labeled as unchecked. Parameters are+-- checked by using the 'checkPublicKey' function, returning a t'PublicKey'+-- type.+data UncheckedPublicKey+  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2)+    -- EdDSA Signature Algorithm+    --+    -- [RFC8032](https://datatracker.ietf.org/doc/html/rfc8032) describes the+    -- elliptic curve signature scheme Edwards-curve+    -- Digital Signature Algorithm (EdDSA). In that document, the signature+    -- algorithm is instantiated using parameters for edwards25519 and+    -- edwards448 curves. The document additionally describes two variants+    -- of the EdDSA algorithm: Pure EdDSA, where no hash function is applied+    -- to the content before signing, and HashEdDSA, where a hash function+    -- is applied to the content before signing and the result of that hash+    -- function is signed. For EdDSA, the content to be signed (either the+    -- message or the pre-hash value) is processed twice inside of the+    -- signature algorithm. For use with COSE, only the pure EdDSA version+    -- is used.+    --+    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2.1)+    PublicKeyEdDSA+      { -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)+        -- The elliptic curve to use+        eddsaCurve :: CoseCurveEdDSA,+        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)+        -- This contains the public key bytes.+        eddsaX :: BS.ByteString+      }+  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)+    -- ECDSA Signature Algorithm+    --+    -- This document defines ECDSA to work only with the curves P-256,+    -- P-384, and P-521. Future documents may define it to work with other+    -- curves and points in the future.+    --+    -- In order to promote interoperability, it is suggested that SHA-256 be+    -- used only with curve P-256, SHA-384 be used only with curve P-384,+    -- and SHA-512 be used with curve P-521. This is aligned with the recommendation in+    -- [Section 4 of RFC5480](https://datatracker.ietf.org/doc/html/rfc5480#section-4).+    --+    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1.1)+    PublicKeyECDSA+      { -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)+        -- The elliptic curve to use+        ecdsaCurve :: CoseCurveECDSA,+        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)+        -- This contains the x-coordinate for the EC point. The integer is+        -- converted to a byte string as defined in [SEC1]. Leading zero+        -- octets MUST be preserved.+        ecdsaX :: Integer,+        -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)+        -- This contains the value of the+        -- y-coordinate for the EC point. When encoding the value y, the+        -- integer is converted to an byte string (as defined in+        -- [SEC1](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#ref-SEC1))+        -- and encoded as a CBOR bstr. Leading zero octets MUST be+        -- preserved.+        ecdsaY :: Integer+      }+  | -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)+    -- [RSASSA-PKCS1-v1_5](https://www.rfc-editor.org/rfc/rfc8017#section-8.2) Signature Algorithm+    --+    -- A key of size 2048 bits or larger MUST be used with these algorithms.+    -- Security considerations are [here](https://www.rfc-editor.org/rfc/rfc8812.html#section-5)+    PublicKeyRSA+      { -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)+        -- The RSA modulus n is a product of u distinct odd primes+        -- r_i, i = 1, 2, ..., u, where u >= 2+        rsaN :: Integer,+        -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)+        -- The RSA public exponent e is an integer between 3 and n - 1 satisfying+        -- GCD(e,\\lambda(n)) = 1, where \\lambda(n) = LCM(r_1 - 1, ..., r_u - 1)+        rsaE :: Integer+      }+  deriving (Eq, Show, Generic, ToJSON)++-- | Same as 'UncheckedPublicKey', but checked to be valid using+-- 'checkPublicKey'.+newtype PublicKey = CheckedPublicKey UncheckedPublicKey+  deriving newtype (Eq, Show, ToJSON)++-- | Returns the 'UncheckedPublicKey' for a t'PublicKey'+pattern PublicKey :: UncheckedPublicKey -> PublicKey+pattern PublicKey k <- CheckedPublicKey k++{-# COMPLETE PublicKey #-}++-- | Checks whether an 'UncheckedPublicKey' is valid. This is the only way to construct a t'PublicKey'+checkPublicKey :: UncheckedPublicKey -> Either Text PublicKey+checkPublicKey key@PublicKeyEdDSA {..}+  | actualSize == expectedSize = Right $ CheckedPublicKey key+  | otherwise =+    Left $+      "EdDSA public key for curve "+        <> Text.pack (show eddsaCurve)+        <> " didn't have the expected size of "+        <> Text.pack (show expectedSize)+        <> " bytes, it has "+        <> Text.pack (show actualSize)+        <> " bytes instead: "+        <> Text.decodeUtf8 (Base16.encode eddsaX)+  where+    actualSize = BS.length eddsaX+    expectedSize = coordinateSizeEdDSA eddsaCurve+checkPublicKey key@PublicKeyECDSA {..}+  | ECC.isPointValid curve point = Right $ CheckedPublicKey key+  | otherwise =+    Left $+      "ECDSA public key point is not valid for curve "+        <> Text.pack (show ecdsaCurve)+        <> ": "+        <> Text.pack (show point)+  where+    curve = ECC.getCurveByName (toCryptCurveECDSA ecdsaCurve)+    point = ECC.Point ecdsaX ecdsaY+checkPublicKey key = Right $ CheckedPublicKey key++-- | COSE elliptic curves that can be used with EdDSA+data CoseCurveEdDSA+  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)+    -- Ed25519 for use w/ EdDSA only+    CoseCurveEd25519+  deriving (Eq, Show, Enum, Bounded, Generic, ToJSON)++-- | Returns the size of a coordinate point for a specific EdDSA curve in bytes.+coordinateSizeEdDSA :: CoseCurveEdDSA -> Int+coordinateSizeEdDSA CoseCurveEd25519 = Ed25519.publicKeySize++-- | COSE elliptic curves that can be used with ECDSA+data CoseCurveECDSA+  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)+    -- NIST P-256 also known as secp256r1+    CoseCurveP256+  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)+    -- NIST P-384 also known as secp384r1+    CoseCurveP384+  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)+    -- NIST P-521 also known as secp521r1+    CoseCurveP521+  deriving (Eq, Show, Enum, Bounded, Generic, ToJSON)++-- | Converts a 'Cose.CoseCurveECDSA' to an 'ECC.CurveName'. The inverse+-- function is 'fromCryptCurveECDSA'+toCryptCurveECDSA :: CoseCurveECDSA -> ECC.CurveName+toCryptCurveECDSA CoseCurveP256 = ECC.SEC_p256r1+toCryptCurveECDSA CoseCurveP384 = ECC.SEC_p384r1+toCryptCurveECDSA CoseCurveP521 = ECC.SEC_p521r1++-- | Tries to converts a 'ECC.CurveName' to an 'Cose.CoseCurveECDSA'. The inverse+-- function is 'toCryptCurveECDSA'+fromCryptCurveECDSA :: ECC.CurveName -> Either Text CoseCurveECDSA+fromCryptCurveECDSA ECC.SEC_p256r1 = Right CoseCurveP256+fromCryptCurveECDSA ECC.SEC_p384r1 = Right CoseCurveP384+fromCryptCurveECDSA ECC.SEC_p521r1 = Right CoseCurveP521+fromCryptCurveECDSA curve =+  Left $+    "Curve "+      <> Text.pack (show curve)+      <> " is not a supported COSE ECDSA public key curve"++-- | Returns the size of a coordinate point for a specific ECDSA curve in bytes.+coordinateSizeECDSA :: CoseCurveECDSA -> Int+coordinateSizeECDSA curve = byteSize+  where+    bitSize = ECC.curveSizeBits (ECC.getCurveByName (toCryptCurveECDSA curve))+    byteSize = (bitSize + 7) `div` 8
+ src/Crypto/WebAuthn/Cose/PublicKeyWithSignAlg.hs view
@@ -0,0 +1,281 @@+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeSynonymInstances #-}++-- | Stability: experimental+-- This module contains a partial implementation of the+-- [COSE_Key](https://datatracker.ietf.org/doc/html/rfc8152#section-7) format,+-- limited to what is needed for Webauthn, and in a structured way.+module Crypto.WebAuthn.Cose.PublicKeyWithSignAlg+  ( -- * COSE public Key+    PublicKeyWithSignAlg (PublicKeyWithSignAlg, Crypto.WebAuthn.Cose.PublicKeyWithSignAlg.publicKey, signAlg),+    CosePublicKey,+    makePublicKeyWithSignAlg,+  )+where++import Codec.CBOR.Decoding (Decoder, TokenType (TypeBool, TypeBytes), decodeBytesCanonical, decodeMapLenCanonical, peekTokenType)+import Codec.CBOR.Encoding (Encoding, encodeBytes, encodeMapLen)+import Codec.Serialise (Serialise (decode, encode))+import Control.Monad (unless)+import Crypto.Number.Serialize (i2osp, i2ospOf_, os2ip)+import qualified Crypto.WebAuthn.Cose.Internal.Registry as R+import qualified Crypto.WebAuthn.Cose.PublicKey as P+import qualified Crypto.WebAuthn.Cose.SignAlg as A+import Crypto.WebAuthn.Internal.ToJSONOrphans ()+import qualified Data.Aeson as Aeson+import qualified Data.ByteString as BS+import Data.Functor (($>))+import Data.Text (Text)+import qualified Data.Text as Text+import GHC.Generics (Generic)++-- | A combination of a t'P.PublicKey' holding the public key data and a+-- 'A.CoseSignAlg' holding the exact signature algorithm that should be used.+-- This type can only be constructed with 'makePublicKeyWithSignAlg', which+-- ensures that the signature scheme matches between 'P.PublicKey' and+-- 'A.CoseSignAlg'. This type is equivalent to a COSE public key, which holds+-- the same information, see 'CosePublicKey'+data PublicKeyWithSignAlg = PublicKeyWithSignAlgInternal+  { publicKeyInternal :: P.PublicKey,+    signAlgInternal :: A.CoseSignAlg+    -- TODO: Consider adding a RawField here to replace+    -- acdCredentialPublicKeyBytes. This would then require parametrizing+    -- 'PublicKeyWithSignAlg' with 'raw :: Bool'+  }+  deriving (Eq, Show, Generic, Aeson.ToJSON)++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#credentialpublickey)+-- A structured and checked representation of a+-- [COSE_Key](https://datatracker.ietf.org/doc/html/rfc8152#section-7), limited+-- to what is know to be necessary for Webauthn public keys for the+-- [credentialPublicKey](https://www.w3.org/TR/webauthn-2/#credentialpublickey)+-- field.+type CosePublicKey = PublicKeyWithSignAlg++-- | Deconstructs a 'makePublicKeyWithSignAlg' into its t'P.PublicKey' and+-- 'A.CoseSignAlg'. Since 'makePublicKeyWithSignAlg' can only be constructed+-- using 'makePublicKeyWithSignAlg', we can be sure that the signature scheme+-- of t'P.PublicKey' and 'A.CoseSignAlg' matches.+pattern PublicKeyWithSignAlg :: P.PublicKey -> A.CoseSignAlg -> PublicKeyWithSignAlg+pattern PublicKeyWithSignAlg {publicKey, signAlg} <- PublicKeyWithSignAlgInternal {publicKeyInternal = publicKey, signAlgInternal = signAlg}++{-# COMPLETE PublicKeyWithSignAlg #-}++-- | Constructs a t'PublicKeyWithSignAlg' from a t'P.PublicKey' and+-- 'A.CoseSignAlg', returning an error if the signature schemes between these+-- two types don't match.+makePublicKeyWithSignAlg :: P.PublicKey -> A.CoseSignAlg -> Either Text PublicKeyWithSignAlg+makePublicKeyWithSignAlg key@(P.PublicKey k) alg =+  verifyValid k alg+    $> PublicKeyWithSignAlgInternal+      { publicKeyInternal = key,+        signAlgInternal = alg+      }+  where+    verifyValid :: P.UncheckedPublicKey -> A.CoseSignAlg -> Either Text ()+    verifyValid P.PublicKeyEdDSA {} A.CoseSignAlgEdDSA = pure ()+    verifyValid P.PublicKeyEdDSA {} alg = Left $ "EdDSA public key cannot be used with signing algorithm " <> Text.pack (show alg)+    verifyValid P.PublicKeyECDSA {} A.CoseSignAlgECDSA {} = pure ()+    verifyValid P.PublicKeyECDSA {} alg = Left $ "ECDSA public key cannot be used with signing algorithm " <> Text.pack (show alg)+    verifyValid P.PublicKeyRSA {} A.CoseSignAlgRSA {} = pure ()+    verifyValid P.PublicKeyRSA {} alg = Left $ "RSA public key cannot be used with signing algorithm " <> Text.pack (show alg)++-- | CBOR encoding as a [COSE_Key](https://tools.ietf.org/html/rfc8152#section-7)+-- using the [CTAP2 canonical CBOR encoding form](https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#ctap2-canonical-cbor-encoding-form)+instance Serialise CosePublicKey where+  encode PublicKeyWithSignAlg {..} = case publicKey of+    P.PublicKey P.PublicKeyEdDSA {..} ->+      common R.CoseKeyTypeOKP+        <> encode R.CoseKeyTypeParameterOKPCrv+        <> encode (fromCurveEdDSA eddsaCurve)+        <> encode R.CoseKeyTypeParameterOKPX+        <> encodeBytes eddsaX+    P.PublicKey P.PublicKeyECDSA {..} ->+      common R.CoseKeyTypeEC2+        <> encode R.CoseKeyTypeParameterEC2Crv+        <> encode (fromCurveECDSA ecdsaCurve)+        -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1+        -- > Leading zero octets MUST be preserved.+        <> encode R.CoseKeyTypeParameterEC2X+        -- This version of i2ospOf_ throws if the bytestring is larger than+        -- size, but this can't happen due to the PublicKey invariants+        <> encodeBytes (i2ospOf_ size ecdsaX)+        <> encode R.CoseKeyTypeParameterEC2Y+        <> encodeBytes (i2ospOf_ size ecdsaY)+      where+        size = P.coordinateSizeECDSA ecdsaCurve+    P.PublicKey P.PublicKeyRSA {..} ->+      common R.CoseKeyTypeRSA+        -- https://www.rfc-editor.org/rfc/rfc8230.html#section-4+        -- > The octet sequence MUST utilize the minimum+        -- number of octets needed to represent the value.+        <> encode R.CoseKeyTypeParameterRSAN+        <> encodeBytes (i2osp rsaN)+        <> encode R.CoseKeyTypeParameterRSAE+        <> encodeBytes (i2osp rsaE)+    where+      common :: R.CoseKeyType -> Encoding+      common kty =+        encodeMapLen (R.parameterCount kty)+          <> encode R.CoseKeyCommonParameterKty+          <> encode kty+          <> encode R.CoseKeyCommonParameterAlg+          <> encode signAlg++  -- NOTE: CBOR itself doesn't give an ordering of map keys, but the CTAP2 canonical CBOR encoding form does:+  -- > The keys in every map must be sorted lowest value to highest. The sorting rules are:+  -- >+  -- > * If the major types are different, the one with the lower value in numerical order sorts earlier.+  -- > * If two keys have different lengths, the shorter one sorts earlier;+  -- > * If two keys have the same length, the one with the lower value in (byte-wise) lexical order sorts earlier.+  --+  -- This has the effect that numeric keys are sorted like 1, 2, 3, ..., -1, -2, -3, ...+  -- Which aligns very nicely with the fact that common parameters use positive+  -- values and can therefore be decoded first, while key type specific+  -- parameters use negative values+  decode = do+    n <- fromIntegral <$> decodeMapLenCanonical+    -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-15#section-7.1+    -- This parameter MUST be present in a key object.+    decodeExpected R.CoseKeyCommonParameterKty+    kty <- decode+    -- https://www.w3.org/TR/webauthn-2/#credentialpublickey+    -- The COSE_Key-encoded credential public key MUST contain the "alg"+    -- parameter and MUST NOT contain any other OPTIONAL parameters.+    decodeExpected R.CoseKeyCommonParameterAlg+    alg <- decode++    uncheckedKey <- decodeKey n kty alg+    case P.checkPublicKey uncheckedKey of+      Left err -> fail $ "Key check failed: " <> Text.unpack err+      Right result ->+        pure $+          PublicKeyWithSignAlgInternal+            { publicKeyInternal = result,+              signAlgInternal = alg+            }+    where+      decodeKey :: Word -> R.CoseKeyType -> A.CoseSignAlg -> Decoder s P.UncheckedPublicKey+      decodeKey n kty alg = case alg of+        A.CoseSignAlgEdDSA -> decodeEdDSAKey+        A.CoseSignAlgECDSA _ -> decodeECDSAKey+        A.CoseSignAlgRSA _ -> decodeRSAKey+        where+          -- [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-15#section-7.1)+          -- Implementations MUST verify that the key type is appropriate for+          -- the algorithm being processed.+          checkKty :: R.CoseKeyType -> Decoder s ()+          checkKty expectedKty = do+            unless (expectedKty == kty) $+              fail $+                "Expected COSE key type "+                  <> show expectedKty+                  <> " for COSE algorithm "+                  <> show alg+                  <> " but got COSE key type "+                  <> show kty+                  <> " instead"+            unless (R.parameterCount kty == n) $+              fail $+                "Expected CBOR map to contain "+                  <> show (R.parameterCount kty)+                  <> " parameters for COSE key type "+                  <> show kty+                  <> " but got "+                  <> show n+                  <> " parameters instead"++          decodeEdDSAKey :: Decoder s P.UncheckedPublicKey+          decodeEdDSAKey = do+            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2+            -- > The 'kty' field MUST be present, and it MUST be 'OKP' (Octet Key Pair).+            checkKty R.CoseKeyTypeOKP+            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2+            decodeExpected R.CoseKeyTypeParameterOKPCrv+            eddsaCurve <- toCurveEdDSA <$> decode+            decodeExpected R.CoseKeyTypeParameterOKPX+            eddsaX <- decodeBytesCanonical+            pure P.PublicKeyEdDSA {..}++          decodeECDSAKey :: Decoder s P.UncheckedPublicKey+          decodeECDSAKey = do+            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1+            -- > The 'kty' field MUST be present, and it MUST be 'EC2'.+            checkKty R.CoseKeyTypeEC2+            -- https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1+            decodeExpected R.CoseKeyTypeParameterEC2Crv+            ecdsaCurve <- toCurveECDSA <$> decode+            let size = P.coordinateSizeECDSA ecdsaCurve+            decodeExpected R.CoseKeyTypeParameterEC2X+            ecdsaX <- os2ipWithSize size =<< decodeBytesCanonical++            decodeExpected R.CoseKeyTypeParameterEC2Y+            ecdsaY <-+              peekTokenType >>= \case+                TypeBytes -> os2ipWithSize size =<< decodeBytesCanonical+                TypeBool -> fail "Compressed EC2 y coordinate not yet supported"+                typ -> fail $ "Unexpected type in EC2 y parameter: " <> show typ++            pure P.PublicKeyECDSA {..}++          decodeRSAKey :: Decoder s P.UncheckedPublicKey+          decodeRSAKey = do+            -- https://www.rfc-editor.org/rfc/rfc8812.html#section-2+            -- > Implementations need to check that the key type is 'RSA' when creating or verifying a signature.+            checkKty R.CoseKeyTypeRSA+            -- https://www.rfc-editor.org/rfc/rfc8230.html#section-4+            decodeExpected R.CoseKeyTypeParameterRSAN+            -- > The octet sequence MUST utilize the minimum number of octets needed to represent the value.+            rsaN <- os2ipNoLeading =<< decodeBytesCanonical+            decodeExpected R.CoseKeyTypeParameterRSAE+            rsaE <- os2ipNoLeading =<< decodeBytesCanonical+            pure P.PublicKeyRSA {..}++-- | Same as 'os2ip', but throws an error if there are not exactly as many bytes as expected. Thus any successful result of this function will give the same 'BS.ByteString' back if encoded with @'i2ospOf_' size@.+os2ipWithSize :: MonadFail m => Int -> BS.ByteString -> m Integer+os2ipWithSize size bytes+  | BS.length bytes == size = pure $ os2ip bytes+  | otherwise =+    fail $+      "bytes have length " <> show (BS.length bytes)+        <> " when length "+        <> show size+        <> " was expected"++-- | Same as 'os2ip', but throws an error if there are leading zero bytes. Thus any successful result of this function will give the same 'BS.ByteString' back if encoded with 'i2osp'.+os2ipNoLeading :: MonadFail m => BS.ByteString -> m Integer+os2ipNoLeading bytes+  | leadingZeroCount == 0 = pure $ os2ip bytes+  | otherwise =+    fail $+      "bytes of length "+        <> show (BS.length bytes)+        <> " has "+        <> show leadingZeroCount+        <> " leading zero bytes when none were expected"+  where+    leadingZeroCount = BS.length (BS.takeWhile (== 0) bytes)++-- | Decode a value and ensure it's the same as the value that was given+decodeExpected :: (Show a, Eq a, Serialise a) => a -> Decoder s ()+decodeExpected expected = do+  actual <- decode+  unless (expected == actual) $+    fail $ "Expected " <> show expected <> " but got " <> show actual++fromCurveEdDSA :: P.CoseCurveEdDSA -> R.CoseEllipticCurveOKP+fromCurveEdDSA P.CoseCurveEd25519 = R.CoseEllipticCurveEd25519++toCurveEdDSA :: R.CoseEllipticCurveOKP -> P.CoseCurveEdDSA+toCurveEdDSA R.CoseEllipticCurveEd25519 = P.CoseCurveEd25519++fromCurveECDSA :: P.CoseCurveECDSA -> R.CoseEllipticCurveEC2+fromCurveECDSA P.CoseCurveP256 = R.CoseEllipticCurveEC2P256+fromCurveECDSA P.CoseCurveP384 = R.CoseEllipticCurveEC2P384+fromCurveECDSA P.CoseCurveP521 = R.CoseEllipticCurveEC2P521++toCurveECDSA :: R.CoseEllipticCurveEC2 -> P.CoseCurveECDSA+toCurveECDSA R.CoseEllipticCurveEC2P256 = P.CoseCurveP256+toCurveECDSA R.CoseEllipticCurveEC2P384 = P.CoseCurveP384+toCurveECDSA R.CoseEllipticCurveEC2P521 = P.CoseCurveP521
+ src/Crypto/WebAuthn/Cose/SignAlg.hs view
@@ -0,0 +1,240 @@+{-# LANGUAGE PatternSynonyms #-}++-- | Stability: experimental+-- This module contains definitions for [COSE registry](https://www.iana.org/assignments/cose/cose.xhtml)+-- entries that are relevant for Webauthn COSE public keys. All the types in+-- this module implement the 'Serialise' class, mapping them to the respective+-- CBOR values/labels.+--+-- This modules sometimes uses this+-- [CBOR Grammar](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-13#section-1.4)+-- to describe CBOR value types corresponding to CBOR parameters+module Crypto.WebAuthn.Cose.SignAlg+  ( -- * COSE Algorithms+    CoseSignAlg+      ( ..,+        CoseAlgorithmEdDSA,+        CoseAlgorithmES256,+        CoseAlgorithmES384,+        CoseAlgorithmES512,+        CoseAlgorithmRS256,+        CoseAlgorithmRS384,+        CoseAlgorithmRS512,+        CoseAlgorithmRS1+      ),+    fromCoseSignAlg,+    toCoseSignAlg,++    -- * Hash Algorithms+    CoseHashAlgECDSA (..),+    CoseHashAlgRSA (..),+  )+where++import Codec.CBOR.Decoding (decodeIntCanonical)+import Codec.CBOR.Encoding (encodeInt)+import Codec.Serialise (Serialise)+import Codec.Serialise.Class (decode, encode)+import Data.Aeson (ToJSON)+import Data.Text (Text)+import qualified Data.Text as Text+import GHC.Generics (Generic)++-- | [(spec)](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- All the entries from the [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- limited to the ones that are currently needed for Webauthn. Notably we only+-- care about asymmetric signature algorithms+data CoseSignAlg+  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2)+    -- EdDSA+    --+    -- [RFC8032](https://datatracker.ietf.org/doc/html/rfc8032) describes the elliptic curve signature scheme Edwards-curve+    -- Digital Signature Algorithm (EdDSA).  In that document, the signature+    -- algorithm is instantiated using parameters for edwards25519 and+    -- edwards448 curves.  The document additionally describes two variants+    -- of the EdDSA algorithm: Pure EdDSA, where no hash function is applied+    -- to the content before signing, and HashEdDSA, where a hash function+    -- is applied to the content before signing and the result of that hash+    -- function is signed.  For EdDSA, the content to be signed (either the+    -- message or the pre-hash value) is processed twice inside of the+    -- signature algorithm.  For use with COSE, only the pure EdDSA version+    -- is used.+    --+    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2.1)+    CoseSignAlgEdDSA+  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)+    -- ECDSA+    --+    -- ECDSA [DSS] defines a signature algorithm using ECC.  Implementations+    -- SHOULD use a deterministic version of ECDSA such as the one defined+    -- in [RFC6979].+    --+    -- The ECDSA signature algorithm is parameterized with a hash function+    -- (h).  In the event that the length of the hash function output is+    -- greater than the group of the key, the leftmost bytes of the hash+    -- output are used.+    -- ECDSA w/ SHA-256+    --+    -- This document defines ECDSA to work only with the curves P-256,+    -- P-384, and P-521. Future documents may define it to work with other+    -- curves and points in the future.+    --+    -- In order to promote interoperability, it is suggested that SHA-256 be+    -- used only with curve P-256, SHA-384 be used only with curve P-384,+    -- and SHA-512 be used with curve P-521.  This is aligned with the+    -- recommendation in [Section 4 of RFC5480](https://datatracker.ietf.org/doc/html/rfc5480#section-4)+    --+    -- Security considerations are [here](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1.1)+    CoseSignAlgECDSA CoseHashAlgECDSA+  | -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)+    -- The RSASSA-PKCS1-v1_5 signature algorithm is defined in+    -- [RFC8017](https://www.rfc-editor.org/rfc/rfc8812.html#RFC8017).+    -- The RSASSA-PKCS1-v1_5 signature algorithm is parameterized with a hash function (h).+    --+    -- A key of size 2048 bits or larger MUST be used with these algorithms.+    --+    -- Security considerations are [here](https://www.rfc-editor.org/rfc/rfc8812.html#section-5)+    CoseSignAlgRSA CoseHashAlgRSA+  deriving (Eq, Show, Ord, Generic, ToJSON)++-- | Hash algorithms that can be used with the ECDSA signature algorithm+data CoseHashAlgECDSA+  = -- | SHA-256+    CoseHashAlgECDSASHA256+  | -- | SHA-384+    CoseHashAlgECDSASHA384+  | -- | SHA-512+    CoseHashAlgECDSASHA512+  deriving (Eq, Show, Ord, Enum, Bounded, Generic, ToJSON)++-- | Hash algorithms that can be used with the RSA signature algorithm+data CoseHashAlgRSA+  = -- | SHA-1 (deprecated)+    CoseHashAlgRSASHA1+  | -- | SHA-256+    CoseHashAlgRSASHA256+  | -- | SHA-384+    CoseHashAlgRSASHA384+  | -- | SHA-512+    CoseHashAlgRSASHA512+  deriving (Eq, Show, Ord, Enum, Bounded, Generic, ToJSON)++-- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.2)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @EdDSA@. Alias for 'CoseSignAlgEdDSA'+--+-- * Name: EdDSA+-- * Description: EdDSA+-- * Recommended: Yes+pattern CoseAlgorithmEdDSA :: CoseSignAlg+pattern CoseAlgorithmEdDSA = CoseSignAlgEdDSA++-- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @ES256@. Alias for @'CoseSignAlgECDSA' 'CoseHashAlgECDSASHA256'@+--+-- * Name: ES256+-- * Description: ECDSA w/ SHA-256+-- * Recommended: Yes+pattern CoseAlgorithmES256 :: CoseSignAlg+pattern CoseAlgorithmES256 = CoseSignAlgECDSA CoseHashAlgECDSASHA256++-- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @ES384@. Alias for @'CoseSignAlgECDSA' 'CoseHashAlgECDSASHA384'@+--+-- * Name: ES384+-- * Description: ECDSA w/ SHA-384+-- * Recommended: Yes+pattern CoseAlgorithmES384 :: CoseSignAlg+pattern CoseAlgorithmES384 = CoseSignAlgECDSA CoseHashAlgECDSASHA384++-- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-2.1)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @ES512@. Alias for @'CoseSignAlgECDSA' 'CoseHashAlgECDSASHA512'@+--+-- * Name: ES512+-- * Description: ECDSA w/ SHA-512+-- * Recommended: Yes+pattern CoseAlgorithmES512 :: CoseSignAlg+pattern CoseAlgorithmES512 = CoseSignAlgECDSA CoseHashAlgECDSASHA512++-- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @RS256@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA256'@+--+-- * Name: RS256+-- * Description: RSASSA-PKCS1-v1_5 using SHA-256+-- * Recommended: No+pattern CoseAlgorithmRS256 :: CoseSignAlg+pattern CoseAlgorithmRS256 = CoseSignAlgRSA CoseHashAlgRSASHA256++-- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @RS384@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA384'@+--+-- * Name: RS384+-- * Description: RSASSA-PKCS1-v1_5 using SHA-384+-- * Recommended: No+pattern CoseAlgorithmRS384 :: CoseSignAlg+pattern CoseAlgorithmRS384 = CoseSignAlgRSA CoseHashAlgRSASHA384++-- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @RS512@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA512'@+--+-- * Name: RS512+-- * Description: RSASSA-PKCS1-v1_5 using SHA-512+-- * Recommended: No+pattern CoseAlgorithmRS512 :: CoseSignAlg+pattern CoseAlgorithmRS512 = CoseSignAlgRSA CoseHashAlgRSASHA512++-- | [(spec)](https://www.rfc-editor.org/rfc/rfc8812.html#section-2)+-- [Cose Algorithm registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms)+-- entry @RS1@. Alias for @'CoseSignAlgRSA' 'CoseHashAlgRSASHA1'@+--+-- * Name: RS1+-- * Description: RSASSA-PKCS1-v1_5 using SHA-1+-- * Recommended: Deprecated+pattern CoseAlgorithmRS1 :: CoseSignAlg+pattern CoseAlgorithmRS1 = CoseSignAlgRSA CoseHashAlgRSASHA1++-- | Serialises COSE Algorithms using the @Value@ column from the+-- [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms).+-- This uses the 'fromCoseSignAlg' and 'toCoseSignAlg' functions to do the+-- encoding and decoding respectively.+instance Serialise CoseSignAlg where+  encode = encodeInt . fromCoseSignAlg+  decode = do+    int <- decodeIntCanonical+    case toCoseSignAlg int of+      Right res -> pure res+      Left err -> fail $ Text.unpack err++-- | Converts a 'CoseSignAlg' to the corresponding integer value from the+-- [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms).+-- The inverse operation is 'toCoseSignAlg'+fromCoseSignAlg :: Num p => CoseSignAlg -> p+fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA1) = -65535+fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA512) = -259+fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA384) = -258+fromCoseSignAlg (CoseSignAlgRSA CoseHashAlgRSASHA256) = -257+fromCoseSignAlg (CoseSignAlgECDSA CoseHashAlgECDSASHA512) = -36+fromCoseSignAlg (CoseSignAlgECDSA CoseHashAlgECDSASHA384) = -35+fromCoseSignAlg CoseSignAlgEdDSA = -8+fromCoseSignAlg (CoseSignAlgECDSA CoseHashAlgECDSASHA256) = -7++-- | Converts an integer value to the corresponding 'CoseSignAlg' from the+-- [COSE Algorithms registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms).+-- Returns an error if the integer doesn't represent a known algorithm.+-- The inverse operation is 'fromCoseSignAlg'+toCoseSignAlg :: (Eq a, Num a, Show a) => a -> Either Text CoseSignAlg+toCoseSignAlg (-65535) = pure (CoseSignAlgRSA CoseHashAlgRSASHA1)+toCoseSignAlg (-259) = pure (CoseSignAlgRSA CoseHashAlgRSASHA512)+toCoseSignAlg (-258) = pure (CoseSignAlgRSA CoseHashAlgRSASHA384)+toCoseSignAlg (-257) = pure (CoseSignAlgRSA CoseHashAlgRSASHA256)+toCoseSignAlg (-36) = pure (CoseSignAlgECDSA CoseHashAlgECDSASHA512)+toCoseSignAlg (-35) = pure (CoseSignAlgECDSA CoseHashAlgECDSASHA384)+toCoseSignAlg (-8) = pure CoseSignAlgEdDSA+toCoseSignAlg (-7) = pure (CoseSignAlgECDSA CoseHashAlgECDSASHA256)+toCoseSignAlg value = Left $ "Unknown COSE algorithm value " <> Text.pack (show value)
+ src/Crypto/WebAuthn/Encoding.hs view
@@ -0,0 +1,39 @@+{-# OPTIONS_GHC -Wno-missing-import-lists #-}++-- | Stability: experimental+-- This module ncludes everything needed to encode\/decode WebAuthn types+-- between serializations and Haskell types defined in "Crypto.WebAuthn.Model".+module Crypto.WebAuthn.Encoding+  ( -- * webauthn-json serialization++    -- This module includes encoding and decoding functions for messages+    -- exchanged with the+    -- [webauthn-json](https://github.com/github/webauthn-json) JavaScript+    -- library.+    module Crypto.WebAuthn.Encoding.WebAuthnJson,++    -- * Binary fields++    -- WebAuthn defines several structures that employ a binary serialization,+    -- such as+    -- [clientDataJSON](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)+    -- or [authenticator+    -- data](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata).+    -- This module exposes functions for encoding/decoding such fields, using+    -- types from "Crypto.WebAuthn.Model". This is useful for defining+    -- serializations alternative to the webauthn-json one.+    module Crypto.WebAuthn.Encoding.Binary,++    -- * Enum strings++    -- WebAuthn also defines several enumerations, which can be translated+    -- to\/from their respective Haskell types in "Crypto.WebAuthn.Model" using+    -- this module. This is useful for defining serializations alternative to+    -- the webauthn-json one.+    module Crypto.WebAuthn.Encoding.Strings,+  )+where++import Crypto.WebAuthn.Encoding.Binary+import Crypto.WebAuthn.Encoding.Strings+import Crypto.WebAuthn.Encoding.WebAuthnJson
+ src/Crypto/WebAuthn/Encoding/Binary.hs view
@@ -0,0 +1,660 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Stability: experimental+-- Certain parts of the specification require that data is decoded\/encoded+-- from\/to a binary form. This module holds such functions.+module Crypto.WebAuthn.Encoding.Binary+  ( -- * 'M.CollectedClientData'+    encodeRawCollectedClientData,+    stripRawCollectedClientData,+    decodeCollectedClientData,++    -- * 'M.AttestedCredentialData'+    encodeRawAttestedCredentialData,+    stripRawAttestedCredentialData,++    -- * 'M.AuthenticatorData'+    encodeRawAuthenticatorData,+    stripRawAuthenticatorData,+    decodeAuthenticatorData,++    -- * 'M.AttestationObject'+    encodeRawAttestationObject,+    stripRawAttestationObject,+    encodeAttestationObject,+    decodeAttestationObject,++    -- * 'M.AuthenticatorResponse'+    encodeRawAuthenticatorResponse,+    stripRawAuthenticatorResponse,++    -- * 'M.Credential'+    encodeRawCredential,+    stripRawCredential,+  )+where++import qualified Codec.CBOR.Decoding as CBOR+import qualified Codec.CBOR.Read as CBOR+import qualified Codec.CBOR.Term as CBOR+import qualified Codec.CBOR.Write as CBOR+import Codec.Serialise (Serialise (decode), encode)+import Control.Monad (unless)+import Control.Monad.Except (throwError)+import Control.Monad.State (MonadState (get, put), StateT (runStateT))+import qualified Crypto.Hash as Hash+import Crypto.WebAuthn.Internal.Utils (jsonEncodingOptions)+import Crypto.WebAuthn.Model.Identifier (AAGUID (AAGUID), unAAGUID)+import qualified Crypto.WebAuthn.Model.Kinds as K+import qualified Crypto.WebAuthn.Model.Types as M+import qualified Data.Aeson as Aeson+import qualified Data.Binary.Get as Binary+import qualified Data.Binary.Put as Binary+import Data.Bits ((.|.))+import qualified Data.Bits as Bits+import Data.ByteArray (convert)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Base64 as Base64+import qualified Data.ByteString.Base64.URL as Base64Url+import Data.ByteString.Builder (Builder, stringUtf8, toLazyByteString)+import qualified Data.ByteString.Lazy as LBS+import qualified Data.HashMap.Strict as HashMap+import Data.Maybe (fromJust, fromMaybe)+import Data.Singletons (SingI (sing))+import Data.Text (Text)+import qualified Data.Text as Text+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import qualified Data.UUID as UUID+import Data.Word (Word16, Word8)+import GHC.Generics (Generic)++{-+The functions in this module are grouped and named according to the+following conventions:++* If the type is parametrized by @raw@, there should be @stripRaw@ and+  @encodeRaw@ functions+* If the type is serializable there should be a @decode@+  * In addition, if the type has a raw field for its own encoding (implying+    that it's parametrized by @raw@), no other function needs to be provided+  * Alternatively, there should be an @encode@ that encodes the type, using+    any nested raw fields if available++If the type is parametrized by @raw@, this module should guarantee these+invariants for any @value :: TheType (raw ~ False)@:++* @stripRaw@ doesn't change any fields: @stripRaw value = value@+* @encodeRaw@ doesn't change any fields: @stripRaw (encodeRaw value) = value@+* If the type is also serializable:+  * If the type has a raw field, @decode@ inverses @encodeRaw@ and+    @getEncoded@: @stripRaw (decode (getEncoded (encodeRaw value))) = value@+  * Alternatively, @decode@ inverses @encodeRaw@ and @encode@:+    @stripRaw (decode (encode (encodeRaw value))) = value@++If the type is only serializable then this invariant should hold for any+@value :: TheType@++* @decode@ inverses @encode@: @decode (encode value) = value@++If any such functions are expected to be used only internally, they may not be+exported+-}++-- | Webauthn contains a mixture of binary formats. For one it's CBOR and for+-- another it's a custom format. For CBOR we wish to use the+-- [cborg](https://hackage.haskell.org/package/cborg) library and for the+-- custom binary format the+-- [binary](https://hackage.haskell.org/package/binary) library. However these+-- two libraries don't interact nicely with each other. Because of this we are+-- specifying decoders that don't consume all input as a 'PartialBinaryDecoder+-- DecodingError', which is just a function that can partially consume a+-- 'LBS.ByteString'. Using this we can somewhat easily flip between the two+-- libraries while decoding without too much nastiness.+type PartialBinaryDecoder a = StateT LBS.ByteString (Either Text) a++-- | Runs a 'PartialBinaryDecoder' using a strict bytestring. Afterwards it+-- makes sure that no bytes are left, otherwise returns an error.+runPartialBinaryDecoder ::+  BS.ByteString ->+  PartialBinaryDecoder a ->+  Either Text a+runPartialBinaryDecoder bytes decoder =+  case runStateT decoder . LBS.fromStrict $ bytes of+    Left err -> Left err+    Right (result, rest)+      | LBS.null rest -> return result+      | otherwise ->+        Left $+          "Not all binary input used, rest in base64 format is: "+            <> decodeUtf8 (Base64.encode $ LBS.toStrict rest)++-- | A 'PartialBinaryDecoder' for a binary encoding specified using+-- 'Binary.Get'.+runBinary ::+  Binary.Get a ->+  PartialBinaryDecoder a+runBinary decoder = do+  bytes <- get+  case Binary.runGetOrFail decoder bytes of+    Left (_rest, _offset, err) ->+      throwError $ "Binary decoding error: " <> Text.pack err+    Right (rest, _offset, result) -> do+      put rest+      pure result++-- | A 'PartialBinaryDecoder' for a CBOR encoding specified using the given+-- 'CBOR.Decoder'.+runCBOR ::+  (forall s. CBOR.Decoder s a) ->+  PartialBinaryDecoder (LBS.ByteString, a)+runCBOR decoder = do+  bytes <- get+  case CBOR.deserialiseFromBytesWithSize decoder bytes of+    Left err ->+      throwError $ "CBOR decoding error: " <> Text.pack (show err)+    Right (rest, consumed, a) -> do+      put rest+      pure (LBS.take (fromIntegral consumed) bytes, a)++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#authdataextensions) Encodes+-- [authenticator extension+-- outputs](https://www.w3.org/TR/webauthn-2/#authenticator-extension-output)+-- as a CBOR map.+encodeExtensions ::+  M.AuthenticatorExtensionOutputs ->+  Builder+encodeExtensions M.AuthenticatorExtensionOutputs {} =+  -- TODO: Extensions are not implemented by this library, see the TODO in the+  -- module documentation of `Crypto.WebAuthn.Model` for more information.+  CBOR.toBuilder $ CBOR.encodeTerm (CBOR.TMap [])++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#authdataextensions) Decodes a+-- CBOR map as [authenticator extension+-- outputs](https://www.w3.org/TR/webauthn-2/#authenticator-extension-output).+decodeExtensions ::+  PartialBinaryDecoder M.AuthenticatorExtensionOutputs+decodeExtensions = do+  -- TODO: Extensions are not implemented by this library, see the TODO in the+  -- module documentation of `Crypto.WebAuthn.Model` for more information.+  (_, _extensions :: CBOR.Term) <- runCBOR CBOR.decodeTerm+  pure M.AuthenticatorExtensionOutputs {}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-client-data)+-- Intermediate type used to extract the JSON structure stored in the+-- CBOR-encoded+-- [clientDataJSON](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson).+data ClientDataJSON = ClientDataJSON+  { littype :: Text,+    challenge :: Text,+    origin :: Text,+    crossOrigin :: Maybe Bool+    -- TODO: We do not implement TokenBinding, see the documentation of+    -- `CollectedClientData` for more information.+    -- tokenBinding :: Maybe TokenBinding+  }+  deriving (Generic)++-- Note: Encoding should NOT be derived via aeson, use+-- 'encodeRawCollectedClientData' instead+instance Aeson.FromJSON ClientDataJSON where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-client-data) Encodes+-- all raw fields of a 'M.CollectedClientData' into 'M.ccdRawData' using the+-- [JSON-compatible serialization of client+-- data](https://www.w3.org/TR/webauthn-2/#collectedclientdata-json-compatible-serialization-of-client-data)+-- This function is useful for testing.+encodeRawCollectedClientData ::+  forall (c :: K.CeremonyKind) raw.+  SingI c =>+  M.CollectedClientData c raw ->+  M.CollectedClientData c 'True+encodeRawCollectedClientData M.CollectedClientData {..} =+  M.CollectedClientData {ccdRawData = M.WithRaw bytes, ..}+  where+    bytes = LBS.toStrict $ toLazyByteString builder++    -- https://www.w3.org/TR/webauthn-2/#clientdatajson-serialization+    builder :: Builder+    builder =+      stringUtf8 "{\"type\":"+        <> jsonBuilder typeValue+        <> stringUtf8 ",\"challenge\":"+        <> jsonBuilder challengeValue+        <> stringUtf8 ",\"origin\":"+        <> jsonBuilder originValue+        <> stringUtf8 ",\"crossOrigin\":"+        <> jsonBuilder crossOriginValue+        <> stringUtf8 "}"++    typeValue :: Text+    typeValue = case sing @c of+      K.SRegistration -> "webauthn.create"+      K.SAuthentication -> "webauthn.get"++    challengeValue :: Text+    challengeValue = decodeUtf8 (Base64Url.encode (M.unChallenge ccdChallenge))++    originValue :: Text+    originValue = M.unOrigin ccdOrigin++    crossOriginValue :: Bool+    -- > If crossOrigin is not present, or is false:+    -- > Append 0x66616c7365 (false) to result.+    crossOriginValue = fromMaybe False ccdCrossOrigin++    jsonBuilder :: Aeson.ToJSON a => a -> Builder+    jsonBuilder = Aeson.fromEncoding . Aeson.toEncoding++-- | Removes all raw fields of a 'M.CollectedClientData'.+stripRawCollectedClientData ::+  M.CollectedClientData c raw ->+  M.CollectedClientData c 'False+stripRawCollectedClientData M.CollectedClientData {..} =+  M.CollectedClientData {ccdRawData = M.NoRaw, ..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-client-data) Decodes+-- a 'M.CollectedClientData' from a 'BS.ByteString'. This is needed to parse+-- the+-- [clientDataJSON](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)+-- field in the+-- [AuthenticatorResponse](https://www.w3.org/TR/webauthn-2/#iface-authenticatorresponse)+-- structure, which is used for both attestation and assertion.+decodeCollectedClientData ::+  forall (c :: K.CeremonyKind).+  SingI c =>+  BS.ByteString ->+  Either Text (M.CollectedClientData c 'True)+decodeCollectedClientData bytes = do+  -- <https://www.w3.org/TR/webauthn-2/#collectedclientdata-json-compatible-serialization-of-client-data>+  ClientDataJSON {..} <- case Aeson.eitherDecodeStrict bytes of+    Left err ->+      Left $+        "Collected client data JSON decoding error: "+          <> Text.pack err+    Right res -> pure res++  -- [(spec)](https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-challenge)+  -- This member contains the base64url encoding of the challenge provided by+  -- the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party). See+  -- the [§ 13.4.3 Cryptographic+  -- Challenges](https://www.w3.org/TR/webauthn-2/#sctn-cryptographic-challenges)+  -- security consideration.+  challenge <- case Base64Url.decode (encodeUtf8 challenge) of+    Left err ->+      Left $+        "Failed to base64url-decode challenge "+          <> challenge+          <> ": "+          <> Text.pack err+    Right res -> pure res++  -- [(spec)](https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-type)+  -- This member contains the string "webauthn.create" when creating new+  -- credentials, and "webauthn.get" when getting an assertion from an existing+  -- credential. The purpose of this member is to prevent certain types of+  -- signature confusion attacks (where an attacker substitutes one legitimate+  -- signature for another).+  let expectedType = case sing @c of+        K.SRegistration -> "webauthn.create"+        K.SAuthentication -> "webauthn.get"+  unless (littype == expectedType) $+    Left $+      "Expected collected client data to have webauthn type "+        <> expectedType+        <> " but it is "+        <> littype+  pure+    M.CollectedClientData+      { ccdChallenge = M.Challenge challenge,+        ccdOrigin = M.Origin origin,+        ccdCrossOrigin = crossOrigin,+        ccdRawData = M.WithRaw bytes+      }++-- | Encodes all raw fields of a 'M.AttestedCredentialData', particularly+-- encodes 'M.acdCredentialPublicKey' using its 'Serialise' instance into+-- 'M.acdCredentialPublicKeyBytes', see+-- [@credentialPublicKey@](https://www.w3.org/TR/webauthn-2/#credentialpublickey).+encodeRawAttestedCredentialData ::+  M.AttestedCredentialData c raw ->+  M.AttestedCredentialData c 'True+encodeRawAttestedCredentialData M.AttestedCredentialData {..} =+  M.AttestedCredentialData+    { acdCredentialPublicKeyBytes = M.WithRaw $ LBS.toStrict bytes,+      ..+    }+  where+    bytes = CBOR.toLazyByteString $ encode acdCredentialPublicKey+encodeRawAttestedCredentialData M.NoAttestedCredentialData =+  M.NoAttestedCredentialData++-- | Removes all raw fields of a 'M.AttestedCredentialData'.+stripRawAttestedCredentialData ::+  M.AttestedCredentialData c raw ->+  M.AttestedCredentialData c 'False+stripRawAttestedCredentialData M.AttestedCredentialData {..} =+  M.AttestedCredentialData {acdCredentialPublicKeyBytes = M.NoRaw, ..}+stripRawAttestedCredentialData M.NoAttestedCredentialData =+  M.NoAttestedCredentialData++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-attested-credential-data)+-- Encodes attested credential data into bytes, used by+-- 'encodeRawAuthenticatorData'.+encodeAttestedCredentialData ::+  M.AttestedCredentialData 'K.Registration 'True ->+  Builder+encodeAttestedCredentialData M.AttestedCredentialData {..} =+  Binary.execPut (Binary.putLazyByteString $ UUID.toByteString $ unAAGUID acdAaguid)+    <> Binary.execPut (Binary.putWord16be credentialLength)+    <> Binary.execPut (Binary.putByteString $ M.unCredentialId acdCredentialId)+    <> Binary.execPut (Binary.putByteString $ M.unRaw acdCredentialPublicKeyBytes)+  where+    credentialLength :: Word16+    credentialLength = fromIntegral $ BS.length $ M.unCredentialId acdCredentialId++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-attested-credential-data)+-- Decodes attested credential data from bytes, used by+-- 'decodeAuthenticatorData'.+decodeAttestedCredentialData ::+  PartialBinaryDecoder (M.AttestedCredentialData 'K.Registration 'True)+decodeAttestedCredentialData = do+  -- https://www.w3.org/TR/webauthn-2/#aaguid+  acdAaguid <-+    -- Note: fromJust is safe because UUID.fromByteString only returns+    -- nothing if there's not exactly 16 bytes+    AAGUID . fromJust . UUID.fromByteString+      <$> runBinary (Binary.getLazyByteString 16)++  -- https://www.w3.org/TR/webauthn-2/#credentialidlength+  credentialLength <-+    runBinary Binary.getWord16be++  -- https://www.w3.org/TR/webauthn-2/#credentialid+  acdCredentialId <-+    M.CredentialId+      <$> runBinary (Binary.getByteString (fromIntegral credentialLength))++  -- https://www.w3.org/TR/webauthn-2/#credentialpublickey+  (usedBytes, acdCredentialPublicKey) <- runCBOR decode+  let acdCredentialPublicKeyBytes = M.WithRaw $ LBS.toStrict usedBytes++  pure M.AttestedCredentialData {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#authenticator-data)+-- Encodes all raw-containing fields of a 'M.AuthenticatorData', particularly+-- 'M.adAttestedCredentialData', and the 'M.AuthenticatorData' itself into+-- 'M.adRawData'. This function is needed for an authenticator implementation.+encodeRawAuthenticatorData ::+  forall (c :: K.CeremonyKind) raw.+  SingI c =>+  M.AuthenticatorData c raw ->+  M.AuthenticatorData c 'True+encodeRawAuthenticatorData M.AuthenticatorData {..} =+  M.AuthenticatorData+    { adRawData = M.WithRaw bytes,+      adAttestedCredentialData = rawAttestedCredentialData,+      ..+    }+  where+    rawAttestedCredentialData =+      encodeRawAttestedCredentialData adAttestedCredentialData++    bytes :: BS.ByteString+    bytes = LBS.toStrict $ toLazyByteString builder++    -- https://www.w3.org/TR/webauthn-2/#flags+    flags :: Word8+    flags =+      userPresentFlag+        .|. userVerifiedFlag+        .|. attestedCredentialDataPresentFlag+        .|. extensionsPresentFlag+      where+        userPresentFlag = if M.adfUserPresent adFlags then Bits.bit 0 else 0+        userVerifiedFlag = if M.adfUserVerified adFlags then Bits.bit 2 else 0+        attestedCredentialDataPresentFlag = case sing @c of+          K.SRegistration -> Bits.bit 6+          K.SAuthentication -> 0+        extensionsPresentFlag = case adExtensions of+          Just _ -> Bits.bit 7+          Nothing -> 0++    -- https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data+    builder :: Builder+    builder =+      Binary.execPut (Binary.putByteString $ convert $ M.unRpIdHash adRpIdHash)+        <> Binary.execPut (Binary.putWord8 flags)+        <> Binary.execPut (Binary.putWord32be $ M.unSignatureCounter adSignCount)+        <> ( case sing @c of+               K.SRegistration ->+                 encodeAttestedCredentialData rawAttestedCredentialData+               K.SAuthentication ->+                 mempty+           )+        <> maybe mempty encodeExtensions adExtensions++-- | Removes all raw fields from a 'M.AuthenticatorData'.+stripRawAuthenticatorData ::+  M.AuthenticatorData c raw ->+  M.AuthenticatorData c 'False+stripRawAuthenticatorData M.AuthenticatorData {..} =+  M.AuthenticatorData+    { adRawData = M.NoRaw,+      adAttestedCredentialData =+        stripRawAttestedCredentialData adAttestedCredentialData,+      ..+    }++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#authenticator-data) Decodes a+-- 'M.AuthenticatorData' from a 'BS.ByteString'. This is needed to parse a+-- webauthn clients+-- [authenticatorData](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata)+-- field in the+-- [AuthenticatorAssertionResponse](https://www.w3.org/TR/webauthn-2/#iface-authenticatorassertionresponse)+-- structure.+decodeAuthenticatorData ::+  forall (c :: K.CeremonyKind).+  SingI c =>+  BS.ByteString ->+  Either Text (M.AuthenticatorData c 'True)+decodeAuthenticatorData strictBytes = runPartialBinaryDecoder strictBytes $ do+  -- https://www.w3.org/TR/webauthn-2/#authenticator-data+  let adRawData = M.WithRaw strictBytes++  -- https://www.w3.org/TR/webauthn-2/#rpidhash+  adRpIdHash <-+    M.RpIdHash . fromJust . Hash.digestFromByteString+      <$> runBinary (Binary.getByteString 32)++  -- https://www.w3.org/TR/webauthn-2/#flags+  bitFlags <- runBinary Binary.getWord8+  let adFlags =+        M.AuthenticatorDataFlags+          { M.adfUserPresent = Bits.testBit bitFlags 0,+            M.adfUserVerified = Bits.testBit bitFlags 2+          }++  -- https://www.w3.org/TR/webauthn-2/#signcount+  adSignCount <- M.SignatureCounter <$> runBinary Binary.getWord32be++  -- https://www.w3.org/TR/webauthn-2/#attestedcredentialdata+  adAttestedCredentialData <- case (sing @c, Bits.testBit bitFlags 6) of+    -- For [attestation+    -- signatures](https://www.w3.org/TR/webauthn-2/#attestation-signature),+    -- the authenticator MUST set the AT+    -- [flag](https://www.w3.org/TR/webauthn-2/#flags) and include the+    -- `[attestedCredentialData](https://www.w3.org/TR/webauthn-2/#attestedcredentialdata)`.+    (K.SRegistration, True) ->+      decodeAttestedCredentialData+    (K.SRegistration, False) ->+      throwError "Expected attested credential data, but there is none"+    -- For [assertion+    -- signatures](https://www.w3.org/TR/webauthn-2/#assertion-signature), the+    -- AT [flag](https://www.w3.org/TR/webauthn-2/#flags) MUST NOT be set and+    -- the+    -- `[attestedCredentialData](https://www.w3.org/TR/webauthn-2/#attestedcredentialdata)`+    -- MUST NOT be included.+    (K.SAuthentication, False) ->+      pure M.NoAttestedCredentialData+    (K.SAuthentication, True) ->+      throwError "Expected no attested credential data, but there is"++  -- https://www.w3.org/TR/webauthn-2/#authdataextensions+  adExtensions <-+    if Bits.testBit bitFlags 7+      then Just <$> decodeExtensions+      else pure Nothing++  pure M.AuthenticatorData {..}++-- | Encodes all raw fields of an 'M.AttestationObject'.+encodeRawAttestationObject ::+  M.AttestationObject raw ->+  M.AttestationObject 'True+encodeRawAttestationObject M.AttestationObject {..} =+  M.AttestationObject+    { aoAuthData = encodeRawAuthenticatorData aoAuthData,+      ..+    }++-- | Removes all raw fields of an 'M.AttestationObject'.+stripRawAttestationObject ::+  M.AttestationObject raw ->+  M.AttestationObject 'False+stripRawAttestationObject M.AttestationObject {..} =+  M.AttestationObject+    { aoAuthData = stripRawAuthenticatorData aoAuthData,+      ..+    }++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object)+-- Encodes an 'M.AttestationObject' as a 'BS.ByteString'. This is needed by+-- the client side to generate a valid JSON response.+encodeAttestationObject ::+  M.AttestationObject 'True ->+  BS.ByteString+encodeAttestationObject M.AttestationObject {..} =+  CBOR.toStrictByteString $ CBOR.encodeTerm term+  where+    -- https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object+    term :: CBOR.Term+    term =+      CBOR.TMap+        [ (CBOR.TString "authData", CBOR.TBytes $ M.unRaw $ M.adRawData aoAuthData),+          (CBOR.TString "fmt", CBOR.TString $ M.asfIdentifier aoFmt),+          (CBOR.TString "attStmt", M.asfEncode aoFmt aoAttStmt)+        ]++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object)+-- Decodes a 'M.AttestationObject' from a 'BS.ByteString'. This is needed to+-- parse a webauthn clients+-- [attestationObject](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-attestationobject)+-- field in the+-- [AuthenticatorAttestationResponse](https://www.w3.org/TR/webauthn-2/#iface-authenticatorattestationresponse)+-- structure This function takes a 'M.SupportedAttestationStatementFormats'+-- argument to indicate which attestation statement formats are supported.+-- structure.+decodeAttestationObject ::+  M.SupportedAttestationStatementFormats ->+  BS.ByteString ->+  Either Text (M.AttestationObject 'True)+decodeAttestationObject supportedFormats bytes = do+  (_consumed, result) <-+    runPartialBinaryDecoder bytes (runCBOR CBOR.decodeTerm)+  pairs <- case result of+    CBOR.TMap pairs -> return pairs+    _ ->+      Left $+        "The attestation object should be a CBOR map, but it's not: "+          <> Text.pack (show result)++  -- https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object+  case ( CBOR.TString "authData" `lookup` pairs,+         CBOR.TString "fmt" `lookup` pairs,+         CBOR.TString "attStmt" `lookup` pairs+       ) of+    ( Just (CBOR.TBytes authDataBytes),+      Just (CBOR.TString fmt),+      Just (CBOR.TMap attStmtPairs)+      ) -> do+        aoAuthData <- decodeAuthenticatorData authDataBytes++        case M.lookupAttestationStatementFormat fmt supportedFormats of+          Nothing -> Left $ "Unknown attestation statement format: " <> fmt+          Just (M.SomeAttestationStatementFormat aoFmt) -> do+            attStmtMap <-+              HashMap.fromList+                <$> traverse textKeyPairs attStmtPairs+            aoAttStmt <- M.asfDecode aoFmt attStmtMap+            pure M.AttestationObject {..}+    _ ->+      Left $+        "The attestation object doesn't have the expected structure of "+          <> "(authData: bytes, fmt: string, attStmt: map): "+          <> Text.pack (show result)+  where+    textKeyPairs (CBOR.TString text, term) = pure (text, term)+    textKeyPairs (nonString, _) =+      Left $+        "Unexpected non-string attestation statement key: "+          <> Text.pack (show nonString)++-- | Encode all raw fields of an 'M.AuthenticatorResponse'.+encodeRawAuthenticatorResponse ::+  M.AuthenticatorResponse c raw ->+  M.AuthenticatorResponse c 'True+encodeRawAuthenticatorResponse M.AuthenticatorResponseRegistration {..} =+  M.AuthenticatorResponseRegistration+    { arrClientData = encodeRawCollectedClientData arrClientData,+      arrAttestationObject = encodeRawAttestationObject arrAttestationObject,+      ..+    }+encodeRawAuthenticatorResponse M.AuthenticatorResponseAuthentication {..} =+  M.AuthenticatorResponseAuthentication+    { araClientData = encodeRawCollectedClientData araClientData,+      araAuthenticatorData = encodeRawAuthenticatorData araAuthenticatorData,+      ..+    }++-- | Removes all raw fields of an 'M.AuthenticatorResponse'.+stripRawAuthenticatorResponse ::+  M.AuthenticatorResponse c raw ->+  M.AuthenticatorResponse c 'False+stripRawAuthenticatorResponse M.AuthenticatorResponseRegistration {..} =+  M.AuthenticatorResponseRegistration+    { arrClientData = stripRawCollectedClientData arrClientData,+      arrAttestationObject = stripRawAttestationObject arrAttestationObject,+      ..+    }+stripRawAuthenticatorResponse M.AuthenticatorResponseAuthentication {..} =+  M.AuthenticatorResponseAuthentication+    { araClientData = stripRawCollectedClientData araClientData,+      araAuthenticatorData = stripRawAuthenticatorData araAuthenticatorData,+      ..+    }++-- | Encodes all raw fields of an 'M.Credential'.+encodeRawCredential ::+  M.Credential c raw ->+  M.Credential c 'True+encodeRawCredential M.Credential {..} =+  M.Credential+    { cResponse = encodeRawAuthenticatorResponse cResponse,+      ..+    }++-- | Removes all raw fields of an 'M.Credential'.+stripRawCredential ::+  M.Credential c raw ->+  M.Credential c 'False+stripRawCredential M.Credential {..} =+  M.Credential+    { cResponse = stripRawAuthenticatorResponse cResponse,+      ..+    }
+ src/Crypto/WebAuthn/Encoding/Internal/WebAuthnJson.hs view
@@ -0,0 +1,666 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeFamilies #-}++-- | Stability: internal+-- This module implements decoding\/encoding from\/to+-- [webauthn-json](https://github.com/github/webauthn-json) JSON values to the+-- Haskell types defined in "Crypto.WebAuthn.Model.Types".+module Crypto.WebAuthn.Encoding.Internal.WebAuthnJson+  ( -- * Top-level types+    PublicKeyCredentialCreationOptions (..),+    PublicKeyCredentialRequestOptions (..),+    PublicKeyCredential (..),++    -- * Nested types+    AuthenticatorAttestationResponse (..),+    AuthenticatorAssertionResponse (..),+    PublicKeyCredentialRpEntity (..),+    PublicKeyCredentialUserEntity (..),+    PublicKeyCredentialParameters (..),+    COSEAlgorithmIdentifier,+    PublicKeyCredentialDescriptor (..),+    AuthenticatorSelectionCriteria (..),+    Base64UrlString (..),++    -- * Type classes+    Encode (..),+    Decode (..),+  )+where++import Control.Monad.Except (MonadError, liftEither)+import Control.Monad.Reader (MonadReader (ask))+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose+import qualified Crypto.WebAuthn.Encoding.Binary as B+import qualified Crypto.WebAuthn.Encoding.Strings as S+import Crypto.WebAuthn.Internal.Utils (jsonEncodingOptions)+import qualified Crypto.WebAuthn.Model.Defaults as D+import qualified Crypto.WebAuthn.Model.Kinds as K+import qualified Crypto.WebAuthn.Model.Types as T+import qualified Data.Aeson as Aeson+import qualified Data.ByteString as BS+import qualified Data.ByteString.Base64.URL as Base64Url+import Data.Coerce (Coercible, coerce)+import Data.Int (Int32)+import Data.Kind (Type)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Singletons (SingI)+import Data.Text (Text)+import qualified Data.Text.Encoding as Text+import Data.Word (Word32)+import GHC.Generics (Generic)++-- | A type class to indicate that some Haskell type @a@ can be encoded to a+-- corresponding JSON-serializable webauthn-json type @'JSON' a@ using 'encode'+class Encode a where+  type JSON a :: Type++  -- | Encodes a value to its webauthn-json equivalent+  encode :: a -> JSON a+  default encode :: Coercible a (JSON a) => a -> JSON a+  encode = coerce++-- | An extension of 'Encode' to decoding. This typeclass is parametrized by a+-- 'Monad' @m@ since decoding certain structures requires additional+-- information to succeed, specifically+-- 'M.SupportedAttestationStatementFormats', which can be provided with a+-- 'MonadReader' constraint+class Encode a => Decode m a where+  -- | Decodes a webauthn-json type, potentially throwing a 'Text' error+  decode :: MonadError Text m => JSON a -> m a+  default decode :: (MonadError Text m, Coercible (JSON a) a) => JSON a -> m a+  decode = pure . coerce++-- | Decodes an optional value with a default+decodeWithDefault :: (MonadError Text m, Decode m a) => a -> Maybe (JSON a) -> m a+decodeWithDefault def Nothing = pure def+decodeWithDefault _ (Just value) = decode value++instance (Functor f, Encode a) => Encode (f a) where+  type JSON (f a) = f (JSON a)+  encode = fmap encode++instance (Traversable f, Decode m a) => Decode m (f a) where+  decode = traverse decode++-- | A base64url encoded string. Its 'Aeson.FromJSON'\/'Aeson.ToJSON' instances+-- do the conversion+newtype Base64UrlString = Base64UrlString {unBase64UrlString :: BS.ByteString}+  deriving (Show, Eq)++-- | Decodes a base64url encoded JSON string into the bytes it represents+instance Aeson.FromJSON Base64UrlString where+  parseJSON = Aeson.withText "base64url" $ \t ->+    either fail (pure . Base64UrlString) (Base64Url.decode $ Text.encodeUtf8 t)++-- | Encodes bytes using base64url to a JSON string+instance Aeson.ToJSON Base64UrlString where+  toJSON = Aeson.String . Text.decodeUtf8 . Base64Url.encodeUnpadded . unBase64UrlString++instance Encode T.Timeout where+  type JSON T.Timeout = Word32++instance Decode m T.Timeout++instance Encode T.RpId where+  type JSON T.RpId = Text++instance Decode m T.RpId++instance Encode T.RelyingPartyName where+  type JSON T.RelyingPartyName = Text++instance Decode m T.RelyingPartyName++instance Encode T.UserHandle where+  type JSON T.UserHandle = Base64UrlString++instance Decode m T.UserHandle++instance Encode T.UserAccountDisplayName where+  type JSON T.UserAccountDisplayName = Text++instance Decode m T.UserAccountDisplayName++instance Encode T.UserAccountName where+  type JSON T.UserAccountName = Text++instance Decode m T.UserAccountName++instance Encode T.Challenge where+  type JSON T.Challenge = Base64UrlString++instance Decode m T.Challenge++instance Encode T.CredentialId where+  type JSON T.CredentialId = Base64UrlString++instance Decode m T.CredentialId++instance Encode T.AssertionSignature where+  type JSON T.AssertionSignature = Base64UrlString++instance Decode m T.AssertionSignature++{-+Note: The spec often mentions that _client platforms_ must ignore unknown+values, but since we implement a RP, we don't need to concern ourselves with+that.++The only place where we do need to concern ourselves with it is the+[transports](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-transports-slot)+field returned from the client, which in Level 2 of the spec mentions:++> The values SHOULD be members of+> `[AuthenticatorTransport](https://www.w3.org/TR/webauthn-2/#enumdef-authenticatortransport)`+> but [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party) MUST+> ignore unknown values.++However that doesn't say what should happen in case of unknown values. This has+been fixed in a more recent version of the spec, see+https://github.com/w3c/webauthn/issues/1587. It will say this in the future:++> The values SHOULD be members of AuthenticatorTransport but Relying Parties+> SHOULD accept and store unknown values.+-}++instance Encode T.CredentialType where+  type JSON T.CredentialType = Text+  encode = S.encodeCredentialType++instance Decode m T.CredentialType where+  decode = liftEither . S.decodeCredentialType++instance Encode T.UserVerificationRequirement where+  type JSON T.UserVerificationRequirement = Text+  encode = S.encodeUserVerificationRequirement++instance Decode m T.UserVerificationRequirement where+  decode = liftEither . S.decodeUserVerificationRequirement++instance Encode T.AuthenticatorAttachment where+  type JSON T.AuthenticatorAttachment = Text+  encode = S.encodeAuthenticatorAttachment++instance Decode m T.AuthenticatorAttachment where+  decode = liftEither . S.decodeAuthenticatorAttachment++instance Encode T.ResidentKeyRequirement where+  type JSON T.ResidentKeyRequirement = Text+  encode = S.encodeResidentKeyRequirement++instance Decode m T.ResidentKeyRequirement where+  decode = liftEither . S.decodeResidentKeyRequirement++instance Encode T.AttestationConveyancePreference where+  type JSON T.AttestationConveyancePreference = Text+  encode = S.encodeAttestationConveyancePreference++instance Decode m T.AttestationConveyancePreference where+  decode = liftEither . S.decodeAttestationConveyancePreference++instance Encode T.AuthenticatorTransport where+  type JSON T.AuthenticatorTransport = Text+  encode = S.encodeAuthenticatorTransport++instance Decode m T.AuthenticatorTransport where+  decode = pure . S.decodeAuthenticatorTransport++instance Encode Cose.CoseSignAlg where+  type JSON Cose.CoseSignAlg = Int32+  encode = Cose.fromCoseSignAlg++instance Decode m Cose.CoseSignAlg where+  decode = liftEither . Cose.toCoseSignAlg++instance Encode T.AuthenticationExtensionsClientInputs where+  type JSON T.AuthenticationExtensionsClientInputs = Map Text Aeson.Value++  -- TODO: Extensions are not implemented by this library, see the TODO in the+  -- module documentation of `Crypto.WebAuthn.Model` for more information.+  encode T.AuthenticationExtensionsClientInputs {} = Map.empty++instance Decode m T.AuthenticationExtensionsClientInputs where+  -- TODO: Extensions are not implemented by this library, see the TODO in the+  -- module documentation of `Crypto.WebAuthn.Model` for more information.+  decode _ = pure T.AuthenticationExtensionsClientInputs {}++instance Encode T.AuthenticationExtensionsClientOutputs where+  type JSON T.AuthenticationExtensionsClientOutputs = Map Text Aeson.Value++  -- TODO: Extensions are not implemented by this library, see the TODO in the+  -- module documentation of `Crypto.WebAuthn.Model` for more information.+  encode T.AuthenticationExtensionsClientOutputs {} = Map.empty++instance Decode m T.AuthenticationExtensionsClientOutputs where+  -- TODO: Extensions are not implemented by this library, see the TODO in the+  -- module documentation of `Crypto.WebAuthn.Model` for more information.+  decode _ = pure T.AuthenticationExtensionsClientOutputs {}++instance SingI c => Encode (T.CollectedClientData (c :: K.CeremonyKind) 'True) where+  type JSON (T.CollectedClientData c 'True) = Base64UrlString+  encode = Base64UrlString . T.unRaw . T.ccdRawData++instance SingI c => Decode m (T.CollectedClientData (c :: K.CeremonyKind) 'True) where+  decode = liftEither . B.decodeCollectedClientData . unBase64UrlString++instance Encode (T.AttestationObject 'True) where+  type JSON (T.AttestationObject 'True) = Base64UrlString+  encode = Base64UrlString . B.encodeAttestationObject++instance+  MonadReader T.SupportedAttestationStatementFormats m =>+  Decode m (T.AttestationObject 'True)+  where+  decode (Base64UrlString bytes) = do+    supportedFormats <- ask+    liftEither $ B.decodeAttestationObject supportedFormats bytes++instance Encode (T.AuthenticatorData 'K.Authentication 'True) where+  type JSON (T.AuthenticatorData 'K.Authentication 'True) = Base64UrlString+  encode = Base64UrlString . T.unRaw . T.adRawData++instance Decode m (T.AuthenticatorData 'K.Authentication 'True) where+  decode = liftEither . B.decodeAuthenticatorData . unBase64UrlString++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-makecredentialoptions)+data PublicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-rp)+    rp :: PublicKeyCredentialRpEntity,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-user)+    user :: PublicKeyCredentialUserEntity,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-challenge)+    challenge :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-pubkeycredparams)+    pubKeyCredParams :: [PublicKeyCredentialParameters],+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-timeout)+    timeout :: Maybe Word32,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-excludecredentials)+    excludeCredentials :: Maybe [PublicKeyCredentialDescriptor],+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection)+    authenticatorSelection :: Maybe AuthenticatorSelectionCriteria,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-attestation)+    attestation :: Maybe Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-extensions)+    extensions :: Maybe (Map Text Aeson.Value)+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON PublicKeyCredentialCreationOptions where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON PublicKeyCredentialCreationOptions where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode (T.CredentialOptions 'K.Registration) where+  type JSON (T.CredentialOptions 'K.Registration) = PublicKeyCredentialCreationOptions+  encode T.CredentialOptionsRegistration {..} =+    PublicKeyCredentialCreationOptions+      { rp = encode corRp,+        user = encode corUser,+        challenge = encode corChallenge,+        pubKeyCredParams = encode corPubKeyCredParams,+        timeout = encode corTimeout,+        excludeCredentials = Just $ encode corExcludeCredentials,+        authenticatorSelection = encode corAuthenticatorSelection,+        attestation = Just $ encode corAttestation,+        extensions = encode corExtensions+      }++instance Decode m (T.CredentialOptions 'K.Registration) where+  decode PublicKeyCredentialCreationOptions {..} = do+    corRp <- decode rp+    corUser <- decode user+    corChallenge <- decode challenge+    corPubKeyCredParams <- decode pubKeyCredParams+    corTimeout <- decode timeout+    corExcludeCredentials <- decodeWithDefault D.corExcludeCredentialsDefault excludeCredentials+    corAuthenticatorSelection <- decode authenticatorSelection+    corAttestation <- decodeWithDefault D.corAttestationDefault attestation+    corExtensions <- decode extensions+    pure $ T.CredentialOptionsRegistration {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options)+data PublicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-challenge)+    challenge :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-timeout)+    timeout :: Maybe Word32,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-rpid)+    rpId :: Maybe Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-allowcredentials)+    allowCredentials :: Maybe [PublicKeyCredentialDescriptor],+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-userverification)+    userVerification :: Maybe Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-extensions)+    extensions :: Maybe (Map Text Aeson.Value)+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON PublicKeyCredentialRequestOptions where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON PublicKeyCredentialRequestOptions where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode (T.CredentialOptions 'K.Authentication) where+  type JSON (T.CredentialOptions 'K.Authentication) = PublicKeyCredentialRequestOptions+  encode T.CredentialOptionsAuthentication {..} =+    PublicKeyCredentialRequestOptions+      { challenge = encode coaChallenge,+        timeout = encode coaTimeout,+        rpId = encode coaRpId,+        allowCredentials = Just $ encode coaAllowCredentials,+        userVerification = Just $ encode coaUserVerification,+        extensions = encode coaExtensions+      }++instance Decode m (T.CredentialOptions 'K.Authentication) where+  decode PublicKeyCredentialRequestOptions {..} = do+    coaChallenge <- decode challenge+    coaTimeout <- decode timeout+    coaRpId <- decode rpId+    coaAllowCredentials <- decodeWithDefault D.coaAllowCredentialsDefault allowCredentials+    coaUserVerification <- decodeWithDefault D.coaUserVerificationDefault userVerification+    coaExtensions <- decode extensions+    pure $ T.CredentialOptionsAuthentication {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-rp-credential-params)+data PublicKeyCredentialRpEntity = PublicKeyCredentialRpEntity+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrpentity-id)+    id :: Maybe Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialentity-name)+    name :: Text+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON PublicKeyCredentialRpEntity where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON PublicKeyCredentialRpEntity where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode T.CredentialRpEntity where+  type JSON T.CredentialRpEntity = PublicKeyCredentialRpEntity+  encode T.CredentialRpEntity {..} =+    PublicKeyCredentialRpEntity+      { id = encode creId,+        name = encode creName+      }++instance Decode m T.CredentialRpEntity where+  decode PublicKeyCredentialRpEntity {..} = do+    creId <- decode id+    creName <- decode name+    pure $ T.CredentialRpEntity {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-user-credential-params)+data PublicKeyCredentialUserEntity = PublicKeyCredentialUserEntity+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialuserentity-id)+    id :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialuserentity-displayname)+    displayName :: Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialentity-name)+    name :: Text+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON PublicKeyCredentialUserEntity where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON PublicKeyCredentialUserEntity where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode T.CredentialUserEntity where+  type JSON T.CredentialUserEntity = PublicKeyCredentialUserEntity+  encode T.CredentialUserEntity {..} =+    PublicKeyCredentialUserEntity+      { id = encode cueId,+        displayName = encode cueDisplayName,+        name = encode cueName+      }++instance Decode m T.CredentialUserEntity where+  decode PublicKeyCredentialUserEntity {..} = do+    cueId <- decode id+    cueDisplayName <- decode displayName+    cueName <- decode name+    pure $ T.CredentialUserEntity {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-credential-params)+data PublicKeyCredentialParameters = PublicKeyCredentialParameters+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialparameters-type)+    littype :: Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialparameters-alg)+    alg :: COSEAlgorithmIdentifier+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON PublicKeyCredentialParameters where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON PublicKeyCredentialParameters where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode T.CredentialParameters where+  type JSON T.CredentialParameters = PublicKeyCredentialParameters+  encode T.CredentialParameters {..} =+    PublicKeyCredentialParameters+      { littype = encode cpTyp,+        alg = encode cpAlg+      }++instance Decode m T.CredentialParameters where+  decode PublicKeyCredentialParameters {..} = do+    cpTyp <- decode littype+    cpAlg <- decode alg+    pure T.CredentialParameters {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-alg-identifier)+type COSEAlgorithmIdentifier = Int32++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialdescriptor)+data PublicKeyCredentialDescriptor = PublicKeyCredentialDescriptor+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialdescriptor-type)+    littype :: Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialdescriptor-id)+    id :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialdescriptor-transports)+    transports :: Maybe [Text]+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON PublicKeyCredentialDescriptor where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON PublicKeyCredentialDescriptor where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode T.CredentialDescriptor where+  type JSON T.CredentialDescriptor = PublicKeyCredentialDescriptor+  encode T.CredentialDescriptor {..} =+    PublicKeyCredentialDescriptor+      { littype = encode cdTyp,+        id = encode cdId,+        transports = encode cdTransports+      }++instance Decode m T.CredentialDescriptor where+  decode PublicKeyCredentialDescriptor {..} = do+    cdTyp <- decode littype+    cdId <- decode id+    cdTransports <- decode transports+    pure T.CredentialDescriptor {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictdef-authenticatorselectioncriteria)+data AuthenticatorSelectionCriteria = AuthenticatorSelectionCriteria+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-authenticatorattachment)+    authenticatorAttachment :: Maybe Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-residentkey)+    residentKey :: Maybe Text,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey)+    requireResidentKey :: Maybe Bool,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-userverification)+    userVerification :: Maybe Text+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON AuthenticatorSelectionCriteria where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON AuthenticatorSelectionCriteria where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode T.AuthenticatorSelectionCriteria where+  type JSON T.AuthenticatorSelectionCriteria = AuthenticatorSelectionCriteria+  encode T.AuthenticatorSelectionCriteria {..} =+    AuthenticatorSelectionCriteria+      { authenticatorAttachment = encode ascAuthenticatorAttachment,+        residentKey = Just $ encode ascResidentKey,+        -- [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey)+        -- Relying Parties SHOULD set it to true if, and only if, residentKey is set to required.+        requireResidentKey = Just (ascResidentKey == T.ResidentKeyRequirementRequired),+        userVerification = Just $ encode ascUserVerification+      }++instance Decode m T.AuthenticatorSelectionCriteria where+  decode AuthenticatorSelectionCriteria {..} = do+    ascAuthenticatorAttachment <- decode authenticatorAttachment+    ascResidentKey <- decodeWithDefault (D.ascResidentKeyDefault requireResidentKey) residentKey+    ascUserVerification <- decodeWithDefault D.ascUserVerificationDefault userVerification+    pure $ T.AuthenticatorSelectionCriteria {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)+data PublicKeyCredential response = PublicKeyCredential+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredential-identifier-slot)+    rawId :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredential-response)+    response :: response,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredential-getclientextensionresults)+    clientExtensionResults :: Map Text Aeson.Value+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON response => Aeson.FromJSON (PublicKeyCredential response) where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON response => Aeson.ToJSON (PublicKeyCredential response) where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode (T.Credential 'K.Registration 'True) where+  type JSON (T.Credential 'K.Registration 'True) = PublicKeyCredential AuthenticatorAttestationResponse+  encode T.Credential {..} =+    PublicKeyCredential+      { rawId = encode cIdentifier,+        response = encode cResponse,+        clientExtensionResults = encode cClientExtensionResults+      }++instance+  MonadReader T.SupportedAttestationStatementFormats m =>+  Decode m (T.Credential 'K.Registration 'True)+  where+  decode PublicKeyCredential {..} = do+    cIdentifier <- decode rawId+    cResponse <- decode response+    cClientExtensionResults <- decode clientExtensionResults+    pure $ T.Credential {..}++instance Encode (T.Credential 'K.Authentication 'True) where+  type JSON (T.Credential 'K.Authentication 'True) = PublicKeyCredential AuthenticatorAssertionResponse+  encode T.Credential {..} =+    PublicKeyCredential+      { rawId = encode cIdentifier,+        response = encode cResponse,+        clientExtensionResults = encode cClientExtensionResults+      }++instance Decode m (T.Credential 'K.Authentication 'True) where+  decode PublicKeyCredential {..} = do+    cIdentifier <- decode rawId+    cResponse <- decode response+    cClientExtensionResults <- decode clientExtensionResults+    pure $ T.Credential {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-authenticatorattestationresponse)+data AuthenticatorAttestationResponse = AuthenticatorAttestationResponse+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)+    clientDataJSON :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-attestationobject)+    attestationObject :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-transports-slot)+    -- This field is only being propagated by webauthn-json [since recently](https://github.com/github/webauthn-json/pull/44),+    -- which is why we allow absence of this value+    transports :: Maybe [Text]+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON AuthenticatorAttestationResponse where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON AuthenticatorAttestationResponse where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode (T.AuthenticatorResponse 'K.Registration 'True) where+  type JSON (T.AuthenticatorResponse 'K.Registration 'True) = AuthenticatorAttestationResponse+  encode T.AuthenticatorResponseRegistration {..} =+    AuthenticatorAttestationResponse+      { clientDataJSON = encode arrClientData,+        attestationObject = encode arrAttestationObject,+        transports = Just $ encode arrTransports+      }++instance+  MonadReader T.SupportedAttestationStatementFormats m =>+  Decode m (T.AuthenticatorResponse 'K.Registration 'True)+  where+  decode AuthenticatorAttestationResponse {..} = do+    arrClientData <- decode clientDataJSON+    arrAttestationObject <- decode attestationObject+    -- Older webauthn-json versions don't add that field+    arrTransports <- decodeWithDefault [] transports+    pure $ T.AuthenticatorResponseRegistration {..}++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-authenticatorassertionresponse)+data AuthenticatorAssertionResponse = AuthenticatorAssertionResponse+  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)+    clientDataJSON :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata)+    authenticatorData :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-signature)+    signature :: Base64UrlString,+    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-userhandle)+    userHandle :: Maybe Base64UrlString+  }+  deriving (Eq, Show, Generic)++instance Aeson.FromJSON AuthenticatorAssertionResponse where+  parseJSON = Aeson.genericParseJSON jsonEncodingOptions++instance Aeson.ToJSON AuthenticatorAssertionResponse where+  toJSON = Aeson.genericToJSON jsonEncodingOptions++instance Encode (T.AuthenticatorResponse 'K.Authentication 'True) where+  type JSON (T.AuthenticatorResponse 'K.Authentication 'True) = AuthenticatorAssertionResponse+  encode T.AuthenticatorResponseAuthentication {..} =+    AuthenticatorAssertionResponse+      { clientDataJSON = encode araClientData,+        authenticatorData = encode araAuthenticatorData,+        signature = encode araSignature,+        userHandle = encode araUserHandle+      }++instance Decode m (T.AuthenticatorResponse 'K.Authentication 'True) where+  decode AuthenticatorAssertionResponse {..} = do+    araClientData <- decode clientDataJSON+    araAuthenticatorData <- decode authenticatorData+    araSignature <- decode signature+    araUserHandle <- decode userHandle+    pure $ T.AuthenticatorResponseAuthentication {..}
+ src/Crypto/WebAuthn/Encoding/Strings.hs view
@@ -0,0 +1,133 @@+-- | Stability: experimental+-- This module provides functions for encoding and decoding WebAuthn enum types+-- between their Haskell types defined in "Crypto.WebAuthn.Model.Types" and+-- their string forms.+module Crypto.WebAuthn.Encoding.Strings+  ( encodeCredentialType,+    decodeCredentialType,+    encodeUserVerificationRequirement,+    decodeUserVerificationRequirement,+    encodeAuthenticatorAttachment,+    decodeAuthenticatorAttachment,+    encodeResidentKeyRequirement,+    decodeResidentKeyRequirement,+    encodeAttestationConveyancePreference,+    decodeAttestationConveyancePreference,+    encodeAuthenticatorTransport,+    decodeAuthenticatorTransport,+  )+where++import qualified Crypto.WebAuthn.Model.Types as T+import Data.Text (Text)++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-publickeycredentialtype)+-- Encodes a 'T.CredentialType' to a string.+encodeCredentialType :: T.CredentialType -> Text+encodeCredentialType T.CredentialTypePublicKey = "public-key"++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-publickeycredentialtype)+-- Decodes a string into a 'T.CredentialType', returning 'Left' when the string+-- isn't known to be an enum value.+decodeCredentialType :: Text -> Either Text T.CredentialType+decodeCredentialType "public-key" = pure T.CredentialTypePublicKey+decodeCredentialType str = Left $ "Unknown PublicKeyCredentialType string: " <> str++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-userVerificationRequirement)+-- Encodes a 'T.UserVerificationRequirement' to a string.+encodeUserVerificationRequirement :: T.UserVerificationRequirement -> Text+encodeUserVerificationRequirement T.UserVerificationRequirementRequired = "required"+encodeUserVerificationRequirement T.UserVerificationRequirementPreferred = "preferred"+encodeUserVerificationRequirement T.UserVerificationRequirementDiscouraged = "discouraged"++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-userVerificationRequirement)+-- Decodes a string into a 'T.UserVerificationRequirement', returning 'Left' when+-- the string isn't known to be an enum value.+decodeUserVerificationRequirement :: Text -> Either Text T.UserVerificationRequirement+decodeUserVerificationRequirement "discouraged" = pure T.UserVerificationRequirementDiscouraged+decodeUserVerificationRequirement "preferred" = pure T.UserVerificationRequirementPreferred+decodeUserVerificationRequirement "required" = pure T.UserVerificationRequirementRequired+decodeUserVerificationRequirement str = Left $ "Unknown UserVerificationRequirement string: " <> str++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-authenticatorattachment)+-- Encodes a 'T.AuthenticatorAttachment' to a string.+encodeAuthenticatorAttachment :: T.AuthenticatorAttachment -> Text+encodeAuthenticatorAttachment T.AuthenticatorAttachmentPlatform = "platform"+encodeAuthenticatorAttachment T.AuthenticatorAttachmentCrossPlatform = "cross-platform"++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-authenticatorattachment)+-- Decodes a string into a 'T.AuthenticatorAttachment', returning 'Left' when+-- the string isn't known to be an enum value.+decodeAuthenticatorAttachment :: Text -> Either Text T.AuthenticatorAttachment+decodeAuthenticatorAttachment "platform" = pure T.AuthenticatorAttachmentPlatform+decodeAuthenticatorAttachment "cross-platform" = pure T.AuthenticatorAttachmentCrossPlatform+decodeAuthenticatorAttachment str = Left $ "Unknown AuthenticatorAttachment string: " <> str++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-residentKeyRequirement)+-- Encodes a 'T.ResidentKeyRequirement' to a string.+encodeResidentKeyRequirement :: T.ResidentKeyRequirement -> Text+encodeResidentKeyRequirement T.ResidentKeyRequirementDiscouraged = "discouraged"+encodeResidentKeyRequirement T.ResidentKeyRequirementPreferred = "preferred"+encodeResidentKeyRequirement T.ResidentKeyRequirementRequired = "required"++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-residentKeyRequirement)+-- Decodes a string into a 'T.ResidentKeyRequirement', returning 'Left' when+-- the string isn't known to be an enum value.+decodeResidentKeyRequirement :: Text -> Either Text T.ResidentKeyRequirement+decodeResidentKeyRequirement "discouraged" = pure T.ResidentKeyRequirementDiscouraged+decodeResidentKeyRequirement "preferred" = pure T.ResidentKeyRequirementPreferred+decodeResidentKeyRequirement "required" = pure T.ResidentKeyRequirementRequired+decodeResidentKeyRequirement str = Left $ "Unknown ResidentKeyRequirement string: " <> str++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-attestation-convey)+-- Encodes a 'T.AttestationConveyancePreference' to a string.+encodeAttestationConveyancePreference :: T.AttestationConveyancePreference -> Text+encodeAttestationConveyancePreference T.AttestationConveyancePreferenceNone = "none"+encodeAttestationConveyancePreference T.AttestationConveyancePreferenceIndirect = "indirect"+encodeAttestationConveyancePreference T.AttestationConveyancePreferenceDirect = "direct"+encodeAttestationConveyancePreference T.AttestationConveyancePreferenceEnterprise = "enterprise"++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-attestation-convey)+-- Decodes a string into a 'T.AttestationConveyancePreference', returning 'Left' when+-- the string isn't known to be an enum value.+decodeAttestationConveyancePreference :: Text -> Either Text T.AttestationConveyancePreference+decodeAttestationConveyancePreference "none" = pure T.AttestationConveyancePreferenceNone+decodeAttestationConveyancePreference "indirect" = pure T.AttestationConveyancePreferenceIndirect+decodeAttestationConveyancePreference "direct" = pure T.AttestationConveyancePreferenceDirect+decodeAttestationConveyancePreference "enterprise" = pure T.AttestationConveyancePreferenceEnterprise+decodeAttestationConveyancePreference str = Left $ "Unknown AttestationConveyancePreference string: " <> str++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-authenticatortransport)+-- Encodes a 'T.AuthenticatorTransport' to a string.+encodeAuthenticatorTransport :: T.AuthenticatorTransport -> Text+encodeAuthenticatorTransport T.AuthenticatorTransportUSB = "usb"+encodeAuthenticatorTransport T.AuthenticatorTransportNFC = "nfc"+encodeAuthenticatorTransport T.AuthenticatorTransportBLE = "ble"+encodeAuthenticatorTransport T.AuthenticatorTransportInternal = "internal"+encodeAuthenticatorTransport (T.AuthenticatorTransportUnknown str) = str++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-authenticatortransport)+-- Decodes a string into a 'T.AuthenticatorTransport', returning+-- 'T.AuthenticatorTransportUnknown' when the string isn't known to be an enum+-- value. This is required so that relying parties can still store unknown+-- values, see+-- [transports](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-transports-slot)+-- and the clarification to that section+-- [here](https://github.com/w3c/webauthn/pull/1654)+decodeAuthenticatorTransport :: Text -> T.AuthenticatorTransport+decodeAuthenticatorTransport "usb" = T.AuthenticatorTransportUSB+decodeAuthenticatorTransport "nfc" = T.AuthenticatorTransportNFC+decodeAuthenticatorTransport "ble" = T.AuthenticatorTransportBLE+decodeAuthenticatorTransport "internal" = T.AuthenticatorTransportInternal+-- <https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-transports-slot>+-- mentions:+--+-- > The values SHOULD be members of AuthenticatorTransport but Relying Parties+-- > MUST ignore unknown values.+--+-- This is a small bug in the standard however, see+-- https://github.com/w3c/webauthn/pull/1654 which changes it to+--+-- > The values SHOULD be members of AuthenticatorTransport but Relying+-- > Parties SHOULD accept and store unknown values.+decodeAuthenticatorTransport str = T.AuthenticatorTransportUnknown str
+ src/Crypto/WebAuthn/Encoding/WebAuthnJson.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE DataKinds #-}++-- | Stability: experimental+-- This module contains functions and types for encoding 'T.CredentialOptions'+-- and decoding 'T.Credential's, based on intermediate types that implement the+-- 'ToJSON' and 'FromJSON' types respectively, matching the serialization used+-- by [webauthn-json](https://github.com/github/webauthn-json).+module Crypto.WebAuthn.Encoding.WebAuthnJson+  ( -- * Registration+    wjEncodeCredentialOptionsRegistration,+    WJCredentialOptionsRegistration,+    WJCredentialRegistration,+    wjDecodeCredentialRegistration',+    wjDecodeCredentialRegistration,++    -- * Authentication+    wjEncodeCredentialOptionsAuthentication,+    WJCredentialOptionsAuthentication,+    WJCredentialAuthentication,+    wjDecodeCredentialAuthentication,+  )+where++import Control.Monad.Except (runExceptT)+import Control.Monad.Identity (runIdentity)+import Control.Monad.Reader (runReaderT)+import Crypto.WebAuthn.AttestationStatementFormat (allSupportedFormats)+import qualified Crypto.WebAuthn.Encoding.Internal.WebAuthnJson as WJ+import qualified Crypto.WebAuthn.Model.Kinds as K+import qualified Crypto.WebAuthn.Model.Types as T+import Data.Aeson (FromJSON, ToJSON)+import Data.Text (Text)++-- | Encodes a @'T.CredentialOptions' 'K.Registration'@, which is needed for the+-- [registration ceremony](https://www.w3.org/TR/webauthn-2/#registration). The+-- resulting type from this function can be encoded using 'Data.Aeson.toJSON',+-- sent as a response, received by the Relying Party script, passed directly as the [@publicKey@](https://www.w3.org/TR/webauthn-2/#dom-credentialcreationoptions-publickey)+-- field in the argument to [webauthn-json](https://github.com/github/webauthn-json)'s [@create()@](https://github.com/github/webauthn-json#api) (or equivalent) function. The result of that function can then be decoded using 'wjDecodeCredentialRegistration'.+wjEncodeCredentialOptionsRegistration ::+  T.CredentialOptions 'K.Registration ->+  WJCredentialOptionsRegistration+wjEncodeCredentialOptionsRegistration = WJCredentialOptionsRegistration <$> WJ.encode++-- | The intermediate type returned by 'wjEncodeCredentialOptionsRegistration',+-- equivalent to the [@PublicKeyCredentialCreationOptions@](https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialcreationoptions) dictionary+newtype WJCredentialOptionsRegistration = WJCredentialOptionsRegistration+  { _unWJCredentialOptionsRegistration :: WJ.PublicKeyCredentialCreationOptions+  }+  deriving newtype (Show, Eq, ToJSON)++-- | The intermediate type as an input to 'wjDecodeCredentialRegistration',+-- equivalent to the [PublicKeyCredential](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)+-- interface with the response being an+-- [AuthenticatorAttestationResponse](https://www.w3.org/TR/webauthn-2/#authenticatorattestationresponse).+newtype WJCredentialRegistration = WJCredentialRegistration+  { unWJCredentialRegistration :: WJ.PublicKeyCredential WJ.AuthenticatorAttestationResponse+  }+  deriving newtype (Show, Eq, FromJSON, ToJSON)++-- | Decodes the intermediate 'WJCredentialRegistration' type which can be+-- parsed with 'Data.Aeson.fromJSON' from the result of+-- [webauthn-json](https://github.com/github/webauthn-json)'s+-- [@create()@](https://github.com/github/webauthn-json#api) (or equivalent)+-- function, to a @'T.Credential' 'K.Registration'@. This is the continuation+-- of 'wjEncodeCredentialOptionsRegistration'.+wjDecodeCredentialRegistration' ::+  -- | The [attestation statement formats](https://www.w3.org/TR/webauthn-2/#sctn-attestation-formats)+  -- that should be supported. The value of 'Crypto.WebAuthn.allSupportedFormats'+  -- can be passed here, but additional or custom formats may also be used if needed+  T.SupportedAttestationStatementFormats ->+  WJCredentialRegistration ->+  Either Text (T.Credential 'K.Registration 'True)+wjDecodeCredentialRegistration' supportedFormats =+  runIdentity . (`runReaderT` supportedFormats) . runExceptT . WJ.decode . unWJCredentialRegistration++-- | A version of 'wjDecodeCredentialRegistration'' with 'allSupportedFormats' passed as the supported formats+wjDecodeCredentialRegistration ::+  WJCredentialRegistration ->+  Either Text (T.Credential 'K.Registration 'True)+wjDecodeCredentialRegistration = wjDecodeCredentialRegistration' allSupportedFormats++-- | Encodes a @'T.CredentialOptions' 'K.Authentication'@, which is needed for the+-- [authentication ceremony](https://www.w3.org/TR/webauthn-2/#authentication). The+-- resulting type from this function can be encoded using 'Data.Aeson.toJSON',+-- sent as a response, received by the Relying Party script, parsed as JSON,+-- and passed directly as the [@publicKey@](https://www.w3.org/TR/webauthn-2/#dom-credentialrequestoptions-publickey)+-- field in the argument to the [@navigator.credentials.get()@](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)+-- function.+wjEncodeCredentialOptionsAuthentication ::+  T.CredentialOptions 'K.Authentication ->+  WJCredentialOptionsAuthentication+wjEncodeCredentialOptionsAuthentication = WJCredentialOptionsAuthentication <$> WJ.encode++-- | The intermediate type returned by 'wjEncodeCredentialOptionsAuthentication',+-- equivalent to the [@PublicKeyCredentialRequestOptions@](https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialrequestoptions) dictionary+newtype WJCredentialOptionsAuthentication = WJCredentialOptionsAuthentication+  { _unWJCredentialOptionsAuthentication :: WJ.PublicKeyCredentialRequestOptions+  }+  deriving newtype (Show, Eq, ToJSON)++-- | The intermediate type as an input to 'wjDecodeCredentialAuthentication',+-- equivalent to the [PublicKeyCredential](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)+-- interface with the response being an+-- [AuthenticatorAssertionResponse](https://www.w3.org/TR/webauthn-2/#authenticatorassertionresponse).+newtype WJCredentialAuthentication = WJCredentialAuthentication+  { unWJCredentialAuthentication :: WJ.PublicKeyCredential WJ.AuthenticatorAssertionResponse+  }+  deriving newtype (Show, Eq, FromJSON, ToJSON)++-- | Decodes a 'WJ.RequestedPublicKeyCredential' result, corresponding to the+-- [@PublicKeyCredential@ interface](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)+-- as returned by the [get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)+-- method while [Verifying an Authentication Assertion](https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion)+--+-- | Decodes the intermediate 'WJCredentialAuthentication' type which can be+-- parsed with 'Data.Aeson.fromJSON' from the result of+-- [webauthn-json](https://github.com/github/webauthn-json)'s+-- [@get()@](https://github.com/github/webauthn-json#api) (or equivalent)+-- function, to a @'T.Credential' 'K.Authentication' True@. This is the continuation+-- of 'wjEncodeCredentialOptionsAuthentication'+wjDecodeCredentialAuthentication ::+  WJCredentialAuthentication ->+  Either Text (T.Credential 'K.Authentication 'True)+wjDecodeCredentialAuthentication =+  runIdentity . runExceptT . WJ.decode . unWJCredentialAuthentication
src/Crypto/WebAuthn/Metadata/Service/Decode.hs view
@@ -13,7 +13,7 @@ import qualified Crypto.WebAuthn.Metadata.Service.Types as ServiceTypes import qualified Crypto.WebAuthn.Metadata.Service.WebIDL as ServiceIDL import Crypto.WebAuthn.Metadata.Statement.Decode (decodeAAGUID, decodeCertificate, decodeMetadataStatement, decodeSubjectKeyIdentifier)-import qualified Crypto.WebAuthn.WebIDL as IDL+import qualified Crypto.WebAuthn.Metadata.WebIDL as IDL import Data.Bifunctor (first) import Data.Hourglass (Date, DateTime (dtDate), ISO8601_Date (ISO8601_Date), timeParse) import Data.List.NonEmpty (NonEmpty)
src/Crypto/WebAuthn/Metadata/Service/WebIDL.hs view
@@ -20,7 +20,7 @@ import Crypto.WebAuthn.Internal.Utils (jsonEncodingOptions) import Crypto.WebAuthn.Metadata.Statement.WebIDL (AAGUID, MetadataStatement) import qualified Crypto.WebAuthn.Metadata.UAF as UAF-import qualified Crypto.WebAuthn.WebIDL as IDL+import qualified Crypto.WebAuthn.Metadata.WebIDL as IDL import qualified Data.Aeson as Aeson import Data.List.NonEmpty (NonEmpty) import GHC.Generics (Generic)
src/Crypto/WebAuthn/Metadata/Statement/Decode.hs view
@@ -19,9 +19,9 @@ import Crypto.WebAuthn.Metadata.Statement.Types (WebauthnAttestationType (WebauthnAttestationAttCA, WebauthnAttestationBasic)) import qualified Crypto.WebAuthn.Metadata.Statement.Types as StatementTypes import qualified Crypto.WebAuthn.Metadata.Statement.WebIDL as StatementIDL+import qualified Crypto.WebAuthn.Metadata.WebIDL as IDL import qualified Crypto.WebAuthn.Model as M import Crypto.WebAuthn.Model.Identifier (AAGUID (AAGUID), AuthenticatorIdentifier (AuthenticatorIdentifierFido2, AuthenticatorIdentifierFidoU2F), SubjectKeyIdentifier (SubjectKeyIdentifier))-import qualified Crypto.WebAuthn.WebIDL as IDL import Data.Bifunctor (first) import qualified Data.ByteString as BS import qualified Data.ByteString.Base16 as Base16
src/Crypto/WebAuthn/Metadata/Statement/WebIDL.hs view
@@ -28,7 +28,7 @@ import Crypto.WebAuthn.Internal.Utils (enumJSONEncodingOptions, jsonEncodingOptions) import qualified Crypto.WebAuthn.Metadata.FidoRegistry as Registry import qualified Crypto.WebAuthn.Metadata.UAF as UAF-import qualified Crypto.WebAuthn.WebIDL as IDL+import qualified Crypto.WebAuthn.Metadata.WebIDL as IDL import qualified Data.Aeson as Aeson import Data.List.NonEmpty (NonEmpty) import Data.Map (Map)
src/Crypto/WebAuthn/Metadata/UAF.hs view
@@ -9,7 +9,7 @@ where  import Crypto.WebAuthn.Internal.Utils (jsonEncodingOptions)-import qualified Crypto.WebAuthn.WebIDL as IDL+import qualified Crypto.WebAuthn.Metadata.WebIDL as IDL import qualified Data.Aeson as Aeson import Data.Text (Text) import GHC.Generics (Generic)
+ src/Crypto/WebAuthn/Metadata/WebIDL.hs view
@@ -0,0 +1,59 @@+-- | Stability: experimental+-- | This module defines some types from the [Web IDL](https://webidl.spec.whatwg.org/) specification+module Crypto.WebAuthn.Metadata.WebIDL+  ( DOMString,+    USVString,+    UnsignedLongLong,+    UnsignedLong,+    Long,+    UnsignedShort,+    Octet,+    Boolean,+    Crypto.WebAuthn.Metadata.WebIDL.Double,+  )+where++import Data.Int (Int32)+import Data.Text (Text)+import Data.Word (Word16, Word32, Word64, Word8)++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-DOMString)+-- The `[DOMString](https://webidl.spec.whatwg.org/#idl-DOMString)` type+-- corresponds to the set of all possible sequences of+-- [code units](https://webidl.spec.whatwg.org/#dfn-code-unit). Such sequences+-- are commonly interpreted as UTF-16 encoded strings+-- [RFC2781](https://webidl.spec.whatwg.org/#biblio-rfc2781) although this is not required.+-- TODO: This implementation doesn't allow invalid UTF-16 codepoints, which+-- probably makes it not work regarding <https://www.w3.org/TR/webauthn-2/#sctn-strings>+-- Write a test case that doesn't work and find a better representation.+type DOMString = Text++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-USVString)+-- The `[USVString](https://webidl.spec.whatwg.org/#idl-USVString)` type+-- corresponds to the set of all possible sequences of+-- [Unicode scalar values](http://www.unicode.org/glossary/#unicode_scalar_value),+-- which are all of the Unicode code points apart from the surrogate code points.+-- TODO: This implementation allows for surrogate code points. Figure out if+-- this can violate the spec in any way.+type USVString = Text++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-unsigned-long)+type UnsignedLong = Word32++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-unsigned-long)+type UnsignedLongLong = Word64++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-long)+type Long = Int32++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-unsigned-short)+type UnsignedShort = Word16++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-octet)+type Octet = Word8++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-boolean)+type Boolean = Bool++-- | [(spec)](https://webidl.spec.whatwg.org/#idl-double)+type Double = Prelude.Double
src/Crypto/WebAuthn/Model.hs view
@@ -4,34 +4,23 @@ -- A set of types representing credential options ('CredentialOptions') -- and their resulting credentials responses ('Credential'). ----- Also includes a set of functions for indirectly encoding credential--- options to JSON ('encodeCredentialOptionsRegistration',--- 'encodeCredentialOptionsAuthentication') and indirectly decoding--- credential responses from JSON ('decodeCredentialRegistration',--- 'decodeCredentialAuthentication'), using the same encoding as--- [webauthn-json](https://github.com/github/webauthn-json) which can be--- used on the JavaScript side.------ The types in this module form one way the library represents the WebAuthn--- types, another are the internal WebIDL modules, which is a lower-level, more--- one-to-one mapping. As a user of the library, you will most likely use the--- representation in this module over the one in the WebIDL modules.--- -- This module is reexported by the "Crypto.WebAuthn" module, which is the -- preferred way of using it. module Crypto.WebAuthn.Model-  ( module Crypto.WebAuthn.Model.Identifier,+  ( module Crypto.WebAuthn.Model.Defaults,+    module Crypto.WebAuthn.Model.Identifier,     module Crypto.WebAuthn.Model.Kinds,     module Crypto.WebAuthn.Model.Types,-    module Crypto.WebAuthn.Model.WebIDL,-    module Crypto.WebAuthn.Cose.Algorithm,-    module Crypto.WebAuthn.Cose.Key,+    module Crypto.WebAuthn.Cose.SignAlg,+    module Crypto.WebAuthn.Cose.PublicKeyWithSignAlg,+    module Crypto.WebAuthn.Cose.PublicKey,   ) where -import Crypto.WebAuthn.Cose.Algorithm-import Crypto.WebAuthn.Cose.Key+import Crypto.WebAuthn.Cose.PublicKey+import Crypto.WebAuthn.Cose.PublicKeyWithSignAlg+import Crypto.WebAuthn.Cose.SignAlg+import Crypto.WebAuthn.Model.Defaults import Crypto.WebAuthn.Model.Identifier import Crypto.WebAuthn.Model.Kinds import Crypto.WebAuthn.Model.Types-import Crypto.WebAuthn.Model.WebIDL
+ src/Crypto/WebAuthn/Model/Defaults.hs view
@@ -0,0 +1,54 @@+-- | Stability: experimental+-- This module defines default values for fields of webauthn structures that+-- are optional but have a default specified. The identifiers here all have the+-- pattern of @<field>Default@ indicating that this is the default value for+-- field @<field>@ defined in 'Crypto.WebAuthn.Model.Types'+--+-- These default values are used when the respective fields are missing during+-- decoding. They may also be used by relying parties that don't want to set+-- the respective fields to their default. This is needed because defaults for+-- such fields can't be easily mapped to Haskell's records, see+-- "Crypto.WebAuthn.Model.Types#defaultFields"+module Crypto.WebAuthn.Model.Defaults+  ( ascUserVerificationDefault,+    ascResidentKeyDefault,+    corAttestationDefault,+    corExcludeCredentialsDefault,+    coaUserVerificationDefault,+    coaAllowCredentialsDefault,+  )+where++import qualified Crypto.WebAuthn.Model.Types as M++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-userverification)+-- Returns the default of the field 'M.ascUserVerification'+ascUserVerificationDefault :: M.UserVerificationRequirement+ascUserVerificationDefault = M.UserVerificationRequirementPreferred++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-residentkey)+-- Returns the default of the field 'M.ascResidentKey' based on the+-- value of [@requireResidentKey@](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey)+ascResidentKeyDefault :: Maybe Bool -> M.ResidentKeyRequirement+ascResidentKeyDefault (Just True) = M.ResidentKeyRequirementRequired+ascResidentKeyDefault _ = M.ResidentKeyRequirementDiscouraged++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-attestation)+-- Returns the default of the field 'M.corAttestation'+corAttestationDefault :: M.AttestationConveyancePreference+corAttestationDefault = M.AttestationConveyancePreferenceNone++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-excludecredentials)+-- Returns the default of the field 'M.corExcludeCredentials'+corExcludeCredentialsDefault :: [M.CredentialDescriptor]+corExcludeCredentialsDefault = []++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-userverification)+-- Returns the default of the field 'M.coaUserVerification'+coaUserVerificationDefault :: M.UserVerificationRequirement+coaUserVerificationDefault = M.UserVerificationRequirementPreferred++-- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-allowcredentials)+-- Returns the default of the field 'M.coaAllowCredentials'+coaAllowCredentialsDefault :: [M.CredentialDescriptor]+coaAllowCredentialsDefault = []
src/Crypto/WebAuthn/Model/Types.hs view
@@ -7,12 +7,43 @@ {-# LANGUAGE TypeFamilies #-}  -- | Stability: experimental--- This module contains the same top-level definitions as 'Crypto.WebAuthn.Client.JavaScript',--- but with the types containing a more Haskell-friendly structure. ----- Note: The 'ToJSON' instances of these types are for pretty-printing purposes--- only.+-- This module contains Haskell-friendly types for structures used in WebAuthn+-- that are used throughout this library. These types are modelled according to+-- the following conventions: --+-- * If a structure has the same semantics for both the+--   [registration](https://www.w3.org/TR/webauthn-2/#registration) and+--   [authentication](https://www.w3.org/TR/webauthn-2/#authentication) WebAuthn+--   [ceremonies](https://www.w3.org/TR/webauthn-2/#ceremony), then its type is+--   parametrized by a @c@ parameter of kind 'CeremonyKind'. If such types have+--   differing fields,+--   [GADTs](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/gadt.html)+--   are used to distinguish between them, where the constructor name is the+--   type name with a @...Registration@ or @...Authentication@ suffix+-- * If the raw bytes are needed for verification purposes of a structure, then+--   its type is parametrized by a @raw@ parameter of kind 'Bool'. Only if @raw+--   ~ 'True'@, the raw bytes of the necessary structures has to be present in+--   the type. The type 'RawField' is used as a helper type for this.+-- * In order to avoid duplicate record fields, all fields are prefixed with+--   the initials of the constructor name.+-- * Every type should have a 'ToJSON' instance for pretty-printing purposes.+--   This JSON encoding doesn't correspond to any encoding used for+--   sending/receiving these structures, it's only used for pretty-printing,+--   which is why it doesn't need to be standardized. For encoding these+--   structures from/to JSON for sending/receiving, see the+--   'Crypto.WebAuthn.Model.WebIDL' module+-- #defaultFields#+-- * Fields of the WebAuthn standard that are optional (for writing) but have+--   defaults (making them non-optional for reading) are encoded as+--   non-optional fields, while the defaults are exposed in the+--   'Crypto.WebAuthn.Model.Defaults' module. The alternative of making these+--   fields optional would allow RP not having to specify them, which seems+--   like a less safer option, since the defaults might not be what is really+--   needed, and they might change. The root cause why this decision had to be+--   made is that such assymetrical reading/writing fields don't map nicely to+--   Haskell's records.+-- -- #extensions# -- TODO: -- [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-extensions) This library@@ -86,7 +117,6 @@     -- * Top-level types     CredentialOptions (..),     Credential (..),-    stripRawCredential,   ) where @@ -95,15 +125,14 @@ import Crypto.Hash (Digest) import Crypto.Hash.Algorithms (SHA256) import Crypto.Random (MonadRandom, getRandomBytes)-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import Crypto.WebAuthn.Internal.ToJSONOrphans () import Crypto.WebAuthn.Model.Identifier (AAGUID) import Crypto.WebAuthn.Model.Kinds   ( AttestationKind (Unverifiable, Verifiable),     CeremonyKind (Authentication, Registration),     ProtocolKind (Fido2, FidoU2F),-    SCeremonyKind (SAuthentication, SRegistration),   ) import Data.Aeson (ToJSON, Value (Null, String), object, (.=)) import Data.Aeson.Types (toJSON)@@ -141,6 +170,9 @@ -- values can be added to it in the future, as more credential types are defined. -- The values of this enumeration are used for versioning the Authentication Assertion -- and attestation structures according to the type of the authenticator.+--+-- To decode\/encode this type from\/to its standard string, use+-- 'Crypto.WebAuthn.Encoding.Strings.decodeCredentialType'/'Crypto.WebAuthn.Encoding.Strings.encodeCredentialType'. data CredentialType = CredentialTypePublicKey   deriving (Eq, Show, Bounded, Enum, Ord, Generic) @@ -157,6 +189,9 @@ -- best belief as to how an authenticator may be reached. A [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party) -- will typically learn of the supported transports for a [public key credential](https://www.w3.org/TR/webauthn-2/#public-key-credential) -- via [getTransports()](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-gettransports).+--+-- To decode\/encode this type from\/to its standard string, use+-- 'Crypto.WebAuthn.Encoding.Strings.decodeAuthenticatorTransport'/'Crypto.WebAuthn.Encoding.Strings.encodeAuthenticatorTransport'. data AuthenticatorTransport   = -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatortransport-usb)     -- Indicates the respective [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator)@@ -176,7 +211,15 @@     -- transport, i.e., it is a [platform authenticator](https://www.w3.org/TR/webauthn-2/#platform-authenticators).     -- These authenticators are not removable from the [client device](https://www.w3.org/TR/webauthn-2/#client-device).     AuthenticatorTransportInternal-  deriving (Eq, Show, Bounded, Enum, Ord, Generic, ToJSON)+  | -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialdescriptor-transports)+    -- An unknown authenticator transport. Note that according to the current+    -- version 2 of the WebAuthn standard, unknown fields [must be+    -- ignored](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-transports-slot),+    -- which is a bit misleading because such unknown values still need to be+    -- stored. Draft version 3 of the standard [fixes+    -- this](https://github.com/w3c/webauthn/pull/1654).+    AuthenticatorTransportUnknown Text+  deriving (Eq, Show, Ord, Generic, ToJSON)  -- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-authenticatorattachment) -- This enumeration’s values describe [authenticators](https://www.w3.org/TR/webauthn-2/#authenticator)'@@ -185,6 +228,9 @@ -- express a preferred [authenticator attachment modality](https://www.w3.org/TR/webauthn-2/#authenticator-attachment-modality) -- when calling [@navigator.credentials.create()@](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create) -- to [create a credential](https://www.w3.org/TR/webauthn-2/#sctn-createCredential).+--+-- To decode\/encode this type from\/to its standard string, use+-- 'Crypto.WebAuthn.Encoding.Strings.decodeAuthenticatorAttachment'/'Crypto.WebAuthn.Encoding.Strings.encodeAuthenticatorAttachment'. data AuthenticatorAttachment   = -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattachment-platform)     -- This value indicates [platform attachment](https://www.w3.org/TR/webauthn-2/#platform-attachment).@@ -199,6 +245,9 @@ -- requirements for [client-side discoverable credentials](https://www.w3.org/TR/webauthn-2/#client-side-discoverable-credential) -- (formerly known as [resident credentials](https://www.w3.org/TR/webauthn-2/#resident-credential) -- or [resident keys](https://www.w3.org/TR/webauthn-2/#resident-key)):+--+-- To decode\/encode this type from\/to its standard string, use+-- 'Crypto.WebAuthn.Encoding.Strings.decodeResidentKeyRequirement'/'Crypto.WebAuthn.Encoding.Strings.encodeResidentKeyRequirement'. data ResidentKeyRequirement   = -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-residentkeyrequirement-discouraged)     -- This value indicates the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)@@ -225,6 +274,9 @@ -- A [WebAuthn Relying Party](https://www.w3.org/TR/webauthn-2/#webauthn-relying-party) may -- require [user verification](https://www.w3.org/TR/webauthn-2/#user-verification) for some -- of its operations but not for others, and may use this type to express its needs.+--+-- To decode\/encode this type from\/to its standard string, use+-- 'Crypto.WebAuthn.Encoding.Strings.decodeUserVerificationRequirement'/'Crypto.WebAuthn.Encoding.Strings.encodeUserVerificationRequirement'. data UserVerificationRequirement   = -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-userverificationrequirement-required)     -- This value indicates that the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)@@ -250,6 +302,9 @@ -- [AttestationConveyancePreference](https://www.w3.org/TR/webauthn-2/#enumdef-attestationconveyancepreference) -- to specify their preference regarding -- [attestation conveyance](https://www.w3.org/TR/webauthn-2/#attestation-conveyance) during credential generation.+--+-- To decode\/encode this type from\/to its standard string, use+-- 'Crypto.WebAuthn.Encoding.Strings.decodeAttestationConveyancePreference'/'Crypto.WebAuthn.Encoding.Strings.encodeAttestationConveyancePreference'. data AttestationConveyancePreference   = -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-attestationconveyancepreference-none)     -- This value indicates that the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)@@ -604,7 +659,7 @@ -- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-authentication-extensions-client-inputs) -- This is a dictionary containing the [client extension input](https://www.w3.org/TR/webauthn-2/#client-extension-input) -- values for zero or more [WebAuthn Extensions](https://www.w3.org/TR/webauthn-2/#webauthn-extensions).--- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model#extensions".+-- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model.Types#extensions". data AuthenticationExtensionsClientInputs = AuthenticationExtensionsClientInputs   {   }@@ -616,7 +671,7 @@ -- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-authentication-extensions-client-outputs) -- This is a dictionary containing the [client extension output](https://www.w3.org/TR/webauthn-2/#client-extension-output) -- values for zero or more [WebAuthn Extensions](https://www.w3.org/TR/webauthn-2/#webauthn-extensions).--- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model#extensions".+-- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model.Types#extensions". data AuthenticationExtensionsClientOutputs = AuthenticationExtensionsClientOutputs   {   }@@ -710,7 +765,6 @@     -- This OPTIONAL member contains a hint as to how the [client](https://www.w3.org/TR/webauthn-2/#client)     -- might communicate with the [managing authenticator](https://www.w3.org/TR/webauthn-2/#public-key-credential-source-managing-authenticator)     -- of the [public key credential](https://www.w3.org/TR/webauthn-2/#public-key-credential) the caller is referring to.-    -- The values SHOULD be members of 'AuthenticatorTransport' but [client platforms](https://www.w3.org/TR/webauthn-2/#client-platform) MUST ignore unknown values.     cdTransports :: Maybe [AuthenticatorTransport]   }   deriving (Eq, Show, Generic, ToJSON)@@ -729,15 +783,14 @@     -- Specifies the extent to which the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)     -- desires to create a [client-side discoverable credential](https://www.w3.org/TR/webauthn-2/#client-side-discoverable-credential).     -- For historical reasons the naming retains the deprecated “resident” terminology.+    -- The default value of this field is 'Crypto.WebAuthn.Model.Defaults.ascResidentKeyDefault'.     ascResidentKey :: ResidentKeyRequirement,     -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-userverification)     -- This member describes the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)'s     -- requirements regarding [user verification](https://www.w3.org/TR/webauthn-2/#user-verification)     -- for the [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create)     -- operation. Eligible authenticators are filtered to only those capable of satisfying this requirement.-    -- The value SHOULD be a member of 'UserVerificationRequirement' but-    -- [client platforms](https://www.w3.org/TR/webauthn-2/#client-platform) MUST ignore unknown values,-    -- treating an unknown value as if the [member does not exist](https://infra.spec.whatwg.org/#map-exists).+    -- The default value of this field is 'Crypto.WebAuthn.Model.Defaults.ascUserVerificationDefault'.     ascUserVerification :: UserVerificationRequirement   }   deriving (Eq, Show, Generic, ToJSON)@@ -818,6 +871,7 @@       -- that wish to limit the creation of multiple credentials for the same account on a single authenticator.       -- The [client](https://www.w3.org/TR/webauthn-2/#client) is requested to return an error if the new credential       -- would be created on an authenticator that also contains one of the credentials enumerated in this parameter.+      -- The default value of this field is 'Crypto.WebAuthn.Model.Defaults.corExcludeCredentials'.       corExcludeCredentials :: [CredentialDescriptor],       -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection)       -- This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party)@@ -827,6 +881,7 @@       -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-attestation)       -- This member is intended for use by [Relying Parties](https://www.w3.org/TR/webauthn-2/#relying-party)       -- that wish to express their preference for [attestation conveyance](https://www.w3.org/TR/webauthn-2/#attestation-conveyance).+      -- The default value of this field is 'Crypto.WebAuthn.Model.Defaults.corAttestationDefault'.       corAttestation :: AttestationConveyancePreference,       -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-extensions)       -- This member contains additional parameters requesting additional processing by the client and authenticator.@@ -836,7 +891,7 @@       -- consult the IANA "WebAuthn Extension Identifiers" registry [IANA-WebAuthn-Registries](https://www.w3.org/TR/webauthn-2/#biblio-iana-webauthn-registries)       -- established by [RFC8809](https://www.w3.org/TR/webauthn-2/#biblio-rfc8809) for an up-to-date       -- list of registered [WebAuthn Extensions](https://www.w3.org/TR/webauthn-2/#webauthn-extensions).-      -- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model#extensions".+      -- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model.Types#extensions".       corExtensions :: Maybe AuthenticationExtensionsClientInputs     } ->     CredentialOptions 'Registration@@ -864,16 +919,18 @@       -- This OPTIONAL member contains a list of 'CredentialDescriptor'       -- objects representing [public key credentials](https://www.w3.org/TR/webauthn-2/#public-key-credential) acceptable to the caller,       -- in descending order of the caller’s preference (the first item in the list is the most preferred credential, and so on down the list).+      -- The default value of this field is 'Crypto.WebAuthn.Model.Defaults.coaAllowCredentialsDefault'.       coaAllowCredentials :: [CredentialDescriptor],       -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-userverification)       -- This OPTIONAL member describes the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party)'s requirements regarding       -- [user verification](https://www.w3.org/TR/webauthn-2/#user-verification) for the       -- `[get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)` operation.+      -- The default value of this field is 'Crypto.WebAuthn.Model.Defaults.coaUserVerificationDefault'.       coaUserVerification :: UserVerificationRequirement,       -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-extensions)       -- This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator.       -- For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension.-      -- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model#extensions".+      -- TODO: Extensions are not implemented by this library, see "Crypto.WebAuthn.Model.Types#extensions".       coaExtensions :: Maybe AuthenticationExtensionsClientInputs     } ->     CredentialOptions 'Authentication@@ -911,6 +968,23 @@ -- The client data represents the contextual bindings of both the -- [WebAuthn Relying Party](https://www.w3.org/TR/webauthn-2/#webauthn-relying-party) -- and the [client](https://www.w3.org/TR/webauthn-2/#client).+--+-- For binary serialization of thes type, see+-- "Crypto.WebAuthn.Encoding.Binary". If decoded with+-- 'Crypto.WebAuthn.Encoding.Binary.decodeCollectedClientData', the+-- 'ccdRawData' field is filled out with the raw bytes, while+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawCollectedClientData' can be used+-- to fill out this field when constructing this value otherwise. Unchecked+-- invariant: If @raw ~ 'True'@, then+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawCollectedClientData c = c',+-- ensuring that the 'ccdRawData' field should always correspond to its+-- encoding. This means that if @raw ~ 'True'@, it's not safe to modify+-- individual fields. To make changes, first use+-- 'Crypto.WebAuthn.Encoding.Binary.stripRawCollectedClientData', make the+-- changes on the result, then call+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawCollectedClientData' on that. Note+-- however that any modifications also invalidate signatures over the binary+-- data, specifically 'araSignature' and 'aoAttStmt'. data CollectedClientData (c :: CeremonyKind) raw = CollectedClientData   { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-challenge)     -- This member contains the challenge provided by the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party).@@ -924,8 +998,8 @@     -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-crossorigin)     -- This member contains the inverse of the @sameOriginWithAncestors@ araument value     -- that was passed into the [internal method](https://tc39.github.io/ecma262/#sec-object-internal-methods-and-internal-slots).-    ccdCrossOrigin :: Bool,-    -- | Raw data of the client data, for verification purposes+    ccdCrossOrigin :: Maybe Bool,+    -- | Raw data of the client data, for verification purposes.     ccdRawData :: RawField raw     -- TODO: This library does not implement token binding, this is in     -- anticipation of version 3 of the webauthn spec that likely removes this@@ -995,6 +1069,24 @@ -- the [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party) receives -- the [authenticator data](https://www.w3.org/TR/webauthn-2/#authenticator-data) -- in the same format, and uses its knowledge of the authenticator to make trust decisions.+--+-- For the binary serialization of this type, see+-- "Crypto.WebAuthn.Encoding.Binary". If decoded with+-- 'Crypto.WebAuthn.Encoding.Binary.decodeAuthenticatorData', the 'adRawData'+-- field is filled out with the binary serialization, while+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawAuthenticatorData' can be used to+-- fill out this field when constructing this value otherwise. This also+-- applies to raw 'acdCredentialPublicKeyBytes' field in+-- 'adAttestedCredentialData'. Unchecked invariant: If @raw ~ 'True'@, then+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawAuthenticatorData d = d', ensuring+-- that the 'adRawData' and 'acdCredentialPublicKeyBytes' fields should always+-- correspond to their respective binary serializations. This means that if+-- @raw ~ 'True'@, it's not safe to modify individual fields. To make changes,+-- first use 'Crypto.WebAuthn.Encoding.Binary.stripRawAuthenticatorData', make+-- the changes on the result, then call+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawAuthenticatorData' on that. Note+-- however that any modifications also invalidate signatures over the binary+-- data, specifically 'araSignature' and 'aoAttStmt'. data AuthenticatorData (c :: CeremonyKind) raw = AuthenticatorData   { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#rpidhash)     -- SHA-256 hash of the [RP ID](https://www.w3.org/TR/webauthn-2/#rp-id) the@@ -1153,6 +1245,26 @@ lookupAttestationStatementFormat id (SupportedAttestationStatementFormats sasf) = sasf !? id  -- | [(spec)](https://www.w3.org/TR/webauthn-2/#attestation-object)+--+-- For the [binary+-- serialization](https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object)+-- of this type, see "Crypto.WebAuthn.Encoding.Binary". If decoded with+-- 'Crypto.WebAuthn.Encoding.Binary.decodeAttestationObject', the 'aoAuthData'+-- field is filled out with the binary serialization of its fields, while+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawAttestationObject' can be used to+-- fill out this field when constructing this value otherwise. Unchecked+-- invariant: If @raw ~ 'True'@, then+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawAttestationObject o = o', ensuring+-- that the binary fields of the 'aoAuthData' field should always correspond to+-- their respective serializations. This means that if @raw ~ 'True'@, it's not+-- safe to modify individual fields. To make changes, first use+-- 'Crypto.WebAuthn.Encoding.Binary.stripRawAttestationObject', make the+-- changes on the result, then call+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawAttestationObject' on that. Note+-- however that any modifications also invalidate signatures over the binary+-- data, specifically 'aoAttStmt'. The+-- 'Crypto.WebAuthn.Encoding.Binary.encodeAttestationObject' can be used to get+-- the binary encoding of this type when @raw ~ 'True'@. data AttestationObject raw = forall a.   AttestationStatementFormat a =>   AttestationObject@@ -1171,8 +1283,38 @@     -- in the same format, and uses its knowledge of the authenticator to make trust decisions.     aoAuthData :: AuthenticatorData 'Registration raw,     -- | [(spec)](https://www.w3.org/TR/webauthn-2/#attestation-statement-format)+    -- The attestation statement format is the manner in which the signature is+    -- represented and the various contextual bindings are incorporated into+    -- the attestation statement by the+    -- [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator). In+    -- other words, this defines the syntax of the statement. Various existing+    -- components and OS platforms (such as TPMs and the Android OS) have+    -- previously defined [attestation statement+    -- formats](https://www.w3.org/TR/webauthn-2/#attestation-statement-format).+    -- This specification supports a variety of such formats in an extensible+    -- way, as defined in [§ 6.5.2 Attestation Statement+    -- Formats](https://www.w3.org/TR/webauthn-2/#sctn-attestation-formats).+    -- The formats themselves are identified by strings, as described in [§ 8.1+    -- Attestation Statement Format+    -- Identifiers](https://www.w3.org/TR/webauthn-2/#sctn-attstn-fmt-ids).+    --+    -- This value is of a type that's an instance of+    -- 'AttestationStatementFormat', which encodes everything needed about the+    -- attestation statement.     aoFmt :: a,     -- | [(spec)](https://www.w3.org/TR/webauthn-2/#attestation-statement)+    -- The [(spec)](https://www.w3.org/TR/webauthn-2/#attestation-statement) is+    -- a specific type of signed data object, containing statements about a+    -- [public key+    -- credential](https://www.w3.org/TR/webauthn-2/#public-key-credential)+    -- itself and the+    -- [authenticator](https://www.w3.org/TR/webauthn-2/#authenticator) that+    -- created it. It contains an [attestation+    -- signature](https://www.w3.org/TR/webauthn-2/#attestation-signature)+    -- created using the key of the attesting authority (except for the case of+    -- [self attestation](https://www.w3.org/TR/webauthn-2/#self-attestation),+    -- when it is created using the [credential private+    -- key](https://www.w3.org/TR/webauthn-2/#credential-private-key)).     aoAttStmt :: AttStmt a   } @@ -1271,7 +1413,9 @@       -- returned by the authenticator. See [§ 6.1 Authenticator Data](https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data).       araAuthenticatorData :: AuthenticatorData 'Authentication raw,       -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-signature)-      -- This attribute contains the raw signature returned from the authenticator.+      -- This attribute contains the raw [assertion+      -- signature](https://www.w3.org/TR/webauthn-2/#assertion-signature)+      -- returned from the authenticator.       -- See [§ 6.3.3 The authenticatorGetAssertion Operation](https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion).       araSignature :: AssertionSignature,       -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-userhandle)@@ -1303,6 +1447,22 @@  -- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-pkcredential) -- The 'Credential' interface contains the attributes that are returned to the caller when a new credential is created, or a new assertion is requested.+--+-- This type has nested fields which use a binary encoding that needs to be+-- preserved for verification purposes. The binary encoding of these fields can+-- be removed or recomputed using functions from+-- "Crypto.WebAuthn.Encoding.Binary". Specifically+-- 'Crypto.WebAuthn.Encoding.Binary.stripRawCredential' and+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawCredential' respectively.+-- Unchecked invariant: If @raw ~ 'True'@, then+-- 'Crypto.WebAuthn.Encoding.Binary.encodeRawCredential c = c', ensuring that+-- the binary fields should always correspond to the values respective+-- serializations. This means that if @raw ~ 'True'@, it's not safe to modify+-- individual fields. To make changes, first use+-- 'Crypto.WebAuthn.Encoding.Binary.stripRawCredential', make the changes on+-- the result, then call 'Crypto.WebAuthn.Encoding.Binary.encodeRawCredential'+-- on that. Note however that any modifications also invalidate signatures over+-- the binary data, specifically 'araSignature' and 'aoAttStmt'. data Credential (c :: CeremonyKind) raw = Credential   { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredential-identifier-slot)     -- Contains the [credential ID](https://www.w3.org/TR/webauthn-2/#credential-id),@@ -1330,54 +1490,3 @@     cClientExtensionResults :: AuthenticationExtensionsClientOutputs   }   deriving (Eq, Show, Generic, ToJSON)---- | Removes all raw fields from a 'Credential', useful for--- e.g. pretty-printing only the desired fields. This is the counterpart to--- 'Crypto.WebAuthn.Model.Binary.Encoding.encodeRawCredential'-stripRawCredential :: forall c raw. SingI c => Credential c raw -> Credential c 'False-stripRawCredential Credential {..} =-  Credential-    { cResponse = case sing @c of-        SRegistration -> stripRawAuthenticatorResponseRegistration cResponse-        SAuthentication -> stripRawAuthenticatorResponseAuthentication cResponse,-      ..-    }-  where-    stripRawAuthenticatorResponseAuthentication :: AuthenticatorResponse 'Authentication raw -> AuthenticatorResponse 'Authentication 'False-    stripRawAuthenticatorResponseAuthentication AuthenticatorResponseAuthentication {..} =-      AuthenticatorResponseAuthentication-        { araClientData = stripRawCollectedClientData araClientData,-          araAuthenticatorData = stripRawAuthenticatorData araAuthenticatorData,-          ..-        }--    stripRawAuthenticatorResponseRegistration :: AuthenticatorResponse 'Registration raw -> AuthenticatorResponse 'Registration 'False-    stripRawAuthenticatorResponseRegistration AuthenticatorResponseRegistration {..} =-      AuthenticatorResponseRegistration-        { arrClientData = stripRawCollectedClientData arrClientData,-          arrAttestationObject = stripRawAttestationObject arrAttestationObject,-          ..-        }--    stripRawAttestationObject :: AttestationObject raw -> AttestationObject 'False-    stripRawAttestationObject AttestationObject {..} =-      AttestationObject-        { aoAuthData = stripRawAuthenticatorData aoAuthData,-          ..-        }--    stripRawAuthenticatorData :: forall c raw. SingI c => AuthenticatorData c raw -> AuthenticatorData c 'False-    stripRawAuthenticatorData AuthenticatorData {..} =-      AuthenticatorData-        { adRawData = NoRaw,-          adAttestedCredentialData = stripRawAttestedCredentialData adAttestedCredentialData,-          ..-        }--    stripRawAttestedCredentialData :: forall c raw. SingI c => AttestedCredentialData c raw -> AttestedCredentialData c 'False-    stripRawAttestedCredentialData = case sing @c of-      SRegistration -> \AttestedCredentialData {..} -> AttestedCredentialData {acdCredentialPublicKeyBytes = NoRaw, ..}-      SAuthentication -> \NoAttestedCredentialData -> NoAttestedCredentialData--    stripRawCollectedClientData :: forall c raw. SingI c => CollectedClientData c raw -> CollectedClientData c 'False-    stripRawCollectedClientData CollectedClientData {..} = CollectedClientData {ccdRawData = NoRaw, ..}
− src/Crypto/WebAuthn/Model/WebIDL.hs
@@ -1,112 +0,0 @@-{-# LANGUAGE DataKinds #-}---- | Stability: experimental--- This module contains functions and types for encoding 'T.CredentialOptions'--- and decoding 'T.Credential's, based on intermediate types that implement the 'ToJSON' and 'FromJSON' types respectively, matching the serialization used by [webauthn-json](https://github.com/github/webauthn-json).-module Crypto.WebAuthn.Model.WebIDL-  ( -- * Registration-    encodeCredentialOptionsRegistration,-    IDLCredentialOptionsRegistration,-    IDLCredentialRegistration,-    decodeCredentialRegistration,--    -- * Authentication-    encodeCredentialOptionsAuthentication,-    IDLCredentialOptionsAuthentication,-    IDLCredentialAuthentication,-    decodeCredentialAuthentication,-  )-where--import qualified Crypto.WebAuthn.Model.Kinds as K-import qualified Crypto.WebAuthn.Model.Types as T-import Crypto.WebAuthn.Model.WebIDL.Internal.Decoding (Decode (decode), DecodeCreated (decodeCreated))-import Crypto.WebAuthn.Model.WebIDL.Internal.Encoding (Encode (encode))-import qualified Crypto.WebAuthn.Model.WebIDL.Types as IDL-import Data.Aeson (FromJSON, ToJSON)-import Data.Text (Text)---- | Encodes a @'T.CredentialOptions' 'K.Registration'@, which is needed for the--- [registration ceremony](https://www.w3.org/TR/webauthn-2/#registration). The--- resulting type from this function can be encoded using 'Data.Aeson.toJSON',--- sent as a response, received by the Relying Party script, passed directly as the [@publicKey@](https://www.w3.org/TR/webauthn-2/#dom-credentialcreationoptions-publickey)--- field in the argument to [webauthn-json](https://github.com/github/webauthn-json)'s [@create()@](https://github.com/github/webauthn-json#api) (or equivalent) function. The result of that function can then be decoded using 'decodeCredentialRegistration'.-encodeCredentialOptionsRegistration ::-  T.CredentialOptions 'K.Registration ->-  IDLCredentialOptionsRegistration-encodeCredentialOptionsRegistration = IDLCredentialOptionsRegistration <$> encode---- | The intermediate type returned by 'encodeCredentialOptionsRegistration',--- equivalent to the [@PublicKeyCredentialCreationOptions@](https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialcreationoptions) dictionary-newtype IDLCredentialOptionsRegistration = IDLCredentialOptionsRegistration-  { _unIDLCredentialOptionsRegistration :: IDL.PublicKeyCredentialCreationOptions-  }-  deriving newtype (Show, Eq, ToJSON)---- | The intermediate type as an input to 'decodeCredentialRegistration',--- equivalent to the [PublicKeyCredential](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)--- interface with the response being an--- [AuthenticatorAttestationResponse](https://www.w3.org/TR/webauthn-2/#authenticatorattestationresponse).-newtype IDLCredentialRegistration = IDLCredentialRegistration-  { unIDLCredentialRegistration :: IDL.PublicKeyCredential IDL.AuthenticatorAttestationResponse-  }-  deriving newtype (Show, Eq, FromJSON, ToJSON)---- | Decodes the intermediate 'IDLCredentialRegistration' type which can be--- parsed with 'Data.Aeson.fromJSON' from the result of--- [webauthn-json](https://github.com/github/webauthn-json)'s--- [@create()@](https://github.com/github/webauthn-json#api) (or equivalent)--- function, to a @'T.Credential' 'K.Registration'@. This is the continuation--- of 'encodeCredentialOptionsRegistration'.-decodeCredentialRegistration ::-  -- | The [attestation statement formats](https://www.w3.org/TR/webauthn-2/#sctn-attestation-formats)-  -- that should be supported. The value of 'Crypto.WebAuthn.allSupportedFormats'-  -- can be passed here, but additional or custom formats may also be used if needed-  T.SupportedAttestationStatementFormats ->-  IDLCredentialRegistration ->-  Either Text (T.Credential 'K.Registration 'True)-decodeCredentialRegistration supportedFormats = decodeCreated supportedFormats . unIDLCredentialRegistration---- | Encodes a @'T.CredentialOptions' 'K.Authentication'@, which is needed for the--- [authentication ceremony](https://www.w3.org/TR/webauthn-2/#authentication). The--- resulting type from this function can be encoded using 'Data.Aeson.toJSON',--- sent as a response, received by the Relying Party script, parsed as JSON,--- and passed directly as the [@publicKey@](https://www.w3.org/TR/webauthn-2/#dom-credentialrequestoptions-publickey)--- field in the argument to the [@navigator.credentials.get()@](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)--- function.-encodeCredentialOptionsAuthentication ::-  T.CredentialOptions 'K.Authentication ->-  IDLCredentialOptionsAuthentication-encodeCredentialOptionsAuthentication = IDLCredentialOptionsAuthentication <$> encode---- | The intermediate type returned by 'encodeCredentialOptionsAuthentication',--- equivalent to the [@PublicKeyCredentialRequestOptions@](https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialrequestoptions) dictionary-newtype IDLCredentialOptionsAuthentication = IDLCredentialOptionsAuthentication-  { _unIDLCredentialOptionsAuthentication :: IDL.PublicKeyCredentialRequestOptions-  }-  deriving newtype (Show, Eq, ToJSON)---- | The intermediate type as an input to 'decodeCredentialAuthentication',--- equivalent to the [PublicKeyCredential](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)--- interface with the response being an--- [AuthenticatorAssertionResponse](https://www.w3.org/TR/webauthn-2/#authenticatorassertionresponse).-newtype IDLCredentialAuthentication = IDLCredentialAuthentication-  { unIDLCredentialAuthentication :: IDL.PublicKeyCredential IDL.AuthenticatorAssertionResponse-  }-  deriving newtype (Show, Eq, FromJSON, ToJSON)---- | Decodes a 'IDL.RequestedPublicKeyCredential' result, corresponding to the--- [@PublicKeyCredential@ interface](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)--- as returned by the [get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)--- method while [Verifying an Authentication Assertion](https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion)------ | Decodes the intermediate 'IDLCredentialAuthentication' type which can be--- parsed with 'Data.Aeson.fromJSON' from the result of--- [webauthn-json](https://github.com/github/webauthn-json)'s--- [@get()@](https://github.com/github/webauthn-json#api) (or equivalent)--- function, to a @'T.Credential' 'K.Authentication' True@. This is the continuation--- of 'encodeCredentialOptionsAuthentication'-decodeCredentialAuthentication ::-  IDLCredentialAuthentication ->-  Either Text (T.Credential 'K.Authentication 'True)-decodeCredentialAuthentication = decode . unIDLCredentialAuthentication
− src/Crypto/WebAuthn/Model/WebIDL/Internal/Binary/Decoding.hs
@@ -1,260 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}---- | Stability: internal--- Certain parts of the specification require that data is decoded from a--- binary form. This module holds such functions.-module Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding-  ( -- * Decoding from bytes-    decodeAuthenticatorData,-    decodeAttestationObject,-    decodeCollectedClientData,-  )-where--import qualified Codec.CBOR.Decoding as CBOR-import qualified Codec.CBOR.Read as CBOR-import qualified Codec.CBOR.Term as CBOR-import Codec.Serialise (decode)-import Control.Monad (forM, unless)-import Control.Monad.Except (MonadError (throwError))-import Control.Monad.State (MonadState (get, put), StateT (runStateT))-import qualified Crypto.Hash as Hash-import Crypto.WebAuthn.Internal.Utils (jsonEncodingOptions)-import Crypto.WebAuthn.Model.Identifier (AAGUID (AAGUID))-import qualified Crypto.WebAuthn.Model.Kinds as K-import qualified Crypto.WebAuthn.Model.Types as M-import qualified Crypto.WebAuthn.WebIDL as IDL-import qualified Data.Aeson as Aeson-import Data.Bifunctor (first)-import qualified Data.Binary.Get as Binary-import qualified Data.Bits as Bits-import qualified Data.ByteString as BS-import qualified Data.ByteString.Base64 as Base64-import qualified Data.ByteString.Base64.URL as Base64Url-import qualified Data.ByteString.Lazy as LBS-import qualified Data.HashMap.Strict as HashMap-import Data.Maybe (fromJust, fromMaybe)-import Data.Singletons (SingI, sing)-import Data.Text (Text)-import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text-import qualified Data.UUID as UUID-import GHC.Generics (Generic)---- | Webauthn contains a mixture of binary formats. For one it's CBOR and--- for another it's a custom format. For CBOR we wish to use the--- [cborg](https://hackage.haskell.org/package/cborg) library--- and for the custom binary format the [binary](https://hackage.haskell.org/package/binary)--- library. However these two libraries don't interact nicely with each other.--- Because of this we are specifying the decoders as a 'PartialBinaryDecoder DecodingError',--- which is just a function that can partially consume a 'LBS.ByteString'.--- Using this we can somewhat easily flip between the two libraries while--- decoding without too much nastiness.-type PartialBinaryDecoder a = StateT LBS.ByteString (Either Text) a---- | Runs a 'PartialBinaryDecoder' using a strict bytestring. Afterwards it--- makes sure that no bytes are left, otherwise returns an error-runPartialBinaryDecoder :: BS.ByteString -> PartialBinaryDecoder a -> Either Text a-runPartialBinaryDecoder bytes decoder = case runStateT decoder . LBS.fromStrict $ bytes of-  Left err -> Left err-  Right (result, rest)-    | LBS.null rest -> return result-    | otherwise -> Left $ "Not all binary input used, rest in base64 format is: " <> Text.decodeUtf8 (Base64.encode $ LBS.toStrict rest)---- | A 'PartialBinaryDecoder DecodingError' for a binary encoding specified using 'Binary.Get'-runBinary :: Binary.Get a -> PartialBinaryDecoder a-runBinary decoder = do-  bytes <- get-  case Binary.runGetOrFail decoder bytes of-    Left (_rest, _offset, err) ->-      throwError $ "Binary decoding error: " <> Text.pack err-    Right (rest, _offset, result) -> do-      put rest-      pure result---- | A 'PartialBinaryDecoder DecodingError' for a CBOR encoding specified using the given Decoder-runCBOR :: (forall s. CBOR.Decoder s a) -> PartialBinaryDecoder (LBS.ByteString, a)-runCBOR decoder = do-  bytes <- get-  case CBOR.deserialiseFromBytesWithSize decoder bytes of-    Left err ->-      throwError $ "CBOR decoding error: " <> Text.pack (show err)-    Right (rest, consumed, a) -> do-      put rest-      pure (LBS.take (fromIntegral consumed) bytes, a)---- | Decodes a 'M.AuthenticatorData' from a 'BS.ByteString'.--- This is needed to parse a webauthn clients--- [authenticatorData](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata)--- field in the [AuthenticatorAssertionResponse](https://www.w3.org/TR/webauthn-2/#iface-authenticatorassertionresponse)--- structure-decodeAuthenticatorData ::-  forall c.-  SingI c =>-  BS.ByteString ->-  Either Text (M.AuthenticatorData c 'True)-decodeAuthenticatorData strictBytes = runPartialBinaryDecoder strictBytes $ do-  -- https://www.w3.org/TR/webauthn-2/#authenticator-data-  let adRawData = M.WithRaw strictBytes--  -- https://www.w3.org/TR/webauthn-2/#rpidhash-  adRpIdHash <--    M.RpIdHash . fromJust . Hash.digestFromByteString-      <$> runBinary (Binary.getByteString 32)--  -- https://www.w3.org/TR/webauthn-2/#flags-  bitFlags <- runBinary Binary.getWord8-  let adFlags =-        M.AuthenticatorDataFlags-          { M.adfUserPresent = Bits.testBit bitFlags 0,-            M.adfUserVerified = Bits.testBit bitFlags 2-          }--  -- https://www.w3.org/TR/webauthn-2/#signcount-  adSignCount <- M.SignatureCounter <$> runBinary Binary.getWord32be--  -- https://www.w3.org/TR/webauthn-2/#attestedcredentialdata-  adAttestedCredentialData <- case (sing @c, Bits.testBit bitFlags 6) of-    -- For [attestation signatures](https://www.w3.org/TR/webauthn-2/#attestation-signature),-    -- the authenticator MUST set the AT [flag](https://www.w3.org/TR/webauthn-2/#flags)-    -- and include the `[attestedCredentialData](https://www.w3.org/TR/webauthn-2/#attestedcredentialdata)`.-    (K.SRegistration, True) -> decodeAttestedCredentialData-    (K.SRegistration, False) -> throwError "Expected attested credential data, but there is none"-    -- For [assertion signatures](https://www.w3.org/TR/webauthn-2/#assertion-signature),-    -- the AT [flag](https://www.w3.org/TR/webauthn-2/#flags) MUST NOT be set and the-    -- `[attestedCredentialData](https://www.w3.org/TR/webauthn-2/#attestedcredentialdata)` MUST NOT be included.-    (K.SAuthentication, False) -> pure M.NoAttestedCredentialData-    (K.SAuthentication, True) -> throwError "Expected no attested credential data, but there is"--  -- https://www.w3.org/TR/webauthn-2/#authdataextensions-  adExtensions <--    if Bits.testBit bitFlags 7-      then Just <$> decodeExtensions-      else pure Nothing--  pure M.AuthenticatorData {..}-  where-    decodeAttestedCredentialData :: PartialBinaryDecoder (M.AttestedCredentialData 'K.Registration 'True)-    decodeAttestedCredentialData = do-      -- https://www.w3.org/TR/webauthn-2/#aaguid-      acdAaguid <--        -- Note: fromJust is safe because UUID.fromByteString only returns-        -- nothing if there's not exactly 16 bytes-        AAGUID . fromJust . UUID.fromByteString-          <$> runBinary (Binary.getLazyByteString 16)--      -- https://www.w3.org/TR/webauthn-2/#credentialidlength-      credentialLength <--        runBinary Binary.getWord16be--      -- https://www.w3.org/TR/webauthn-2/#credentialid-      acdCredentialId <--        M.CredentialId-          <$> runBinary (Binary.getByteString (fromIntegral credentialLength))--      -- https://www.w3.org/TR/webauthn-2/#credentialpublickey-      (usedBytes, acdCredentialPublicKey) <- runCBOR decode-      let acdCredentialPublicKeyBytes = M.WithRaw $ LBS.toStrict usedBytes--      pure M.AttestedCredentialData {..}--    decodeExtensions :: PartialBinaryDecoder M.AuthenticatorExtensionOutputs-    decodeExtensions = do-      -- TODO: Extensions are not implemented by this library, see the TODO in the-      -- module documentation of `Crypto.WebAuthn.Model` for more information.-      (_, _extensions :: CBOR.Term) <- runCBOR CBOR.decodeTerm-      pure M.AuthenticatorExtensionOutputs {}---- | Decodes a 'M.AttestationObject' from a 'BS.ByteString'.--- This is needed to parse a webauthn clients--- [attestationObject](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-attestationobject)--- field in the [AuthenticatorAttestationResponse](https://www.w3.org/TR/webauthn-2/#iface-authenticatorattestationresponse)--- structure This function takes a 'M.SupportedAttestationStatementFormats'--- argument to indicate which attestation statement formats are supported.--- structure-decodeAttestationObject :: M.SupportedAttestationStatementFormats -> BS.ByteString -> Either Text (M.AttestationObject 'True)-decodeAttestationObject supportedFormats bytes = do-  (_consumed, result) <- runPartialBinaryDecoder bytes (runCBOR CBOR.decodeTerm)-  pairs <- case result of-    CBOR.TMap pairs -> return pairs-    _ -> Left $ "The attestation object should be a CBOR map, but it's not: " <> Text.pack (show result)--  -- https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object-  case (CBOR.TString "authData" `lookup` pairs, CBOR.TString "fmt" `lookup` pairs, CBOR.TString "attStmt" `lookup` pairs) of-    (Just (CBOR.TBytes authDataBytes), Just (CBOR.TString fmt), Just (CBOR.TMap attStmtPairs)) -> do-      aoAuthData <- decodeAuthenticatorData authDataBytes--      case M.lookupAttestationStatementFormat fmt supportedFormats of-        Nothing -> Left $ "Unknown attestation statement format: " <> fmt-        Just (M.SomeAttestationStatementFormat aoFmt) -> do-          attStmtMap <--            HashMap.fromList-              <$> forM-                attStmtPairs-                ( \case-                    (CBOR.TString text, term) -> pure (text, term)-                    (nonString, _) -> Left $ "Unexpected non-string attestation statement key: " <> Text.pack (show nonString)-                )-          aoAttStmt <- M.asfDecode aoFmt attStmtMap-          pure M.AttestationObject {..}-    _ -> Left $ "The attestation object doesn't have the expected structure of (authData: bytes, fmt: string, attStmt: map): " <> Text.pack (show result)----- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-client-data)---- Intermediate type used to extract the JSON structure stored in the---- CBOR-encoded [clientDataJSON](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson).-data ClientDataJSON = ClientDataJSON-  { littype :: IDL.DOMString,-    challenge :: IDL.DOMString,-    origin :: IDL.DOMString,-    crossOrigin :: Maybe IDL.Boolean-    -- TODO: We do not implement TokenBinding, see the documentation of-    -- `CollectedClientData` for more information.-    -- tokenBinding :: Maybe TokenBinding-  }-  deriving (Generic)---- Note: Encoding should NOT be derived via aeson. See the Encoding module instead-instance Aeson.FromJSON ClientDataJSON where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions---- | Decodes a 'M.CollectedClientData' from a 'BS.ByteString'. This is needed--- to parse the [clientDataJSON](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)--- field in the [AuthenticatorResponse](https://www.w3.org/TR/webauthn-2/#iface-authenticatorresponse)--- structure, which is used for both attestation and assertion-decodeCollectedClientData :: forall (c :: K.CeremonyKind). SingI c => BS.ByteString -> Either Text (M.CollectedClientData c 'True)-decodeCollectedClientData bytes = do-  -- https://www.w3.org/TR/webauthn-2/#collectedclientdata-json-compatible-serialization-of-client-data-  ClientDataJSON {..} <--    first (("Collected client data JSON decoding error: " <>) . Text.pack) $-      Aeson.eitherDecodeStrict bytes-  -- [(spec)](https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-challenge)-  -- This member contains the base64url encoding of the challenge provided by the-  -- [Relying Party](https://www.w3.org/TR/webauthn-2/#relying-party). See the-  -- [§ 13.4.3 Cryptographic Challenges](https://www.w3.org/TR/webauthn-2/#sctn-cryptographic-challenges)-  -- security consideration.-  challenge <--    first ((("Failed to base64url-decode challenge " <> challenge <> ": ") <>) . Text.pack) $-      Base64Url.decode (Text.encodeUtf8 challenge)-  -- [(spec)](https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-type)-  -- This member contains the string "webauthn.create" when creating new credentials,-  -- and "webauthn.get" when getting an assertion from an existing credential.-  -- The purpose of this member is to prevent certain types of signature confusion-  -- attacks (where an attacker substitutes one legitimate signature for another).-  let expectedType = case sing @c of-        K.SRegistration -> "webauthn.create"-        K.SAuthentication -> "webauthn.get"-  unless (littype == expectedType) $-    Left $-      "Expected collected client data to have webauthn type " <> expectedType <> " but it is " <> littype-  pure-    M.CollectedClientData-      { ccdChallenge = M.Challenge challenge,-        ccdOrigin = M.Origin origin,-        ccdCrossOrigin = fromMaybe False crossOrigin,-        ccdRawData = M.WithRaw bytes-      }
− src/Crypto/WebAuthn/Model/WebIDL/Internal/Binary/Encoding.hs
@@ -1,200 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}---- | Stability: internal--- Certain parts of the specification require that data is encoded to a--- binary form. This module holds such functions.-module Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding-  ( -- * Encoding raw fields-    encodeRawCredential,-    encodeRawAuthenticatorData,-    encodeRawCollectedClientData,--    -- * Encoding structures to bytes-    encodeAttestationObject,-    encodeCollectedClientData,-  )-where--import qualified Codec.CBOR.Term as CBOR-import qualified Codec.CBOR.Write as CBOR-import Codec.Serialise (Serialise (encode))-import Crypto.WebAuthn.Model.Identifier (AAGUID (unAAGUID))-import qualified Crypto.WebAuthn.Model.Kinds as K-import qualified Crypto.WebAuthn.Model.Types as M-import qualified Data.Aeson as Aeson-import qualified Data.Binary.Put as Binary-import Data.Bits ((.|.))-import qualified Data.Bits as Bits-import Data.ByteArray (convert)-import qualified Data.ByteString as BS-import qualified Data.ByteString.Base64.URL as Base64Url-import Data.ByteString.Builder (Builder, stringUtf8, toLazyByteString)-import qualified Data.ByteString.Lazy as LBS-import Data.Singletons (SingI, sing)-import Data.Text (Text)-import Data.Text.Encoding (decodeUtf8)-import qualified Data.UUID as UUID-import Data.Word (Word16, Word8)---- | Encodes all raw fields of a 'M.Credential'. This function is--- mainly useful for testing that the encoding/decoding functions are correct.--- The counterpart to this function is 'Crypto.WebAuthn.Model.Binary.Decoding.stripRawCredential'-encodeRawCredential :: forall (c :: K.CeremonyKind) raw. SingI c => M.Credential c raw -> M.Credential c 'True-encodeRawCredential M.Credential {..} =-  M.Credential-    { cResponse = case sing @c of-        K.SRegistration -> encodeRawAuthenticatorResponseRegistration cResponse-        K.SAuthentication -> encodeRawAuthenticatorResponseAuthentication cResponse,-      ..-    }-  where-    encodeRawAuthenticatorResponseAuthentication :: M.AuthenticatorResponse 'K.Authentication raw -> M.AuthenticatorResponse 'K.Authentication 'True-    encodeRawAuthenticatorResponseAuthentication M.AuthenticatorResponseAuthentication {..} =-      M.AuthenticatorResponseAuthentication-        { araClientData = encodeRawCollectedClientData araClientData,-          araAuthenticatorData = encodeRawAuthenticatorData araAuthenticatorData,-          ..-        }--    encodeRawAuthenticatorResponseRegistration :: M.AuthenticatorResponse 'K.Registration raw -> M.AuthenticatorResponse 'K.Registration 'True-    encodeRawAuthenticatorResponseRegistration M.AuthenticatorResponseRegistration {..} =-      M.AuthenticatorResponseRegistration-        { arrClientData = encodeRawCollectedClientData arrClientData,-          arrAttestationObject = encodeRawAttestationObject arrAttestationObject,-          ..-        }--    encodeRawAttestationObject :: M.AttestationObject raw -> M.AttestationObject 'True-    encodeRawAttestationObject M.AttestationObject {..} =-      M.AttestationObject-        { aoAuthData = encodeRawAuthenticatorData aoAuthData,-          ..-        }---- | Encodes all raw fields of a 'M.AuthenticatorData'. This function is needed--- for an authenticator implementation-encodeRawAuthenticatorData :: forall c raw. SingI c => M.AuthenticatorData c raw -> M.AuthenticatorData c 'True-encodeRawAuthenticatorData M.AuthenticatorData {..} =-  M.AuthenticatorData-    { adRawData = M.WithRaw bytes,-      adAttestedCredentialData = rawAttestedCredentialData,-      ..-    }-  where-    rawAttestedCredentialData = encodeRawAttestedCredentialData adAttestedCredentialData--    bytes :: BS.ByteString-    bytes = LBS.toStrict $ toLazyByteString builder--    -- https://www.w3.org/TR/webauthn-2/#flags-    flags :: Word8-    flags =-      userPresentFlag-        .|. userVerifiedFlag-        .|. attestedCredentialDataPresentFlag-        .|. extensionsPresentFlag-      where-        userPresentFlag = if M.adfUserPresent adFlags then Bits.bit 0 else 0-        userVerifiedFlag = if M.adfUserVerified adFlags then Bits.bit 2 else 0-        attestedCredentialDataPresentFlag = case sing @c of-          K.SRegistration -> Bits.bit 6-          K.SAuthentication -> 0-        extensionsPresentFlag = case adExtensions of-          Just _ -> Bits.bit 7-          Nothing -> 0--    -- https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data-    builder :: Builder-    builder =-      Binary.execPut (Binary.putByteString $ convert $ M.unRpIdHash adRpIdHash)-        <> Binary.execPut (Binary.putWord8 flags)-        <> Binary.execPut (Binary.putWord32be $ M.unSignatureCounter adSignCount)-        <> ( case sing @c of-               K.SRegistration -> encodeAttestedCredentialData rawAttestedCredentialData-               K.SAuthentication -> mempty-           )-        <> maybe mempty encodeExtensions adExtensions--    encodeExtensions :: M.AuthenticatorExtensionOutputs -> Builder-    encodeExtensions M.AuthenticatorExtensionOutputs {} = CBOR.toBuilder $ CBOR.encodeTerm (CBOR.TMap [])--    -- https://www.w3.org/TR/webauthn-2/#sctn-attested-credential-data-    encodeAttestedCredentialData :: M.AttestedCredentialData 'K.Registration 'True -> Builder-    encodeAttestedCredentialData M.AttestedCredentialData {..} =-      Binary.execPut (Binary.putLazyByteString $ UUID.toByteString $ unAAGUID acdAaguid)-        <> Binary.execPut (Binary.putWord16be credentialLength)-        <> Binary.execPut (Binary.putByteString $ M.unCredentialId acdCredentialId)-        <> Binary.execPut (Binary.putByteString $ M.unRaw acdCredentialPublicKeyBytes)-      where-        credentialLength :: Word16-        credentialLength = fromIntegral $ BS.length $ M.unCredentialId acdCredentialId--    encodeRawAttestedCredentialData :: forall (c :: K.CeremonyKind) raw. SingI c => M.AttestedCredentialData c raw -> M.AttestedCredentialData c 'True-    encodeRawAttestedCredentialData = case sing @c of-      K.SRegistration -> \M.AttestedCredentialData {..} ->-        M.AttestedCredentialData-          { acdCredentialPublicKeyBytes =-              M.WithRaw $ LBS.toStrict $ CBOR.toLazyByteString $ encode acdCredentialPublicKey,-            ..-          }-      K.SAuthentication -> \M.NoAttestedCredentialData -> M.NoAttestedCredentialData---- | Encodes all raw fields of a 'M.CollectedClientData'. This function is--- needed for a client implementation-encodeRawCollectedClientData :: forall c raw. SingI c => M.CollectedClientData c raw -> M.CollectedClientData c 'True-encodeRawCollectedClientData M.CollectedClientData {..} = M.CollectedClientData {..}-  where-    ccdRawData = M.WithRaw $ LBS.toStrict $ toLazyByteString builder--    -- https://www.w3.org/TR/webauthn-2/#clientdatajson-serialization-    builder :: Builder-    builder =-      stringUtf8 "{\"type\":"-        <> jsonBuilder typeValue-        <> stringUtf8 ",\"challenge\":"-        <> jsonBuilder challengeValue-        <> stringUtf8 ",\"origin\":"-        <> jsonBuilder originValue-        <> stringUtf8 ",\"crossOrigin\":"-        <> jsonBuilder crossOriginValue-        <> stringUtf8 "}"--    typeValue :: Text-    typeValue = case sing @c of-      K.SRegistration -> "webauthn.create"-      K.SAuthentication -> "webauthn.get"--    challengeValue :: Text-    challengeValue = decodeUtf8 (Base64Url.encode (M.unChallenge ccdChallenge))--    originValue :: Text-    originValue = M.unOrigin ccdOrigin--    crossOriginValue :: Bool-    crossOriginValue = ccdCrossOrigin--    jsonBuilder :: Aeson.ToJSON a => a -> Builder-    jsonBuilder = Aeson.fromEncoding . Aeson.toEncoding---- | Encodes an 'M.AttestationObject' as a 'BS.ByteString'. This is needed by--- the client side to generate a valid JSON response-encodeAttestationObject :: M.AttestationObject 'True -> BS.ByteString-encodeAttestationObject M.AttestationObject {..} = CBOR.toStrictByteString $ CBOR.encodeTerm term-  where-    -- https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object-    term :: CBOR.Term-    term =-      CBOR.TMap-        [ (CBOR.TString "authData", CBOR.TBytes $ M.unRaw $ M.adRawData aoAuthData),-          (CBOR.TString "fmt", CBOR.TString $ M.asfIdentifier aoFmt),-          (CBOR.TString "attStmt", M.asfEncode aoFmt aoAttStmt)-        ]---- | Encodes an 'M.CollectedClientData' as a 'BS.ByteString'. This is needed by--- the client side to generate a valid JSON response-encodeCollectedClientData :: forall (c :: K.CeremonyKind). SingI c => M.CollectedClientData c 'True -> BS.ByteString-encodeCollectedClientData M.CollectedClientData {..} = M.unRaw ccdRawData
− src/Crypto/WebAuthn/Model/WebIDL/Internal/Convert.hs
@@ -1,129 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}---- | Stability: internal--- This module maps every Model type to a WebIDL type. As the name of the--- module and typclass suggest, this is used to perform the conversion between--- the WebIDL and Model representations.-module Crypto.WebAuthn.Model.WebIDL.Internal.Convert-  ( Convert (..),-  )-where--import qualified Crypto.WebAuthn.Cose.Algorithm as Cose-import qualified Crypto.WebAuthn.Model.Kinds as K-import qualified Crypto.WebAuthn.Model.Types as M-import qualified Crypto.WebAuthn.Model.WebIDL.Types as IDL-import qualified Crypto.WebAuthn.WebIDL as IDL-import qualified Data.Aeson as Aeson-import Data.Kind (Type)-import Data.Map (Map)-import Data.Text (Text)---- | @'Convert' hs@ indicates that the Haskell-specific type @hs@ has a more--- general JavaScript-specific type associated with it, which can be accessed with 'IDL'.-class Convert hs where-  type IDL hs :: Type--instance Convert hs => Convert (Maybe hs) where-  type IDL (Maybe hs) = Maybe (IDL hs)--instance Convert M.RpId where-  type IDL M.RpId = IDL.DOMString--instance Convert M.RelyingPartyName where-  type IDL M.RelyingPartyName = IDL.DOMString--instance Convert M.CredentialRpEntity where-  type IDL M.CredentialRpEntity = IDL.PublicKeyCredentialRpEntity--instance Convert M.UserHandle where-  type IDL M.UserHandle = IDL.BufferSource--instance Convert M.UserAccountDisplayName where-  type IDL M.UserAccountDisplayName = IDL.DOMString--instance Convert M.UserAccountName where-  type IDL M.UserAccountName = IDL.DOMString--instance Convert M.CredentialUserEntity where-  type IDL M.CredentialUserEntity = IDL.PublicKeyCredentialUserEntity--instance Convert M.Challenge where-  type IDL M.Challenge = IDL.BufferSource--instance Convert M.CredentialType where-  type IDL M.CredentialType = IDL.DOMString--instance Convert Cose.CoseSignAlg where-  type IDL Cose.CoseSignAlg = IDL.COSEAlgorithmIdentifier--instance Convert [M.CredentialParameters] where-  type IDL [M.CredentialParameters] = [IDL.PublicKeyCredentialParameters]--instance Convert M.Timeout where-  type IDL M.Timeout = IDL.UnsignedLong--instance Convert M.CredentialId where-  type IDL M.CredentialId = IDL.BufferSource--instance Convert [M.AuthenticatorTransport] where-  type IDL [M.AuthenticatorTransport] = [IDL.DOMString]--instance Convert M.CredentialDescriptor where-  type IDL M.CredentialDescriptor = IDL.PublicKeyCredentialDescriptor--instance Convert [M.CredentialDescriptor] where-  type IDL [M.CredentialDescriptor] = Maybe [IDL.PublicKeyCredentialDescriptor]--instance Convert M.AuthenticatorAttachment where-  type IDL M.AuthenticatorAttachment = IDL.DOMString--instance Convert M.ResidentKeyRequirement where-  type IDL M.ResidentKeyRequirement = Maybe IDL.DOMString--instance Convert M.UserVerificationRequirement where-  type IDL M.UserVerificationRequirement = Maybe IDL.DOMString--instance Convert M.AuthenticatorSelectionCriteria where-  type IDL M.AuthenticatorSelectionCriteria = IDL.AuthenticatorSelectionCriteria--instance Convert M.AttestationConveyancePreference where-  type IDL M.AttestationConveyancePreference = Maybe IDL.DOMString--instance Convert M.AuthenticationExtensionsClientInputs where-  type IDL M.AuthenticationExtensionsClientInputs = Map Text Aeson.Value--instance Convert (M.CredentialOptions 'K.Registration) where-  type IDL (M.CredentialOptions 'K.Registration) = IDL.PublicKeyCredentialCreationOptions--instance Convert (M.CredentialOptions 'K.Authentication) where-  type IDL (M.CredentialOptions 'K.Authentication) = IDL.PublicKeyCredentialRequestOptions--instance Convert (M.Credential 'K.Registration raw) where-  type IDL (M.Credential 'K.Registration raw) = IDL.PublicKeyCredential IDL.AuthenticatorAttestationResponse--instance Convert (M.AuthenticatorResponse 'K.Registration raw) where-  type IDL (M.AuthenticatorResponse 'K.Registration raw) = IDL.AuthenticatorAttestationResponse--instance Convert (M.Credential 'K.Authentication raw) where-  type IDL (M.Credential 'K.Authentication raw) = IDL.PublicKeyCredential IDL.AuthenticatorAssertionResponse--instance Convert (M.AuthenticatorResponse 'K.Authentication raw) where-  type IDL (M.AuthenticatorResponse 'K.Authentication raw) = IDL.AuthenticatorAssertionResponse--instance Convert M.AuthenticationExtensionsClientOutputs where-  type IDL M.AuthenticationExtensionsClientOutputs = Map Text Aeson.Value--instance Convert (M.CollectedClientData c 'True) where-  type IDL (M.CollectedClientData c 'True) = IDL.ArrayBuffer--instance Convert (M.AttestationObject 'True) where-  type IDL (M.AttestationObject 'True) = IDL.ArrayBuffer--instance Convert M.AssertionSignature where-  type IDL M.AssertionSignature = IDL.ArrayBuffer--instance Convert (M.AuthenticatorData 'K.Authentication raw) where-  type IDL (M.AuthenticatorData 'K.Authentication raw) = IDL.ArrayBuffer
− src/Crypto/WebAuthn/Model/WebIDL/Internal/Decoding.hs
@@ -1,246 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE RecordWildCards #-}---- | Stability: internal--- This module handles the decoding of structures returned by the--- [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create)--- and [get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)--- methods while [Registering a New Credential](https://www.w3.org/TR/webauthn-2/#sctn-registering-a-new-credential)--- and [Verifying an Authentication Assertion](https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion) respectively.-module Crypto.WebAuthn.Model.WebIDL.Internal.Decoding-  ( Decode (..),-    DecodeCreated (..),-  )-where--import qualified Crypto.WebAuthn.Cose.Algorithm as Cose-import qualified Crypto.WebAuthn.Model.Kinds as K-import qualified Crypto.WebAuthn.Model.Types as M-import qualified Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding as B-import Crypto.WebAuthn.Model.WebIDL.Internal.Convert (Convert (IDL))-import qualified Crypto.WebAuthn.Model.WebIDL.Types as IDL-import qualified Crypto.WebAuthn.WebIDL as IDL-import Data.Coerce (Coercible, coerce)-import Data.Maybe (catMaybes, mapMaybe)-import Data.Singletons (SingI)-import Data.Text (Text)---- | @'Decode' a@ indicates that the Haskell-specific type @a@ can be--- decoded from the more generic JavaScript type @'IDL' a@ with the 'decode' function.-class Convert a => Decode a where-  decode :: IDL a -> Either Text a-  default decode :: Coercible (IDL a) a => IDL a -> Either Text a-  decode = pure . coerce---- | Like 'Decode', but with a 'decodeCreated' function that also takes a--- 'M.SupportedAttestationStatementFormats' in order to allow decoding to depend--- on the supported attestation formats.-class Convert a => DecodeCreated a where-  decodeCreated :: M.SupportedAttestationStatementFormats -> IDL a -> Either Text a--instance Decode a => Decode (Maybe a) where-  decode Nothing = pure Nothing-  decode (Just a) = Just <$> decode a--instance Decode M.CredentialId--instance Decode M.AssertionSignature--instance Decode M.UserHandle--instance Decode M.AuthenticationExtensionsClientOutputs where-  -- TODO: Extensions are not implemented by this library, see the TODO in the-  -- module documentation of `Crypto.WebAuthn.Model` for more information.-  decode _ = pure M.AuthenticationExtensionsClientOutputs {}--instance SingI c => Decode (M.CollectedClientData (c :: K.CeremonyKind) 'True) where-  decode (IDL.URLEncodedBase64 bytes) = B.decodeCollectedClientData bytes--instance Decode (M.AuthenticatorData 'K.Authentication 'True) where-  decode (IDL.URLEncodedBase64 bytes) = B.decodeAuthenticatorData bytes--instance Decode (M.AuthenticatorResponse 'K.Authentication 'True) where-  decode IDL.AuthenticatorAssertionResponse {..} = do-    araClientData <- decode clientDataJSON-    araAuthenticatorData <- decode authenticatorData-    araSignature <- decode signature-    araUserHandle <- decode userHandle-    pure $ M.AuthenticatorResponseAuthentication {..}--instance Decode (M.Credential 'K.Authentication 'True) where-  decode IDL.PublicKeyCredential {..} = do-    cIdentifier <- decode rawId-    cResponse <- decode response-    cClientExtensionResults <- decode clientExtensionResults-    pure $ M.Credential {..}--instance Decode M.RpId--instance Decode M.RelyingPartyName--instance Decode M.CredentialRpEntity where-  decode IDL.PublicKeyCredentialRpEntity {..} = do-    creId <- decode id-    creName <- decode name-    pure $ M.CredentialRpEntity {..}--instance Decode M.UserAccountDisplayName--instance Decode M.UserAccountName--instance Decode M.CredentialUserEntity where-  decode IDL.PublicKeyCredentialUserEntity {..} = do-    cueId <- decode id-    cueDisplayName <- decode displayName-    cueName <- decode name-    pure $ M.CredentialUserEntity {..}--instance Decode M.Challenge--instance Decode Cose.CoseSignAlg where-  -- The specification does not inspect the algorithm until-  -- assertion/attestation. We implement the check here to go to a Haskell-  -- type. Erring on the side of caution by failing to parse if an unsupported-  -- alg was encountered.-  decode = Cose.toCoseSignAlg--instance Decode M.Timeout---- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-transport)-instance Decode [M.AuthenticatorTransport] where-  decode = pure . mapMaybe decodeTransport-    where-      decodeTransport "usb" = Just M.AuthenticatorTransportUSB-      decodeTransport "nfc" = Just M.AuthenticatorTransportNFC-      decodeTransport "ble" = Just M.AuthenticatorTransportBLE-      decodeTransport "internal" = Just M.AuthenticatorTransportInternal-      decodeTransport _ = Nothing---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-credential-descriptor)--- [The type] member contains the type of the public key credential the caller--- is referring to. The value SHOULD be a member of--- PublicKeyCredentialType but client platforms MUST ignore any--- PublicKeyCredentialDescriptor with an unknown type.-instance Decode [M.CredentialDescriptor] where-  decode Nothing = pure []-  decode (Just xs) = catMaybes <$> traverse decodeDescriptor xs-    where-      decodeDescriptor :: IDL.PublicKeyCredentialDescriptor -> Either Text (Maybe M.CredentialDescriptor)-      decodeDescriptor IDL.PublicKeyCredentialDescriptor {littype = "public-key", ..} = do-        let cdTyp = M.CredentialTypePublicKey-        cdId <- decode id-        cdTransports <- decode transports-        pure . Just $ M.CredentialDescriptor {..}-      decodeDescriptor _ = pure Nothing---- | [(spec)](https://www.w3.org/TR/webauthn-2/#enum-userVerificationRequirement)--- The value SHOULD be a member of UserVerificationRequirement but client--- platforms MUST ignore unknown values, treating an unknown value as if the--- member does not exist. The default is "preferred".-instance Decode M.UserVerificationRequirement where-  decode (Just "discouraged") = Right M.UserVerificationRequirementDiscouraged-  decode (Just "preferred") = Right M.UserVerificationRequirementPreferred-  decode (Just "required") = Right M.UserVerificationRequirementRequired-  decode _ = Right M.UserVerificationRequirementPreferred---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-authenticatorSelection)-instance Decode M.AuthenticatorSelectionCriteria where-  decode IDL.AuthenticatorSelectionCriteria {..} = do-    let ascAuthenticatorAttachment = decodeAttachment =<< authenticatorAttachment-        ascResidentKey = decodeResidentKey residentKey-    ascUserVerification <- decode userVerification-    pure $ M.AuthenticatorSelectionCriteria {..}-    where-      -- Any unknown values must be ignored, treating them as if the member does not exist-      decodeAttachment "platform" = Just M.AuthenticatorAttachmentPlatform-      decodeAttachment "cross-platform" = Just M.AuthenticatorAttachmentCrossPlatform-      decodeAttachment _ = Nothing--      -- [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-residentkey)-      -- The value SHOULD be a member of ResidentKeyRequirement but client platforms-      -- MUST ignore unknown values, treating an unknown value as if the member does not-      -- exist. If no value is given then the effective value is required if-      -- requireResidentKey is true or discouraged if it is false or absent.-      decodeResidentKey :: Maybe IDL.DOMString -> M.ResidentKeyRequirement-      decodeResidentKey (Just "discouraged") = M.ResidentKeyRequirementDiscouraged-      decodeResidentKey (Just "preferred") = M.ResidentKeyRequirementPreferred-      decodeResidentKey (Just "required") = M.ResidentKeyRequirementRequired-      decodeResidentKey _ = case requireResidentKey of-        Just True -> M.ResidentKeyRequirementRequired-        _ -> M.ResidentKeyRequirementDiscouraged---- | [(spec)](https://www.w3.org/TR/webauthn-2/#enumdef-attestationconveyancepreference)--- Its values SHOULD be members of AttestationConveyancePreference. Client--- platforms MUST ignore unknown values, treating an unknown value as if the--- member does not exist. Its default value is "none".-instance Decode M.AttestationConveyancePreference where-  decode (Just "none") = Right M.AttestationConveyancePreferenceNone-  decode (Just "indirect") = Right M.AttestationConveyancePreferenceIndirect-  decode (Just "direct") = Right M.AttestationConveyancePreferenceDirect-  decode (Just "enterprise") = Right M.AttestationConveyancePreferenceEnterprise-  decode _ = Right M.AttestationConveyancePreferenceNone---- [(spec)](https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialparameters)--- [The type] member specifies the type of credential to be created. The value SHOULD--- be a member of PublicKeyCredentialType but client platforms MUST ignore--- unknown values, ignoring any PublicKeyCredentialParameters with an unknown--- type.-instance Decode [M.CredentialParameters] where-  decode xs = catMaybes <$> traverse decodeParam xs-    where-      decodeParam :: IDL.PublicKeyCredentialParameters -> Either Text (Maybe M.CredentialParameters)-      decodeParam IDL.PublicKeyCredentialParameters {littype = "public-key", ..} = do-        let cpTyp = M.CredentialTypePublicKey-        cpAlg <- decode alg-        pure . Just $ M.CredentialParameters {..}-      decodeParam _ = pure Nothing---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-makecredentialoptions)-instance Decode (M.CredentialOptions 'K.Registration) where-  decode IDL.PublicKeyCredentialCreationOptions {..} = do-    corRp <- decode rp-    corUser <- decode user-    corChallenge <- decode challenge-    corPubKeyCredParams <- decode pubKeyCredParams-    corTimeout <- decode timeout-    corExcludeCredentials <- decode excludeCredentials-    corAuthenticatorSelection <- decode authenticatorSelection-    corAttestation <- decode attestation-    let corExtensions = M.AuthenticationExtensionsClientInputs {} <$ extensions-    pure $ M.CredentialOptionsRegistration {..}---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options)-instance Decode (M.CredentialOptions 'K.Authentication) where-  decode IDL.PublicKeyCredentialRequestOptions {..} = do-    coaChallenge <- decode challenge-    coaTimeout <- decode timeout-    coaRpId <- decode rpId-    coaAllowCredentials <- decode allowCredentials-    coaUserVerification <- decode userVerification-    let coaExtensions = M.AuthenticationExtensionsClientInputs {} <$ extensions-    pure $ M.CredentialOptionsAuthentication {..}---- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-generating-an-attestation-object)-instance DecodeCreated (M.AttestationObject 'True) where-  decodeCreated supportedFormats (IDL.URLEncodedBase64 bytes) =-    B.decodeAttestationObject supportedFormats bytes--instance DecodeCreated (M.AuthenticatorResponse 'K.Registration 'True) where-  decodeCreated supportedFormats IDL.AuthenticatorAttestationResponse {..} = do-    arrClientData <- decode clientDataJSON-    arrAttestationObject <- decodeCreated supportedFormats attestationObject-    arrTransports <- case transports of-      Nothing -> pure []-      Just t -> decode t-    pure $ M.AuthenticatorResponseRegistration {..}--instance DecodeCreated (M.Credential 'K.Registration 'True) where-  decodeCreated supportedFormats IDL.PublicKeyCredential {..} = do-    cIdentifier <- decode rawId-    cResponse <- decodeCreated supportedFormats response-    cClientExtensionResults <- decode clientExtensionResults-    pure $ M.Credential {..}
− src/Crypto/WebAuthn/Model/WebIDL/Internal/Encoding.hs
@@ -1,221 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TypeFamilies #-}---- | Stability: internal--- This module handles the encoding of structures passed to the--- [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create)--- and [get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get)--- methods while [Registering a New Credential](https://www.w3.org/TR/webauthn-2/#sctn-registering-a-new-credential)--- and [Verifying an Authentication Assertion](https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion) respectively.-module Crypto.WebAuthn.Model.WebIDL.Internal.Encoding-  ( Encode (..),-  )-where--import qualified Crypto.WebAuthn.Cose.Algorithm as Cose-import qualified Crypto.WebAuthn.Model.Kinds as K-import qualified Crypto.WebAuthn.Model.Types as M-import qualified Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding as B-import Crypto.WebAuthn.Model.WebIDL.Internal.Convert (Convert (IDL))-import qualified Crypto.WebAuthn.Model.WebIDL.Types as IDL-import qualified Crypto.WebAuthn.WebIDL as IDL-import Data.Coerce (Coercible, coerce)-import qualified Data.Map as Map-import Data.Singletons (SingI)---- | @'Encode' hs@ indicates that the Haskell-specific type @hs@ can be--- encoded to the more generic JavaScript type @'IDL' hs@ with the 'encode' function.-class Convert a => Encode a where-  encode :: a -> IDL a-  default encode :: Coercible a (IDL a) => a -> IDL a-  encode = coerce--instance Encode hs => Encode (Maybe hs) where-  encode Nothing = Nothing-  encode (Just hs) = Just $ encode hs--instance Encode M.RpId--instance Encode M.RelyingPartyName--instance Encode M.UserHandle--instance Encode M.UserAccountDisplayName--instance Encode M.UserAccountName--instance Encode M.Challenge--instance Encode M.Timeout--instance Encode M.CredentialId--instance Encode M.AuthenticationExtensionsClientInputs where-  -- TODO: Extensions are not implemented by this library, see the TODO in the-  -- module documentation of `Crypto.WebAuthn.Model` for more information.-  encode M.AuthenticationExtensionsClientInputs {} = Map.empty---- | <https://www.iana.org/assignments/cose/cose.xhtml#algorithms>-instance Encode Cose.CoseSignAlg where-  encode = Cose.fromCoseSignAlg---- | <https://www.w3.org/TR/webauthn-2/#enum-credentialType>-instance Encode M.CredentialType where-  encode M.CredentialTypePublicKey = "public-key"---- | <https://www.w3.org/TR/webauthn-2/#enumdef-authenticatortransport>-instance Encode [M.AuthenticatorTransport] where-  encode = map encodeTransport-    where-      encodeTransport M.AuthenticatorTransportUSB = "usb"-      encodeTransport M.AuthenticatorTransportNFC = "nfc"-      encodeTransport M.AuthenticatorTransportBLE = "ble"-      encodeTransport M.AuthenticatorTransportInternal = "internal"---- | <https://www.w3.org/TR/webauthn-2/#enumdef-authenticatorattachment>-instance Encode M.AuthenticatorAttachment where-  encode M.AuthenticatorAttachmentPlatform = "platform"-  encode M.AuthenticatorAttachmentCrossPlatform = "cross-platform"---- | <https://www.w3.org/TR/webauthn-2/#enum-residentKeyRequirement>-instance Encode M.ResidentKeyRequirement where-  encode M.ResidentKeyRequirementDiscouraged = Just "discouraged"-  encode M.ResidentKeyRequirementPreferred = Just "preferred"-  encode M.ResidentKeyRequirementRequired = Just "required"---- | <https://www.w3.org/TR/webauthn-2/#enum-userVerificationRequirement>-instance Encode M.UserVerificationRequirement where-  encode M.UserVerificationRequirementRequired = Just "required"-  encode M.UserVerificationRequirementPreferred = Just "preferred"-  encode M.UserVerificationRequirementDiscouraged = Just "discouraged"---- | <https://www.w3.org/TR/webauthn-2/#enum-attestation-convey>-instance Encode M.AttestationConveyancePreference where-  encode M.AttestationConveyancePreferenceNone = Just "none"-  encode M.AttestationConveyancePreferenceIndirect = Just "indirect"-  encode M.AttestationConveyancePreferenceDirect = Just "direct"-  encode M.AttestationConveyancePreferenceEnterprise = Just "enterprise"--instance Encode M.CredentialRpEntity where-  encode M.CredentialRpEntity {..} =-    IDL.PublicKeyCredentialRpEntity-      { id = encode creId,-        name = encode creName-      }--instance Encode M.CredentialUserEntity where-  encode M.CredentialUserEntity {..} =-    IDL.PublicKeyCredentialUserEntity-      { id = encode cueId,-        displayName = encode cueDisplayName,-        name = encode cueName-      }--instance Encode [M.CredentialParameters] where-  encode = map encodeParameters-    where-      encodeParameters M.CredentialParameters {..} =-        IDL.PublicKeyCredentialParameters-          { littype = encode cpTyp,-            alg = encode cpAlg-          }--instance Encode M.CredentialDescriptor where-  encode M.CredentialDescriptor {..} =-    IDL.PublicKeyCredentialDescriptor-      { littype = encode cdTyp,-        id = encode cdId,-        transports = encode cdTransports-      }--instance Encode M.AuthenticatorSelectionCriteria where-  encode M.AuthenticatorSelectionCriteria {..} =-    IDL.AuthenticatorSelectionCriteria-      { authenticatorAttachment = encode ascAuthenticatorAttachment,-        residentKey = encode ascResidentKey,-        -- [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey)-        -- Relying Parties SHOULD set it to true if, and only if, residentKey is set to required.-        requireResidentKey = Just (ascResidentKey == M.ResidentKeyRequirementRequired),-        userVerification = encode ascUserVerification-      }--instance Encode [M.CredentialDescriptor] where-  encode = Just . map encode--instance Encode (M.CredentialOptions 'K.Registration) where-  encode M.CredentialOptionsRegistration {..} =-    IDL.PublicKeyCredentialCreationOptions-      { rp = encode corRp,-        user = encode corUser,-        challenge = encode corChallenge,-        pubKeyCredParams = encode corPubKeyCredParams,-        timeout = encode corTimeout,-        excludeCredentials = encode corExcludeCredentials,-        authenticatorSelection = encode corAuthenticatorSelection,-        attestation = encode corAttestation,-        extensions = encode corExtensions-      }--instance Encode (M.CredentialOptions 'K.Authentication) where-  encode M.CredentialOptionsAuthentication {..} =-    IDL.PublicKeyCredentialRequestOptions-      { challenge = encode coaChallenge,-        timeout = encode coaTimeout,-        rpId = encode coaRpId,-        allowCredentials = encode coaAllowCredentials,-        userVerification = encode coaUserVerification,-        extensions = encode coaExtensions-      }---- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)--- Encodes the PublicKeyCredential for attestation, this instance is mostly used in the tests where we emulate the--- of the client.-instance Encode (M.Credential 'K.Registration 'True) where-  encode M.Credential {..} =-    IDL.PublicKeyCredential-      { rawId = encode cIdentifier,-        response = encode cResponse,-        -- TODO: Extensions are not implemented by this library, see the TODO in the-        -- module documentation of `Crypto.WebAuthn.Model` for more information.-        clientExtensionResults = Map.empty-      }---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)-instance SingI c => Encode (M.CollectedClientData (c :: K.CeremonyKind) 'True) where-  encode ccd = IDL.URLEncodedBase64 $ B.encodeCollectedClientData ccd--instance Encode (M.AuthenticatorResponse 'K.Authentication 'True) where-  encode M.AuthenticatorResponseAuthentication {..} =-    IDL.AuthenticatorAssertionResponse-      { clientDataJSON = encode araClientData,-        authenticatorData = IDL.URLEncodedBase64 $ M.unRaw $ M.adRawData araAuthenticatorData,-        signature = IDL.URLEncodedBase64 $ M.unAssertionSignature araSignature,-        userHandle = IDL.URLEncodedBase64 . M.unUserHandle <$> araUserHandle-      }--instance Encode (M.Credential 'K.Authentication 'True) where-  encode M.Credential {..} =-    IDL.PublicKeyCredential-      { rawId = encode cIdentifier,-        response = encode cResponse,-        -- TODO: Extensions are not implemented by this library, see the TODO in the-        -- module documentation of `Crypto.WebAuthn.Model` for more information.-        clientExtensionResults = Map.empty-      }---- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-authenticatorresponse)-instance Encode (M.AuthenticatorResponse 'K.Registration 'True) where-  encode M.AuthenticatorResponseRegistration {..} =-    IDL.AuthenticatorAttestationResponse-      { clientDataJSON = encode arrClientData,-        attestationObject = encode arrAttestationObject,-        transports = Just $ encode arrTransports-      }---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-attestationobject)-instance Encode (M.AttestationObject 'True) where-  encode ao = IDL.URLEncodedBase64 $ B.encodeAttestationObject ao
− src/Crypto/WebAuthn/Model/WebIDL/Types.hs
@@ -1,242 +0,0 @@-{-# LANGUAGE DuplicateRecordFields #-}---- | Stability: experimental--- This module models direct representations of JavaScript objects interacting with the--- [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create)--- and [get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get) methods, as used by [Webauthn2](https://www.w3.org/TR/webauthn-2).--- Note that these types don't encode the semantics of their values. E.g. if the JavaScript object has a @DOMString@--- field, but only values @"foo"@ and @"bar"@ are possible, the type is still encoded as a generic 'IDL.DOMString'.--- This allows us to match the specification very closely, deferring decoding of these values to another module.--- This module also implements 'Aeson.FromJSON' and 'Aeson.ToJSON' instances of its types, which are compatible with--- [webauthn-json](https://github.com/github/webauthn-json)'s JSON schema.------ The defined types are------ - 'PublicKeyCredentialCreationOptions' and all its subtypes. Passed as the---   [publicKey](https://www.w3.org/TR/webauthn-2/#dom-credentialcreationoptions-publickey) field to the---   [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create) method---   in step 2 of [§ 7.1 Registering a New Credential](https://www.w3.org/TR/webauthn-2/#sctn-registering-a-new-credential)--- - 'PublicKeyCredentialRequestOptions' and all its subtypes. Passed as the---   [publicKey](https://www.w3.org/TR/webauthn-2/#dom-credentialrequestoptions-publickey) field to the---   [get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get) method---   in step 2 of [§ 7.2 Verifying an Authentication Assertion](https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion)--- - @'PublicKeyCredential' response@ and all its subtypes. Responses of the---   [create()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-create) (in which case @response ~ 'AuthenticatorAttestationResponse'@) and---   [get()](https://w3c.github.io/webappsec-credential-management/#dom-credentialscontainer-get) (in which case @response ~ 'AuthenticatorAssertionResponse'@ methods.-module Crypto.WebAuthn.Model.WebIDL.Types-  ( -- * Top-level types-    PublicKeyCredentialCreationOptions (..),-    PublicKeyCredentialRequestOptions (..),-    PublicKeyCredential (..),--    -- * Nested types-    AuthenticatorAttestationResponse (..),-    AuthenticatorAssertionResponse (..),-    PublicKeyCredentialRpEntity (..),-    PublicKeyCredentialUserEntity (..),-    PublicKeyCredentialParameters (..),-    COSEAlgorithmIdentifier,-    PublicKeyCredentialDescriptor (..),-    AuthenticatorSelectionCriteria (..),-  )-where--import Crypto.WebAuthn.Internal.Utils (jsonEncodingOptions)-import qualified Crypto.WebAuthn.WebIDL as IDL-import qualified Data.Aeson as Aeson-import Data.Map (Map)-import Data.Text (Text)-import GHC.Generics (Generic)---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-makecredentialoptions)-data PublicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-rp)-    rp :: PublicKeyCredentialRpEntity,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-user)-    user :: PublicKeyCredentialUserEntity,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-challenge)-    challenge :: IDL.BufferSource,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-pubkeycredparams)-    pubKeyCredParams :: [PublicKeyCredentialParameters],-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-timeout)-    timeout :: Maybe IDL.UnsignedLong,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-excludecredentials)-    excludeCredentials :: Maybe [PublicKeyCredentialDescriptor],-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection)-    authenticatorSelection :: Maybe AuthenticatorSelectionCriteria,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-attestation)-    attestation :: Maybe IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-extensions)-    extensions :: Maybe (Map Text Aeson.Value)-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON PublicKeyCredentialCreationOptions where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON PublicKeyCredentialCreationOptions where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-rp-credential-params)-data PublicKeyCredentialRpEntity = PublicKeyCredentialRpEntity-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrpentity-id)-    id :: Maybe IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialentity-name)-    name :: IDL.DOMString-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON PublicKeyCredentialRpEntity where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON PublicKeyCredentialRpEntity where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-user-credential-params)-data PublicKeyCredentialUserEntity = PublicKeyCredentialUserEntity-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialuserentity-id)-    id :: IDL.BufferSource,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialuserentity-displayname)-    displayName :: IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialentity-name)-    name :: IDL.DOMString-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON PublicKeyCredentialUserEntity where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON PublicKeyCredentialUserEntity where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-credential-params)-data PublicKeyCredentialParameters = PublicKeyCredentialParameters-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialparameters-type)-    littype :: IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialparameters-alg)-    alg :: COSEAlgorithmIdentifier-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON PublicKeyCredentialParameters where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON PublicKeyCredentialParameters where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#sctn-alg-identifier)-type COSEAlgorithmIdentifier = IDL.Long---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialdescriptor)-data PublicKeyCredentialDescriptor = PublicKeyCredentialDescriptor-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialdescriptor-type)-    littype :: IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialdescriptor-id)-    id :: IDL.BufferSource,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialdescriptor-transports)-    transports :: Maybe [IDL.DOMString]-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON PublicKeyCredentialDescriptor where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON PublicKeyCredentialDescriptor where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictdef-authenticatorselectioncriteria)-data AuthenticatorSelectionCriteria = AuthenticatorSelectionCriteria-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-authenticatorattachment)-    authenticatorAttachment :: Maybe IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-residentkey)-    residentKey :: Maybe IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey)-    requireResidentKey :: Maybe IDL.Boolean,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-userverification)-    userVerification :: Maybe IDL.DOMString-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON AuthenticatorSelectionCriteria where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON AuthenticatorSelectionCriteria where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options)-data PublicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-challenge)-    challenge :: IDL.BufferSource,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-timeout)-    timeout :: Maybe IDL.UnsignedLong,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-rpid)-    rpId :: Maybe IDL.USVString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-allowcredentials)-    allowCredentials :: Maybe [PublicKeyCredentialDescriptor],-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-userverification)-    userVerification :: Maybe IDL.DOMString,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-extensions)-    extensions :: Maybe (Map Text Aeson.Value)-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON PublicKeyCredentialRequestOptions where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON PublicKeyCredentialRequestOptions where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-pkcredential)-data PublicKeyCredential response = PublicKeyCredential-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredential-identifier-slot)-    rawId :: IDL.ArrayBuffer,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredential-response)-    response :: response,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-publickeycredential-getclientextensionresults)-    clientExtensionResults :: Map Text Aeson.Value-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON response => Aeson.FromJSON (PublicKeyCredential response) where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON response => Aeson.ToJSON (PublicKeyCredential response) where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-authenticatorattestationresponse)-data AuthenticatorAttestationResponse = AuthenticatorAttestationResponse-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)-    clientDataJSON :: IDL.ArrayBuffer,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-attestationobject)-    attestationObject :: IDL.ArrayBuffer,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorattestationresponse-transports-slot)-    -- This field is only being propagated by webauthn-json [since recently](https://github.com/github/webauthn-json/pull/44),-    -- which is why we allow absence of this value-    transports :: Maybe [IDL.DOMString]-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON AuthenticatorAttestationResponse where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON AuthenticatorAttestationResponse where-  toJSON = Aeson.genericToJSON jsonEncodingOptions---- | [(spec)](https://www.w3.org/TR/webauthn-2/#iface-authenticatorassertionresponse)-data AuthenticatorAssertionResponse = AuthenticatorAssertionResponse-  { -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson)-    clientDataJSON :: IDL.ArrayBuffer,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-authenticatordata)-    authenticatorData :: IDL.ArrayBuffer,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-signature)-    signature :: IDL.ArrayBuffer,-    -- | [(spec)](https://www.w3.org/TR/webauthn-2/#dom-authenticatorassertionresponse-userhandle)-    userHandle :: Maybe IDL.ArrayBuffer-  }-  deriving (Eq, Show, Generic)--instance Aeson.FromJSON AuthenticatorAssertionResponse where-  parseJSON = Aeson.genericParseJSON jsonEncodingOptions--instance Aeson.ToJSON AuthenticatorAssertionResponse where-  toJSON = Aeson.genericToJSON jsonEncodingOptions
src/Crypto/WebAuthn/Operation/Authentication.hs view
@@ -28,12 +28,10 @@ import Control.Monad (unless) import qualified Crypto.Hash as Hash import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose import Crypto.WebAuthn.Internal.Utils (failure) import qualified Crypto.WebAuthn.Model as M import Crypto.WebAuthn.Operation.CredentialEntry (CredentialEntry (cePublicKeyBytes, ceSignCounter, ceUserHandle)) import Data.ByteArray (convert)-import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import Data.List.NonEmpty (NonEmpty) import Data.Text (Text)@@ -42,28 +40,58 @@ -- | Errors that may occur during [assertion](https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion) data AuthenticationError   = -- | The provided Credential was not one explicitly allowed by the server-    -- (first: allowed credentials, second: received credential)-    AuthenticationDisallowedCredential [M.CredentialDescriptor] (M.Credential 'M.Authentication 'True)+    AuthenticationCredentialDisallowed+      { -- | The credentials allowed by the server+        aeAllowedCredentials :: [M.CredentialDescriptor],+        -- | The credential returned by the client+        aeReceivedCredential :: M.Credential 'M.Authentication 'True+      }   | -- | The received credential does not match the currently identified user-    -- (first: identified, second: received)-    AuthenticationIdentifiedUserHandleMismatch M.UserHandle M.UserHandle+    AuthenticationIdentifiedUserHandleMismatch+      { -- | The `M.UserHandle` of the user who is attempting authentication+        aeIdentifiedUser :: M.UserHandle,+        -- | The owner of the credential passed to the+        -- `verifyAuthenticationResponse` function (retrieved from the+        -- database)+        aeRegisteredUser :: M.UserHandle+      }   | -- | The stored credential does not match the user specified in the     -- response-    -- (first: stored, second: received)-    AuthenticationCredentialUserHandleMismatch M.UserHandle M.UserHandle+    AuthenticationCredentialUserHandleMismatch+      { -- | The `M.UserHandle` of the user who is attempting authentication+        aeIdentifiedUser :: M.UserHandle,+        -- | The `M.UserHandle` reported by the authenticator in the response+        aeAuthenticatorUser :: M.UserHandle+      }   | -- | No user was identified and the response did not specify a user     AuthenticationCannotVerifyUserHandle   | -- | The received challenge does not match the originally created     -- challenge-    -- (first: expected, second: received)-    AuthenticationChallengeMismatch M.Challenge M.Challenge+    AuthenticationChallengeMismatch+      { -- | The challenge created by the relying party and part of the+        -- `M.CredentialOptions`+        aeCreatedChallenge :: M.Challenge,+        -- | The challenge received from the client, part of the response+        aeReceivedChallenge :: M.Challenge+      }   | -- | The origin derived by the client does match the assumed origin-    -- (first: expected, second: received)-    AuthenticationOriginMismatch M.Origin M.Origin+    AuthenticationOriginMismatch+      { -- | The origin explicitly passed to the `verifyAuthenticationResponse`+        -- response, set by the RP+        aeExpectedOrigin :: M.Origin,+        -- | The origin received from the client as part of the client data+        aeReceivedOrigin :: M.Origin+      }   | -- | The rpIdHash in the authData is not a valid hash over the RpId     -- expected by the Relying party-    -- (first: expected, second: received)-    AuthenticationRpIdHashMismatch M.RpIdHash M.RpIdHash+    AuthenticationRpIdHashMismatch+      { -- | The RP ID hash explicitly passed to the+        -- `verifyAuthenticationResponse` response, set by the RP+        aeExpectedRpIdHash :: M.RpIdHash,+        -- | The RP ID hash received from the client as part of the authenticator+        -- data+        aeReceivedRpIdHash :: M.RpIdHash+      }   | -- | The UserPresent bit was not set in the authData     AuthenticationUserNotPresent   | -- | The UserVerified bit was not set in the authData while user@@ -71,8 +99,8 @@     AuthenticationUserNotVerified   | -- | The public key provided in the 'CredentialEntry' could not be decoded     AuthenticationSignatureDecodingError CBOR.DeserialiseFailure-  | -- | the public key does verify the signature over the authData-    AuthenticationInvalidSignature Cose.PublicKey BS.ByteString M.AssertionSignature Text+  | -- | The public key doesn't verify the signature over the authData+    AuthenticationSignatureInvalid Text   deriving (Show, Exception)  -- | [Section 6.1.1 of the specification](https://www.w3.org/TR/webauthn-2/#sctn-sign-counter)@@ -185,7 +213,10 @@   -- identifies one of the public key credentials listed in   -- options.allowCredentials.   let allowCredentials = M.coaAllowCredentials options-  unless (null allowCredentials || M.cIdentifier credential `elem` map M.cdId allowCredentials) . failure $ AuthenticationDisallowedCredential allowCredentials credential+  unless+    (null allowCredentials || M.cIdentifier credential `elem` map M.cdId allowCredentials)+    . failure+    $ AuthenticationCredentialDisallowed allowCredentials credential    -- 6. Identify the user being authenticated and verify that this user is the   -- owner of the public key credential source credentialSource identified by@@ -307,12 +338,10 @@       message = rawData <> convert (M.unClientDataHash hash)   case CBOR.deserialiseFromBytes decode pubKeyBytes of     Left err -> failure $ AuthenticationSignatureDecodingError err-    Right (_, coseKey) -> do-      let signAlg = Cose.keySignAlg coseKey-          publicKey = Cose.fromCose coseKey-      case Cose.verify signAlg publicKey message (M.unAssertionSignature sig) of+    Right (_, coseKey) ->+      case Cose.verify coseKey message (M.unAssertionSignature sig) of         Right () -> pure ()-        Left err -> failure $ AuthenticationInvalidSignature publicKey message sig err+        Left err -> failure $ AuthenticationSignatureInvalid err    -- 21. Let storedSignCount be the stored signature counter value associated   -- with credential.id. If authData.signCount is nonzero or storedSignCount
src/Crypto/WebAuthn/Operation/Registration.hs view
@@ -29,8 +29,8 @@ import Control.Exception (Exception) import Control.Monad (unless) import qualified Crypto.Hash as Hash-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import Crypto.WebAuthn.Internal.Utils (certificateSubjectKeyIdentifier, failure) import Crypto.WebAuthn.Metadata.Service.Processing (queryMetadata) import qualified Crypto.WebAuthn.Metadata.Service.Types as Meta@@ -59,21 +59,45 @@  -- | All the errors that can result from a call to 'verifyRegistrationResponse' data RegistrationError-  = -- | The returned challenge does not match the desired one-    RegistrationChallengeMismatch M.Challenge M.Challenge+  = -- | The received challenge does not match the originally created+    -- challenge+    RegistrationChallengeMismatch+      { -- | The challenge created by the relying party and part of the+        -- `M.CredentialOptions`+        reCreatedChallenge :: M.Challenge,+        -- | The challenge received from the client, part of the response+        reReceivedChallenge :: M.Challenge+      }   | -- | The returned origin does not match the relying party's origin-    RegistrationOriginMismatch M.Origin M.Origin-  | -- | The hash of the relying party id does not match the has in the returned authentication data-    RegistrationRpIdHashMismatch M.RpIdHash M.RpIdHash+    RegistrationOriginMismatch+      { -- | The origin explicitly passed to the `verifyRegistrationResponse`+        -- response, set by the RP+        reExpectedOrigin :: M.Origin,+        -- | The origin received from the client as part of the client data+        reReceivedOrigin :: M.Origin+      }+  | -- | The rpIdHash in the authData is not a valid hash over the RpId+    -- expected by the Relying party+    RegistrationRpIdHashMismatch+      { -- | The RP ID hash explicitly passed to the+        -- `verifyRegistrationResponse` response, set by the RP+        reExpectedRpIdHash :: M.RpIdHash,+        -- | The RP ID hash received from the client as part of the authenticator+        -- data+        reReceivedRpIdHash :: M.RpIdHash+      }   | -- | The userpresent bit in the authdata was not set     RegistrationUserNotPresent   | -- | The userverified bit in the authdata was not set     RegistrationUserNotVerified   | -- | The algorithm received from the client was not one of the algorithms     -- we (the relying party) requested from the client.-    -- first: The received algorithm-    -- second: The list of requested algorithm-    RegistrationUndesiredPublicKeyAlgorithm Cose.CoseSignAlg [Cose.CoseSignAlg]+    RegistrationPublicKeyAlgorithmDisallowed+      { -- | The signing algorithms requested by the RP+        reAllowedSigningAlgorithms :: [Cose.CoseSignAlg],+        -- | The signing algorithm received from the client+        reReceivedSigningAlgorithm :: Cose.CoseSignAlg+      }   | -- | There was some exception in the statement format specific section     forall a. M.AttestationStatementFormat a => RegistrationAttestationFormatError a (NonEmpty (M.AttStmtVerificationError a)) @@ -309,12 +333,12 @@        -- 8. Verify that the value of C.challenge equals the base64url encoding of       -- options.challenge.-      unless (M.ccdChallenge c == corChallenge) $-        failure $ RegistrationChallengeMismatch (M.ccdChallenge c) corChallenge+      unless (corChallenge == M.ccdChallenge c) $+        failure $ RegistrationChallengeMismatch corChallenge (M.ccdChallenge c)        -- 9. Verify that the value of C.origin matches the Relying Party's origin.-      unless (M.ccdOrigin c == rpOrigin) $-        failure $ RegistrationOriginMismatch (M.ccdOrigin c) rpOrigin+      unless (rpOrigin == M.ccdOrigin c) $+        failure $ RegistrationOriginMismatch rpOrigin (M.ccdOrigin c)        -- 10. Verify that the value of C.tokenBinding.status matches the state of       -- Token Binding for the TLS connection over which the assertion was@@ -338,8 +362,8 @@        -- 13. Verify that the rpIdHash in authData is the SHA-256 hash of the RP       -- ID expected by the Relying Party.-      unless (M.adRpIdHash authData == rpIdHash) $-        failure $ RegistrationRpIdHashMismatch (M.adRpIdHash authData) rpIdHash+      unless (rpIdHash == M.adRpIdHash authData) $+        failure $ RegistrationRpIdHashMismatch rpIdHash (M.adRpIdHash authData)        -- 14. Verify that the User Present bit of the flags in authData is set.       unless (M.adfUserPresent (M.adFlags authData)) $@@ -364,10 +388,10 @@       -- 16. Verify that the "alg" parameter in the credential public key in       -- authData matches the alg attribute of one of the items in       -- options.pubKeyCredParams.-      let acdAlg = Cose.keySignAlg acdCredentialPublicKey+      let acdAlg = Cose.signAlg acdCredentialPublicKey           desiredAlgs = map M.cpAlg corPubKeyCredParams       unless (acdAlg `elem` desiredAlgs) $-        failure $ RegistrationUndesiredPublicKeyAlgorithm acdAlg desiredAlgs+        failure $ RegistrationPublicKeyAlgorithmDisallowed desiredAlgs acdAlg        -- 17. Verify that the values of the client extension outputs in       -- clientExtensionResults and the authenticator extension outputs in the
− src/Crypto/WebAuthn/WebIDL.hs
@@ -1,80 +0,0 @@--- | Stability: experimental--- | This module defines some types from the [Web IDL](https://webidl.spec.whatwg.org/) specification-module Crypto.WebAuthn.WebIDL-  ( DOMString,-    USVString,-    UnsignedLongLong,-    UnsignedLong,-    Long,-    UnsignedShort,-    Octet,-    Boolean,-    Crypto.WebAuthn.WebIDL.Double,-    BufferSource (..),-    ArrayBuffer,-  )-where--import qualified Data.Aeson as Aeson-import qualified Data.ByteString as BS-import qualified Data.ByteString.Base64.URL as Base64-import Data.Int (Int32)-import Data.Text (Text)-import qualified Data.Text.Encoding as Text-import Data.Word (Word16, Word32, Word64, Word8)---- | [(spec)](https://webidl.spec.whatwg.org/#idl-DOMString)--- The `[DOMString](https://webidl.spec.whatwg.org/#idl-DOMString)` type--- corresponds to the set of all possible sequences of--- [code units](https://webidl.spec.whatwg.org/#dfn-code-unit). Such sequences--- are commonly interpreted as UTF-16 encoded strings--- [RFC2781](https://webidl.spec.whatwg.org/#biblio-rfc2781) although this is not required.--- TODO: This implementation doesn't allow invalid UTF-16 codepoints, which--- probably makes it not work regarding <https://www.w3.org/TR/webauthn-2/#sctn-strings>--- Write a test case that doesn't work and find a better representation.-type DOMString = Text---- | [(spec)](https://webidl.spec.whatwg.org/#idl-USVString)--- The `[USVString](https://webidl.spec.whatwg.org/#idl-USVString)` type--- corresponds to the set of all possible sequences of--- [Unicode scalar values](http://www.unicode.org/glossary/#unicode_scalar_value),--- which are all of the Unicode code points apart from the surrogate code points.--- TODO: This implementation allows for surrogate code points. Figure out if--- this can violate the spec in any way.-type USVString = Text---- | [(spec)](https://webidl.spec.whatwg.org/#idl-unsigned-long)-type UnsignedLong = Word32---- | [(spec)](https://webidl.spec.whatwg.org/#idl-unsigned-long)-type UnsignedLongLong = Word64---- | [(spec)](https://webidl.spec.whatwg.org/#idl-long)-type Long = Int32---- | [(spec)](https://webidl.spec.whatwg.org/#idl-unsigned-short)-type UnsignedShort = Word16---- | [(spec)](https://webidl.spec.whatwg.org/#idl-octet)-type Octet = Word8---- | [(spec)](https://webidl.spec.whatwg.org/#idl-boolean)-type Boolean = Bool---- | [(spec)](https://webidl.spec.whatwg.org/#idl-double)-type Double = Prelude.Double---- | [(spec)](https://webidl.spec.whatwg.org/#BufferSource)-newtype BufferSource = -- | base64url encoded buffersource as done by https://github.com/github/webauthn-json-  URLEncodedBase64 {unUrlEncodedBase64 :: BS.ByteString}-  deriving (Show, Eq)--instance Aeson.FromJSON BufferSource where-  parseJSON = Aeson.withText "base64url" $ \t ->-    either fail (pure . URLEncodedBase64) (Base64.decode $ Text.encodeUtf8 t)--instance Aeson.ToJSON BufferSource where-  toJSON (URLEncodedBase64 bs) = Aeson.String . Text.decodeUtf8 . Base64.encodeUnpadded $ bs---- | [(spec)](https://webidl.spec.whatwg.org/#idl-ArrayBuffer)-type ArrayBuffer = BufferSource
tests/Emulation.hs view
@@ -10,7 +10,7 @@ import Control.Monad.Except (ExceptT (ExceptT), MonadError, MonadTrans (lift), runExceptT, throwError) import Crypto.Hash (hash) import qualified Crypto.Random as Random-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import qualified Crypto.WebAuthn.Metadata.Service.Types as Meta import qualified Crypto.WebAuthn.Model as M import qualified Crypto.WebAuthn.Operation as O@@ -164,7 +164,7 @@     isValidated O.RegistrationUserNotPresent = not $ M.adfUserPresent aAuthenticatorDataFlags     -- The User not being valided must be a result of the authenticator not validating the user     isValidated O.RegistrationUserNotVerified = not $ M.adfUserVerified aAuthenticatorDataFlags-    isValidated (O.RegistrationUndesiredPublicKeyAlgorithm _ _) = False+    isValidated (O.RegistrationPublicKeyAlgorithmDisallowed _ _) = False     isValidated (O.RegistrationAttestationFormatError _ _) = False  -- | Validates the result of assertion. Ensures that the proper errors are@@ -186,7 +186,7 @@ validAssertionResult AuthenticatorNone {..} uaConformance (Left errors) = all isValidated errors   where     isValidated :: O.AuthenticationError -> Bool-    isValidated (O.AuthenticationDisallowedCredential _ _) = False+    isValidated (O.AuthenticationCredentialDisallowed _ _) = False     isValidated (O.AuthenticationIdentifiedUserHandleMismatch _ _) = False     isValidated (O.AuthenticationCredentialUserHandleMismatch _ _) = False     isValidated O.AuthenticationCannotVerifyUserHandle = False@@ -199,7 +199,7 @@     isValidated O.AuthenticationUserNotVerified = not $ M.adfUserVerified aAuthenticatorDataFlags     -- The Signature being invalid can happen when the data was wrong or the wrong private key was used     isValidated (O.AuthenticationSignatureDecodingError _) = False-    isValidated O.AuthenticationInvalidSignature {} = elem RandomSignatureData aConformance || elem RandomPrivateKey aConformance+    isValidated O.AuthenticationSignatureInvalid {} = elem RandomSignatureData aConformance || elem RandomPrivateKey aConformance  -- | Create a default set of options for attestation. These options can be modified before using them in the tests defaultPkcoc :: M.CredentialUserEntity -> M.Challenge -> M.CredentialOptions 'M.Registration
tests/Emulation/Authenticator.hs view
@@ -19,9 +19,9 @@ import Crypto.Random (MonadRandom) import qualified Crypto.Random as Random import qualified Crypto.WebAuthn.AttestationStatementFormat.None as None-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose+import qualified Crypto.WebAuthn.Encoding.Binary as ME import qualified Crypto.WebAuthn.Model as M-import qualified Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding as ME import qualified Data.ByteArray as BA import qualified Data.ByteString as BS import Data.List (find)@@ -252,7 +252,7 @@             M.AttestedCredentialData               { M.acdAaguid = aAAGUID,                 M.acdCredentialId = credentialId,-                M.acdCredentialPublicKey = pubKey, -- This is selfsigned+                M.acdCredentialPublicKey = cosePubKey, -- This is selfsigned                 M.acdCredentialPublicKeyBytes = M.NoRaw               } 
tests/Emulation/Client.hs view
@@ -17,8 +17,8 @@  import Crypto.Hash (hash) import qualified Crypto.Random as Random+import qualified Crypto.WebAuthn.Encoding.Binary as ME import qualified Crypto.WebAuthn.Model as M-import qualified Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding as ME import Data.Maybe (fromMaybe) import qualified Data.Set as Set import Emulation.Authenticator@@ -64,7 +64,7 @@           M.CollectedClientData             { ccdChallenge = challenge,               ccdOrigin = aoOrigin,-              ccdCrossOrigin = False,+              ccdCrossOrigin = Just False,               ccdRawData = M.NoRaw             }       clientDataHash =@@ -121,7 +121,7 @@           M.CollectedClientData             { ccdChallenge = challenge,               ccdOrigin = aoOrigin,-              ccdCrossOrigin = False,+              ccdCrossOrigin = Just False,               ccdRawData = M.NoRaw             }       clientDataHash = M.ClientDataHash $ hash $ M.unRaw $ M.ccdRawData clientData
tests/Encoding.hs view
@@ -2,11 +2,11 @@  module Encoding (spec) where +import Control.Monad.Reader (runReaderT) import Crypto.WebAuthn.AttestationStatementFormat (allSupportedFormats)+import Crypto.WebAuthn.Encoding.Binary (encodeRawCredential)+import Crypto.WebAuthn.Encoding.Internal.WebAuthnJson (Decode (decode), Encode (encode)) import qualified Crypto.WebAuthn.Model as M-import Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding (encodeRawCredential)-import Crypto.WebAuthn.Model.WebIDL.Internal.Decoding (Decode (decode), DecodeCreated (decodeCreated))-import Crypto.WebAuthn.Model.WebIDL.Internal.Encoding (Encode (encode)) import Spec.Types () import Test.Hspec (Expectation, SpecWith, describe, expectationFailure, shouldBe) import Test.Hspec.QuickCheck (prop)@@ -40,7 +40,7 @@ prop_createdCredentialRoundtrip options = do   let withRaw = encodeRawCredential options       encoded = encode withRaw-  case decodeCreated allSupportedFormats encoded of+  case runReaderT (decode encoded) allSupportedFormats of     Right decoded -> do       decoded `shouldBe` withRaw     Left err -> expectationFailure $ show err
tests/Main.hs view
@@ -10,8 +10,8 @@ where  import Crypto.Hash (hash)-import Crypto.WebAuthn.AttestationStatementFormat (allSupportedFormats)-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose+import qualified Crypto.WebAuthn.Encoding.WebAuthnJson as WJ import qualified Crypto.WebAuthn.Metadata as Meta import qualified Crypto.WebAuthn.Metadata.Service.Types as Service import qualified Crypto.WebAuthn.Model as M@@ -80,7 +80,7 @@ registerTestFromFile :: FilePath -> M.Origin -> M.RpId -> Bool -> Service.MetadataServiceRegistry -> HG.DateTime -> IO () registerTestFromFile fp origin rpId verifiable service now = do   pkCredential <--    either (error . show) id . M.decodeCredentialRegistration allSupportedFormats+    either (error . show) id . WJ.wjDecodeCredentialRegistration       <$> decodeFile fp   let options = defaultPublicKeyCredentialCreationOptions pkCredential   let registerResult =@@ -101,12 +101,12 @@     -- Check if all attestation responses can be decoded     describe "attestation responses" $       canDecodeAllToJSRepr-        @M.IDLCredentialRegistration+        @WJ.WJCredentialRegistration         "tests/responses/attestation/"     -- Check if all assertion responses can be decoded     describe "assertion responses" $       canDecodeAllToJSRepr-        @M.IDLCredentialAuthentication+        @WJ.WJCredentialAuthentication         "tests/responses/assertion/"   -- Test public key related tests   describe "PublicKey" PublicKeySpec.spec@@ -124,7 +124,7 @@     it "tests whether the fixed register and login responses are matching" $       do         pkCredential <--          either (error . show) id . M.decodeCredentialRegistration allSupportedFormats+          either (error . show) id . WJ.wjDecodeCredentialRegistration             <$> decodeFile               "tests/responses/attestation/01-none.json"         let options = defaultPublicKeyCredentialCreationOptions pkCredential@@ -140,9 +140,9 @@         registerResult `shouldSatisfy` isExpectedAttestationResponse pkCredential options False         let Right O.RegistrationResult {O.rrEntry = credentialEntry} = registerResult         loginReq <--          either (error . show) id . M.decodeCredentialAuthentication+          either (error . show) id . WJ.wjDecodeCredentialAuthentication             <$> decodeFile-              @M.IDLCredentialAuthentication+              @WJ.WJCredentialAuthentication               "tests/responses/assertion/01-none.json"         let M.Credential {M.cResponse = cResponse} = loginReq             signInResult =
tests/PublicKeySpec.hs view
@@ -7,7 +7,8 @@  import Codec.Serialise.Properties (serialiseIdentity) import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.PublicKey as Cose import qualified Data.ByteString as BS import qualified Spec.Key as Key import Spec.Types ()@@ -28,18 +29,18 @@     property prop_signverify  prop_x509PublicKeyRoundtrip :: Cose.PublicKey -> Bool-prop_x509PublicKeyRoundtrip pubKey =+prop_x509PublicKeyRoundtrip (Cose.PublicKey pubKey) =   case Cose.fromX509 (Key.toX509 pubKey) of-    Right pubKey'+    Right (Cose.PublicKey pubKey')       | pubKey == pubKey' -> True       | otherwise -> False     Left _ -> False  prop_signverify :: Integer -> Key.KeyPair -> BS.ByteString -> Bool prop_signverify seed Key.KeyPair {..} msg = do-  let signAlg = Cose.keySignAlg pubKey+  let signAlg = Cose.signAlg cosePubKey       sig = runSeededMonadRandom seed $ Key.sign signAlg privKey msg-      valid = Cose.verify signAlg (Cose.fromCose pubKey) msg sig+      valid = Cose.verify cosePubKey msg sig    in case valid of         Left _ -> False         Right () -> True
tests/Spec/Key.hs view
@@ -19,14 +19,16 @@ import qualified Crypto.PubKey.RSA as RSA import qualified Crypto.PubKey.RSA.PKCS15 as RSA import Crypto.Random (MonadRandom)-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.PublicKey as Cose import qualified Data.ASN1.BinaryEncoding as ASN1 import qualified Data.ASN1.Encoding as ASN1 import qualified Data.ASN1.Prim as ASN1 import Data.ByteArray (convert) import qualified Data.ByteString as BS+import Data.Either (fromRight) import qualified Data.X509 as X509 import Test.QuickCheck.Instances.ByteString () @@ -47,7 +49,7 @@   deriving (Eq, Show)  data KeyPair = KeyPair-  { pubKey :: Cose.CosePublicKey,+  { cosePubKey :: Cose.CosePublicKey,     privKey :: PrivateKey   }   deriving (Eq, Show)@@ -61,11 +63,13 @@             eddsaBytes = convert privKey'           }       pubKey' = Ed25519.toPublic privKey'-      pubKey =-        Cose.CosePublicKeyEdDSA+      unchecked =+        Cose.PublicKeyEdDSA           { eddsaCurve = Cose.CoseCurveEd25519,             eddsaX = convert pubKey'           }+      pubKey = fromRight (error "unreachable") $ Cose.checkPublicKey unchecked+      cosePubKey = fromRight (error "unreachable") $ Cose.makePublicKeyWithSignAlg pubKey Cose.CoseSignAlgEdDSA   pure KeyPair {..} newKeyPair (Cose.CoseSignAlgECDSA hash) = do   let coseCurve = case hash of@@ -74,33 +78,33 @@         Cose.CoseHashAlgECDSASHA512 -> Cose.CoseCurveP521       curveName = Cose.toCryptCurveECDSA coseCurve       curve = ECC.getCurveByName curveName-      byteSize = (ECC.curveSizeBits curve + 7) `div` 8   (ECDSA.PublicKey {public_q = point}, ECDSA.PrivateKey {private_d = d}) <- ECC.generate curve   let (x, y) = case point of         ECC.Point x y -> (x, y)         ECC.PointO -> error "newKeyPair: infinity point not supported" -      pubKey =-        Cose.CosePublicKeyECDSA-          { ecdsaHash = hash,-            ecdsaCurve = coseCurve,-            ecdsaX = i2ospOf_ byteSize x,-            ecdsaY = i2ospOf_ byteSize y+      unchecked =+        Cose.PublicKeyECDSA+          { ecdsaCurve = coseCurve,+            ecdsaX = x,+            ecdsaY = y           }       privKey =         PrivateKeyECDSA           { ecdsaCurve = coseCurve,             ecdsaD = d           }+      pubKey = fromRight (error "unreachable") $ Cose.checkPublicKey unchecked+      cosePubKey = fromRight (error "unreachable") $ Cose.makePublicKeyWithSignAlg pubKey (Cose.CoseSignAlgECDSA hash)   pure KeyPair {..} newKeyPair (Cose.CoseSignAlgRSA hash) = do   -- https://www.rfc-editor.org/rfc/rfc8812.html#section-2   -- > A key of size 2048 bits or larger MUST be used with these algorithms.   let publicSizeBytes = 2048 `div` 8   (RSA.PublicKey {..}, RSA.PrivateKey {..}) <- RSA.generate publicSizeBytes 65537-  let pubKey =-        Cose.CosePublicKeyRSA-          { rsaHash = hash,+  let unchecked =+        Cose.PublicKeyRSA+          { -- rsaHash = hash,             rsaN = public_n,             rsaE = public_e           }@@ -110,6 +114,8 @@             rsaE = public_e,             rsaD = private_d           }+      pubKey = fromRight (error "unreachable") $ Cose.checkPublicKey unchecked+      cosePubKey = fromRight (error "unreachable") $ Cose.makePublicKeyWithSignAlg pubKey (Cose.CoseSignAlgRSA hash)   pure KeyPair {..}  sign :: MonadRandom m => Cose.CoseSignAlg -> PrivateKey -> BS.ByteString -> m BS.ByteString@@ -149,7 +155,7 @@     Right res -> pure res sign signAlg privKey _ = error $ "sign: Combination of signature algorithm " <> show signAlg <> " and private key " <> show privKey <> " is not valid or supported" -toX509 :: Cose.PublicKey -> X509.PubKey+toX509 :: Cose.UncheckedPublicKey -> X509.PubKey toX509 Cose.PublicKeyEdDSA {eddsaCurve = Cose.CoseCurveEd25519, ..} =   let key = case Ed25519.publicKey eddsaX of         CryptoFailed err -> error $ "Failed to create a cryptonite Ed25519 public key of a bytestring with size " <> show (BS.length eddsaX) <> ": " <> show err@@ -157,7 +163,8 @@    in X509.PubKeyEd25519 key toX509 Cose.PublicKeyECDSA {..} =   let curveName = Cose.toCryptCurveECDSA ecdsaCurve-      serialisedPoint = X509.SerializedPoint $ BS.singleton 0x04 <> ecdsaX <> ecdsaY+      size = Cose.coordinateSizeECDSA ecdsaCurve+      serialisedPoint = X509.SerializedPoint $ BS.singleton 0x04 <> i2ospOf_ size ecdsaX <> i2ospOf_ size ecdsaY       key = X509.PubKeyEC_Named curveName serialisedPoint    in X509.PubKeyEC key toX509 Cose.PublicKeyRSA {..} =
tests/Spec/Types.hs view
@@ -12,9 +12,9 @@ import Crypto.Hash (hash) import qualified Crypto.Random as Random import qualified Crypto.WebAuthn.AttestationStatementFormat.None as None-import qualified Crypto.WebAuthn.Cose.Algorithm as Cose-import qualified Crypto.WebAuthn.Cose.Internal.Verify as Cose-import qualified Crypto.WebAuthn.Cose.Key as Cose+import qualified Crypto.WebAuthn.Cose.PublicKey as Cose+import qualified Crypto.WebAuthn.Cose.PublicKeyWithSignAlg as Cose+import qualified Crypto.WebAuthn.Cose.SignAlg as Cose import qualified Crypto.WebAuthn.Model as M import qualified Data.ByteString.Lazy as LBS import Data.Maybe (fromJust)@@ -54,10 +54,10 @@       ]  instance Arbitrary Cose.PublicKey where-  arbitrary = Cose.fromCose <$> arbitrary+  arbitrary = Cose.publicKey <$> arbitrary  instance Arbitrary Cose.CosePublicKey where-  arbitrary = Key.pubKey <$> arbitrary+  arbitrary = Key.cosePubKey <$> arbitrary  instance Arbitrary Cose.CoseCurveEdDSA where   arbitrary = arbitraryBoundedEnum@@ -75,8 +75,17 @@   arbitrary = arbitraryBoundedEnum  instance Arbitrary M.AuthenticatorTransport where-  arbitrary = arbitraryBoundedEnum+  arbitrary = elements authenticatorTransportsList +authenticatorTransportsList :: [M.AuthenticatorTransport]+authenticatorTransportsList =+  [ M.AuthenticatorTransportBLE,+    M.AuthenticatorTransportInternal,+    M.AuthenticatorTransportNFC,+    M.AuthenticatorTransportUSB,+    M.AuthenticatorTransportUnknown "unknown"+  ]+ instance Arbitrary M.AuthenticatorAttachment where   arbitrary = arbitraryBoundedEnum @@ -107,7 +116,14 @@   arbitrary = pure M.NoRaw  instance Arbitrary (M.CollectedClientData c 'False) where-  arbitrary = M.CollectedClientData <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+  arbitrary =+    M.CollectedClientData+      <$> arbitrary+        <*> arbitrary+        -- The crossOrigin value can't be roundtripped with Nothing values,+        -- so let's just not generate Nothing values here+        <*> (Just <$> arbitrary)+        <*> arbitrary  instance Arbitrary (M.AttestationObject 'False) where   arbitrary = do@@ -211,7 +227,7 @@   arbitrary =     M.CredentialDescriptor M.CredentialTypePublicKey       <$> arbitrary-      <*> liftArbitrary shuffledSubset+      <*> liftArbitrary (shuffledSubsetWith $ Set.fromList authenticatorTransportsList)  instance Arbitrary M.AuthenticatorSelectionCriteria where   arbitrary =@@ -263,15 +279,9 @@       <*> arbitrary       <*> arbitrary -shuffledSubset :: (Ord a, Bounded a, Enum a) => Gen [a]-shuffledSubset = subset >>= shuffle . Set.toList- shuffledSubsetWith :: Ord a => Set a -> Gen [a] shuffledSubsetWith set = subsetWith set >>= shuffle . Set.toList -subset :: (Ord a, Bounded a, Enum a) => Gen (Set a)-subset = Set.fromList <$> sublistOf (Set.toList completeSet)- subsetWith :: Ord a => Set a -> Gen (Set a) subsetWith set = Set.fromList <$> sublistOf (Set.toList set) @@ -279,9 +289,6 @@ parameters = do   algs <- shuffledSubsetWith $ Set.fromList allCoseAlgs   pure $ M.CredentialParameters M.CredentialTypePublicKey <$> algs--completeSet :: (Ord a, Bounded a, Enum a) => Set a-completeSet = Set.fromList [minBound .. maxBound]  allCoseAlgs :: [Cose.CoseSignAlg] allCoseAlgs =
webauthn.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: webauthn-version: 0.3.0.0+version: 0.4.0.0 license: Apache-2.0 license-file: LICENSE copyright:@@ -113,14 +113,20 @@     Crypto.WebAuthn.AttestationStatementFormat.None,     Crypto.WebAuthn.AttestationStatementFormat.Packed,     Crypto.WebAuthn.AttestationStatementFormat.TPM,+    Crypto.WebAuthn.Encoding,+    Crypto.WebAuthn.Encoding.Binary,+    Crypto.WebAuthn.Encoding.Internal.WebAuthnJson,+    Crypto.WebAuthn.Encoding.Strings,+    Crypto.WebAuthn.Encoding.WebAuthnJson,     Crypto.WebAuthn.Operation,     Crypto.WebAuthn.Operation.Authentication,     Crypto.WebAuthn.Operation.CredentialEntry,     Crypto.WebAuthn.Operation.Registration,-    Crypto.WebAuthn.Cose.Algorithm,     Crypto.WebAuthn.Cose.Internal.Registry,     Crypto.WebAuthn.Cose.Internal.Verify,-    Crypto.WebAuthn.Cose.Key,+    Crypto.WebAuthn.Cose.PublicKey,+    Crypto.WebAuthn.Cose.PublicKeyWithSignAlg,+    Crypto.WebAuthn.Cose.SignAlg,     Crypto.WebAuthn.Internal.DateOrphans,     Crypto.WebAuthn.Internal.ToJSONOrphans,     Crypto.WebAuthn.Internal.Utils,@@ -134,18 +140,12 @@     Crypto.WebAuthn.Metadata.Statement.Types,     Crypto.WebAuthn.Metadata.Statement.WebIDL,     Crypto.WebAuthn.Metadata.UAF,+    Crypto.WebAuthn.Metadata.WebIDL,     Crypto.WebAuthn.Model,+    Crypto.WebAuthn.Model.Defaults,     Crypto.WebAuthn.Model.Identifier,     Crypto.WebAuthn.Model.Kinds,-    Crypto.WebAuthn.Model.Types,-    Crypto.WebAuthn.Model.WebIDL,-    Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Decoding,-    Crypto.WebAuthn.Model.WebIDL.Internal.Binary.Encoding,-    Crypto.WebAuthn.Model.WebIDL.Internal.Decoding,-    Crypto.WebAuthn.Model.WebIDL.Internal.Encoding,-    Crypto.WebAuthn.Model.WebIDL.Internal.Convert,-    Crypto.WebAuthn.Model.WebIDL.Types,-    Crypto.WebAuthn.WebIDL+    Crypto.WebAuthn.Model.Types  test-suite tests   import: sanity