{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}

-- | Stability: internal
-- public keys and signature algorithms are represented with three
-- different types:
--
-- * 'Cose.CoseSignAlg', which is the signature algorithm used, equivalent to a
--   COSE Algorithm from the COSE registry
-- * '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'
--
-- 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 'verify'
module Crypto.WebAuthn.Cose.Internal.Verify
  ( -- * Public Key
    PublicKey (..),
    fromCose,
    fromX509,

    -- * Signature verification
    verify,

    -- * Hash Conversions to cryptonite types
    SomeHashAlgorithm (..),
    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 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 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
        PublicKey -> CoseCurveEdDSA
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
        PublicKey -> ByteString
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
        PublicKey -> CoseCurveECDSA
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.
        PublicKey -> ByteString
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.
        PublicKey -> ByteString
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
        PublicKey -> Integer
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)
        PublicKey -> Integer
rsaE :: Integer
      }
  deriving (PublicKey -> PublicKey -> Bool
(PublicKey -> PublicKey -> Bool)
-> (PublicKey -> PublicKey -> Bool) -> Eq PublicKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PublicKey -> PublicKey -> Bool
$c/= :: PublicKey -> PublicKey -> Bool
== :: PublicKey -> PublicKey -> Bool
$c== :: PublicKey -> PublicKey -> Bool
Eq, Int -> PublicKey -> ShowS
[PublicKey] -> ShowS
PublicKey -> String
(Int -> PublicKey -> ShowS)
-> (PublicKey -> String)
-> ([PublicKey] -> ShowS)
-> Show PublicKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PublicKey] -> ShowS
$cshowList :: [PublicKey] -> ShowS
show :: PublicKey -> String
$cshow :: PublicKey -> String
showsPrec :: Int -> PublicKey -> ShowS
$cshowsPrec :: Int -> PublicKey -> ShowS
Show, (forall x. PublicKey -> Rep PublicKey x)
-> (forall x. Rep PublicKey x -> PublicKey) -> Generic PublicKey
forall x. Rep PublicKey x -> PublicKey
forall x. PublicKey -> Rep PublicKey x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep PublicKey x -> PublicKey
$cfrom :: forall x. PublicKey -> Rep PublicKey x
Generic, [PublicKey] -> Encoding
[PublicKey] -> Value
PublicKey -> Encoding
PublicKey -> Value
(PublicKey -> Value)
-> (PublicKey -> Encoding)
-> ([PublicKey] -> Value)
-> ([PublicKey] -> Encoding)
-> ToJSON PublicKey
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [PublicKey] -> Encoding
$ctoEncodingList :: [PublicKey] -> Encoding
toJSONList :: [PublicKey] -> Value
$ctoJSONList :: [PublicKey] -> Value
toEncoding :: PublicKey -> Encoding
$ctoEncoding :: PublicKey -> Encoding
toJSON :: PublicKey -> Value
$ctoJSON :: PublicKey -> Value
ToJSON)

-- | Turns a 'Cose.CosePublicKey' into a 'PublicKey' by removing the hash functions
fromCose :: Cose.CosePublicKey -> PublicKey
fromCose :: CosePublicKey -> PublicKey
fromCose Cose.CosePublicKeyEdDSA {ByteString
CoseCurveEdDSA
eddsaX :: CosePublicKey -> ByteString
eddsaCurve :: CosePublicKey -> CoseCurveEdDSA
eddsaX :: ByteString
eddsaCurve :: CoseCurveEdDSA
..} = PublicKeyEdDSA :: CoseCurveEdDSA -> ByteString -> PublicKey
PublicKeyEdDSA {ByteString
CoseCurveEdDSA
eddsaX :: ByteString
eddsaCurve :: CoseCurveEdDSA
eddsaX :: ByteString
eddsaCurve :: CoseCurveEdDSA
..}
fromCose Cose.CosePublicKeyECDSA {ByteString
CoseHashAlgECDSA
CoseCurveECDSA
ecdsaY :: CosePublicKey -> ByteString
ecdsaX :: CosePublicKey -> ByteString
ecdsaCurve :: CosePublicKey -> CoseCurveECDSA
ecdsaHash :: CosePublicKey -> CoseHashAlgECDSA
ecdsaY :: ByteString
ecdsaX :: ByteString
ecdsaCurve :: CoseCurveECDSA
ecdsaHash :: CoseHashAlgECDSA
..} = PublicKeyECDSA :: CoseCurveECDSA -> ByteString -> ByteString -> PublicKey
PublicKeyECDSA {ByteString
CoseCurveECDSA
ecdsaY :: ByteString
ecdsaX :: ByteString
ecdsaCurve :: CoseCurveECDSA
ecdsaY :: ByteString
ecdsaX :: ByteString
ecdsaCurve :: CoseCurveECDSA
..}
fromCose Cose.CosePublicKeyRSA {Integer
CoseHashAlgRSA
rsaE :: CosePublicKey -> Integer
rsaN :: CosePublicKey -> Integer
rsaHash :: CosePublicKey -> CoseHashAlgRSA
rsaE :: Integer
rsaN :: Integer
rsaHash :: CoseHashAlgRSA
..} = PublicKeyRSA :: Integer -> Integer -> PublicKey
PublicKeyRSA {Integer
rsaE :: Integer
rsaN :: Integer
rsaE :: Integer
rsaN :: Integer
..}

-- | Turns a X.509 certificates 'X509.PubKey' into a 'PublicKey'
fromX509 :: X509.PubKey -> Either Text PublicKey
fromX509 :: PubKey -> Either Text PublicKey
fromX509 (X509.PubKeyEd25519 PublicKey
key) =
  PublicKey -> Either Text PublicKey
forall a b. b -> Either a b
Right (PublicKey -> Either Text PublicKey)
-> PublicKey -> Either Text PublicKey
forall a b. (a -> b) -> a -> b
$
    PublicKeyEdDSA :: CoseCurveEdDSA -> ByteString -> PublicKey
PublicKeyEdDSA
      { eddsaCurve :: CoseCurveEdDSA
eddsaCurve = CoseCurveEdDSA
Cose.CoseCurveEd25519,
        eddsaX :: ByteString
eddsaX = PublicKey -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert PublicKey
key
      }
fromX509 (X509.PubKeyEC X509.PubKeyEC_Named {CurveName
SerializedPoint
pubkeyEC_pub :: PubKeyEC -> SerializedPoint
pubkeyEC_name :: PubKeyEC -> CurveName
pubkeyEC_pub :: SerializedPoint
pubkeyEC_name :: CurveName
..}) = do
  let curve :: Curve
curve = CurveName -> Curve
ECC.getCurveByName CurveName
pubkeyEC_name
  CoseCurveECDSA
ecdsaCurve <- CurveName -> Either Text CoseCurveECDSA
fromCryptCurveECDSA CurveName
pubkeyEC_name
  Point
point <- case Curve -> SerializedPoint -> Maybe Point
X509.unserializePoint Curve
curve SerializedPoint
pubkeyEC_pub of
    Maybe Point
Nothing -> Text -> Either Text Point
forall a b. a -> Either a b
Left Text
"Failed to unserialize ECDSA point in X509 certificate"
    Just Point
res -> Point -> Either Text Point
forall (f :: * -> *) a. Applicative f => a -> f a
pure Point
res
  -- Round up to a full byte
  let byteSize :: Int
byteSize = (Curve -> Int
ECC.curveSizeBits Curve
curve Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
7) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
8
  case Point
point of
    ECC.Point Integer
x Integer
y -> do
      ByteString
ecdsaX <- case Int -> Integer -> Maybe ByteString
forall ba. ByteArray ba => Int -> Integer -> Maybe ba
i2ospOf Int
byteSize Integer
x of
        Maybe ByteString
Nothing -> Text -> Either Text ByteString
forall a b. a -> Either a b
Left (Text -> Either Text ByteString) -> Text -> Either Text ByteString
forall a b. (a -> b) -> a -> b
$ Text
"Failed to convert ECDSA x coordinate integer " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (Integer -> String
forall a. Show a => a -> String
show Integer
x) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" to bytes of size " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (Int -> String
forall a. Show a => a -> String
show Int
byteSize)
        Just ByteString
res -> ByteString -> Either Text ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString
res
      ByteString
ecdsaY <- case Int -> Integer -> Maybe ByteString
forall ba. ByteArray ba => Int -> Integer -> Maybe ba
i2ospOf Int
byteSize Integer
y of
        Maybe ByteString
Nothing -> Text -> Either Text ByteString
forall a b. a -> Either a b
Left (Text -> Either Text ByteString) -> Text -> Either Text ByteString
forall a b. (a -> b) -> a -> b
$ Text
"Failed to convert ECDSA y coordinate integer " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (Integer -> String
forall a. Show a => a -> String
show Integer
y) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" to bytes of size " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (Int -> String
forall a. Show a => a -> String
show Int
byteSize)
        Just ByteString
res -> ByteString -> Either Text ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString
res
      PublicKey -> Either Text PublicKey
forall a b. b -> Either a b
Right (PublicKey -> Either Text PublicKey)
-> PublicKey -> Either Text PublicKey
forall a b. (a -> b) -> a -> b
$ PublicKeyECDSA :: CoseCurveECDSA -> ByteString -> ByteString -> PublicKey
PublicKeyECDSA {ByteString
CoseCurveECDSA
ecdsaY :: ByteString
ecdsaX :: ByteString
ecdsaCurve :: CoseCurveECDSA
ecdsaY :: ByteString
ecdsaX :: ByteString
ecdsaCurve :: CoseCurveECDSA
..}
    Point
ECC.PointO -> Text -> Either Text PublicKey
forall a b. a -> Either a b
Left Text
"The infinity point is not supported"
fromX509 (X509.PubKeyRSA RSA.PublicKey {Int
Integer
public_size :: PublicKey -> Int
public_n :: PublicKey -> Integer
public_e :: PublicKey -> Integer
public_e :: Integer
public_n :: Integer
public_size :: Int
..}) =
  PublicKey -> Either Text PublicKey
forall a b. b -> Either a b
Right
    PublicKeyRSA :: Integer -> Integer -> PublicKey
PublicKeyRSA
      { rsaN :: Integer
rsaN = Integer
public_n,
        rsaE :: Integer
rsaE = Integer
public_e
      }
fromX509 PubKey
key = Text -> Either Text PublicKey
forall a b. a -> Either a b
Left (Text -> Either Text PublicKey) -> Text -> Either Text PublicKey
forall a b. (a -> b) -> a -> b
$ Text
"X509 public key algorithm is not supported: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (PubKeyALG -> String
forall a. Show a => a -> String
show (PubKey -> PubKeyALG
X509.pubkeyToAlg PubKey
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 :: CoseSignAlg
-> PublicKey -> ByteString -> ByteString -> Either Text ()
verify CoseSignAlg
A.CoseSignAlgEdDSA PublicKeyEdDSA {eddsaCurve :: PublicKey -> CoseCurveEdDSA
eddsaCurve = CoseCurveEdDSA
Cose.CoseCurveEd25519, ByteString
eddsaX :: ByteString
eddsaX :: PublicKey -> ByteString
..} ByteString
msg ByteString
sig = do
  PublicKey
key <- case ByteString -> CryptoFailable PublicKey
forall ba. ByteArrayAccess ba => ba -> CryptoFailable PublicKey
Ed25519.publicKey ByteString
eddsaX of
    CryptoFailed CryptoError
err -> Text -> Either Text PublicKey
forall a b. a -> Either a b
Left (Text -> Either Text PublicKey) -> Text -> Either Text PublicKey
forall a b. (a -> b) -> a -> b
$ Text
"Failed to create Ed25519 public key: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (CryptoError -> String
forall a. Show a => a -> String
show CryptoError
err)
    CryptoPassed PublicKey
res -> PublicKey -> Either Text PublicKey
forall (f :: * -> *) a. Applicative f => a -> f a
pure PublicKey
res
  Signature
sig <- case ByteString -> CryptoFailable Signature
forall ba. ByteArrayAccess ba => ba -> CryptoFailable Signature
Ed25519.signature ByteString
sig of
    CryptoFailed CryptoError
err -> Text -> Either Text Signature
forall a b. a -> Either a b
Left (Text -> Either Text Signature) -> Text -> Either Text Signature
forall a b. (a -> b) -> a -> b
$ Text
"Failed to create Ed25519 signature: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (CryptoError -> String
forall a. Show a => a -> String
show CryptoError
err)
    CryptoPassed Signature
res -> Signature -> Either Text Signature
forall (f :: * -> *) a. Applicative f => a -> f a
pure Signature
res
  if PublicKey -> ByteString -> Signature -> Bool
forall ba.
ByteArrayAccess ba =>
PublicKey -> ba -> Signature -> Bool
Ed25519.verify PublicKey
key ByteString
msg Signature
sig
    then () -> Either Text ()
forall a b. b -> Either a b
Right ()
    else Text -> Either Text ()
forall a b. a -> Either a b
Left Text
"EdDSA Signature invalid"
verify (A.CoseSignAlgECDSA (CoseHashAlgECDSA -> SomeHashAlgorithm
toCryptHashECDSA -> SomeHashAlgorithm a
hash)) PublicKeyECDSA {ByteString
CoseCurveECDSA
ecdsaY :: ByteString
ecdsaX :: ByteString
ecdsaCurve :: CoseCurveECDSA
ecdsaY :: PublicKey -> ByteString
ecdsaX :: PublicKey -> ByteString
ecdsaCurve :: PublicKey -> CoseCurveECDSA
..} ByteString
msg ByteString
sig = do
  let key :: PublicKey
key =
        PublicKey :: Curve -> Point -> PublicKey
ECDSA.PublicKey
          { public_curve :: Curve
public_curve = CurveName -> Curve
ECC.getCurveByName (CurveName -> Curve) -> CurveName -> Curve
forall a b. (a -> b) -> a -> b
$ CoseCurveECDSA -> CurveName
toCryptCurveECDSA CoseCurveECDSA
ecdsaCurve,
            public_q :: Point
public_q = Integer -> Integer -> Point
ECC.Point (ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
ecdsaX) (ByteString -> Integer
forall ba. ByteArrayAccess ba => ba -> Integer
os2ip ByteString
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.
  Signature
sig <- case DER -> ByteString -> Either ASN1Error [ASN1]
forall a.
ASN1Decoding a =>
a -> ByteString -> Either ASN1Error [ASN1]
ASN1.decodeASN1' DER
ASN1.DER ByteString
sig of
    Left ASN1Error
err -> Text -> Either Text Signature
forall a b. a -> Either a b
Left (Text -> Either Text Signature) -> Text -> Either Text Signature
forall a b. (a -> b) -> a -> b
$ Text
"Failed to decode ECDSA DER value: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (ASN1Error -> String
forall a. Show a => a -> String
show ASN1Error
err)
    -- Ecdsa-Sig-Value in https://datatracker.ietf.org/doc/html/rfc3279#section-2.2.3
    Right [ASN1.Start ASN1ConstructionType
ASN1.Sequence, ASN1.IntVal Integer
r, ASN1.IntVal Integer
s, ASN1.End ASN1ConstructionType
ASN1.Sequence] ->
      Signature -> Either Text Signature
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Signature -> Either Text Signature)
-> Signature -> Either Text Signature
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Signature
ECDSA.Signature Integer
r Integer
s
    Right [ASN1]
asns -> Text -> Either Text Signature
forall a b. a -> Either a b
Left (Text -> Either Text Signature) -> Text -> Either Text Signature
forall a b. (a -> b) -> a -> b
$ Text
"Unexpected ECDSA ASN.1 structure: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack ([ASN1] -> String
forall a. Show a => a -> String
show [ASN1]
asns)

  if a -> PublicKey -> Signature -> ByteString -> Bool
forall msg hash.
(ByteArrayAccess msg, HashAlgorithm hash) =>
hash -> PublicKey -> Signature -> msg -> Bool
ECDSA.verify a
hash PublicKey
key Signature
sig ByteString
msg
    then () -> Either Text ()
forall a b. b -> Either a b
Right ()
    else Text -> Either Text ()
forall a b. a -> Either a b
Left Text
"ECDSA Signature invalid"
verify (A.CoseSignAlgRSA (CoseHashAlgRSA -> SomeHashAlgorithmASN1
toCryptHashRSA -> SomeHashAlgorithmASN1 a
hash)) PublicKeyRSA {Integer
rsaE :: Integer
rsaN :: Integer
rsaE :: PublicKey -> Integer
rsaN :: PublicKey -> Integer
..} ByteString
msg ByteString
sig = do
  let key :: PublicKey
key =
        PublicKey :: Int -> Integer -> Integer -> PublicKey
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 :: Int
public_size = ByteString -> Int
BS.length (Integer -> ByteString
forall ba. ByteArray ba => Integer -> ba
i2osp Integer
rsaN),
            public_n :: Integer
public_n = Integer
rsaN,
            public_e :: Integer
public_e = Integer
rsaE
          }
  if Maybe a -> PublicKey -> ByteString -> ByteString -> Bool
forall hashAlg.
HashAlgorithmASN1 hashAlg =>
Maybe hashAlg -> PublicKey -> ByteString -> ByteString -> Bool
RSA.verify (a -> Maybe a
forall a. a -> Maybe a
Just a
hash) PublicKey
key ByteString
msg ByteString
sig
    then () -> Either Text ()
forall a b. b -> Either a b
Right ()
    else Text -> Either Text ()
forall a b. a -> Either a b
Left Text
"RSA Signature invalid"
verify CoseSignAlg
sigAlg PublicKey
pubKey ByteString
_ ByteString
_ =
  Text -> Either Text ()
forall a b. a -> Either a b
Left (Text -> Either Text ()) -> Text -> Either Text ()
forall a b. (a -> b) -> a -> b
$ Text
"Unsupported combination of signature algorithm " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (CoseSignAlg -> String
forall a. Show a => a -> String
show CoseSignAlg
sigAlg) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" and public key " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (PublicKey -> String
forall a. Show a => a -> String
show PublicKey
pubKey)

-- | 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 :: CoseHashAlgECDSA -> SomeHashAlgorithm
toCryptHashECDSA CoseHashAlgECDSA
A.CoseHashAlgECDSASHA256 = SHA256 -> SomeHashAlgorithm
forall a. HashAlgorithm a => a -> SomeHashAlgorithm
SomeHashAlgorithm SHA256
Hash.SHA256
toCryptHashECDSA CoseHashAlgECDSA
A.CoseHashAlgECDSASHA384 = SHA384 -> SomeHashAlgorithm
forall a. HashAlgorithm a => a -> SomeHashAlgorithm
SomeHashAlgorithm SHA384
Hash.SHA384
toCryptHashECDSA CoseHashAlgECDSA
A.CoseHashAlgECDSASHA512 = SHA512 -> SomeHashAlgorithm
forall a. HashAlgorithm a => a -> SomeHashAlgorithm
SomeHashAlgorithm SHA512
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 :: CoseHashAlgRSA -> SomeHashAlgorithmASN1
toCryptHashRSA CoseHashAlgRSA
A.CoseHashAlgRSASHA1 = SHA1 -> SomeHashAlgorithmASN1
forall a. HashAlgorithmASN1 a => a -> SomeHashAlgorithmASN1
SomeHashAlgorithmASN1 SHA1
Hash.SHA1
toCryptHashRSA CoseHashAlgRSA
A.CoseHashAlgRSASHA256 = SHA256 -> SomeHashAlgorithmASN1
forall a. HashAlgorithmASN1 a => a -> SomeHashAlgorithmASN1
SomeHashAlgorithmASN1 SHA256
Hash.SHA256
toCryptHashRSA CoseHashAlgRSA
A.CoseHashAlgRSASHA384 = SHA384 -> SomeHashAlgorithmASN1
forall a. HashAlgorithmASN1 a => a -> SomeHashAlgorithmASN1
SomeHashAlgorithmASN1 SHA384
Hash.SHA384
toCryptHashRSA CoseHashAlgRSA
A.CoseHashAlgRSASHA512 = SHA512 -> SomeHashAlgorithmASN1
forall a. HashAlgorithmASN1 a => a -> SomeHashAlgorithmASN1
SomeHashAlgorithmASN1 SHA512
Hash.SHA512

-- | Converts a 'Cose.CoseCurveECDSA' to an 'ECC.CurveName'. The inverse
-- function is 'fromCryptCurveECDSA'
toCryptCurveECDSA :: Cose.CoseCurveECDSA -> ECC.CurveName
toCryptCurveECDSA :: CoseCurveECDSA -> CurveName
toCryptCurveECDSA CoseCurveECDSA
Cose.CoseCurveP256 = CurveName
ECC.SEC_p256r1
toCryptCurveECDSA CoseCurveECDSA
Cose.CoseCurveP384 = CurveName
ECC.SEC_p384r1
toCryptCurveECDSA CoseCurveECDSA
Cose.CoseCurveP521 = CurveName
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 :: CurveName -> Either Text CoseCurveECDSA
fromCryptCurveECDSA CurveName
ECC.SEC_p256r1 = CoseCurveECDSA -> Either Text CoseCurveECDSA
forall a b. b -> Either a b
Right CoseCurveECDSA
Cose.CoseCurveP256
fromCryptCurveECDSA CurveName
ECC.SEC_p384r1 = CoseCurveECDSA -> Either Text CoseCurveECDSA
forall a b. b -> Either a b
Right CoseCurveECDSA
Cose.CoseCurveP384
fromCryptCurveECDSA CurveName
ECC.SEC_p521r1 = CoseCurveECDSA -> Either Text CoseCurveECDSA
forall a b. b -> Either a b
Right CoseCurveECDSA
Cose.CoseCurveP521
fromCryptCurveECDSA CurveName
curve = Text -> Either Text CoseCurveECDSA
forall a b. a -> Either a b
Left (Text -> Either Text CoseCurveECDSA)
-> Text -> Either Text CoseCurveECDSA
forall a b. (a -> b) -> a -> b
$ Text
"Curve " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
Text.pack (CurveName -> String
forall a. Show a => a -> String
show CurveName
curve) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not a supported COSE ECDSA public key curve"