packages feed

webauthn-0.1.0.0: src/Crypto/WebAuthn/Cose/Internal/Registry.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | Stability: internal
-- 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.Internal.Registry
  ( -- * COSE Key Types
    CoseKeyType (..),

    -- * COSE Parameters
    CoseKeyCommonParameter (..),
    CoseKeyTypeParameterOKP (..),
    CoseKeyTypeParameterEC2 (..),
    CoseKeyTypeParameterRSA (..),
    parameterCount,

    -- * COSE Elliptic Curves
    CoseEllipticCurveOKP (..),
    CoseEllipticCurveEC2 (..),
  )
where

import Codec.CBOR.Decoding (decodeIntCanonical)
import Codec.CBOR.Encoding (encodeInt)
import Codec.Serialise (Serialise)
import Codec.Serialise.Class (decode, encode)

-- | [(spec)](https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters)
-- All the entries from the [COSE Key Common Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters)
-- that are needed for Webauthn public keys
data CoseKeyCommonParameter
  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-15#section-7.1)
    --
    -- * COSE value type: tstr / int
    -- * Value registry: 'CoseKeyType'
    -- * Description: Identification of the key type
    --
    -- This parameter is used to identify the family of keys for this
    -- structure and, thus, the set of key-type-specific parameters to be
    -- found. The key type MUST be included as part of the trust decision
    -- process.
    CoseKeyCommonParameterKty
  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-struct-15#section-7.1)
    --
    -- * COSE value type: tstr / int
    -- * Value registry: 'Crypto.WebAuthn.Cose.Algorithm.CoseSignAlg'
    -- * Description: Key usage restriction to this algorithm
    --
    -- This parameter is used to restrict the algorithm that is used
    -- with the key.
    CoseKeyCommonParameterAlg
  deriving (Eq, Show, Bounded, Enum)

-- | Serialises the parameters using the @Label@ column from the
-- [COSE Key Common Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters)
instance Serialise CoseKeyCommonParameter where
  encode CoseKeyCommonParameterKty = encodeInt 1
  encode CoseKeyCommonParameterAlg = encodeInt 3
  decode =
    decodeIntCanonical >>= \case
      1 -> pure CoseKeyCommonParameterKty
      3 -> pure CoseKeyCommonParameterAlg
      value -> fail $ "Unknown COSE key common parameter " <> show value

-- | [(spec)](https://www.iana.org/assignments/cose/cose.xhtml#key-type)
-- All the entries from the [COSE Key Types registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type)
-- that are known to be needed for Webauthn public keys
data CoseKeyType
  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)
    -- Octet Key Pair.
    -- See 'CoseKeyTypeParameterOKP' for the parameters specific to this key type.
    CoseKeyTypeOKP
  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)
    -- Elliptic Curve Keys w/ x- and y-coordinate pair.
    -- See 'CoseKeyTypeParameterEC2' for the parameters specific to this key type.
    CoseKeyTypeEC2
  | -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)
    -- RSA Key.
    -- See 'CoseKeyTypeParameterRSA' for the parameters specific to this key type.
    CoseKeyTypeRSA
  deriving (Eq, Show)

-- | Serialises the key type using the @Value@ column from the
-- [COSE Key Types registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type)
instance Serialise CoseKeyType where
  encode CoseKeyTypeOKP = encodeInt 1
  encode CoseKeyTypeEC2 = encodeInt 2
  encode CoseKeyTypeRSA = encodeInt 3
  decode =
    decodeIntCanonical >>= \case
      1 -> pure CoseKeyTypeOKP
      2 -> pure CoseKeyTypeEC2
      3 -> pure CoseKeyTypeRSA
      value -> fail $ "Unknown COSE key type " <> show value

-- | [(spec)](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
-- All the entries from the [COSE Key Type Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
-- for key type 'CoseKeyTypeOKP' (aka @Key Type@ is @1@) that are required for
-- public keys
data CoseKeyTypeParameterOKP
  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)
    --
    -- * COSE value type: int / tstr
    -- * Value registry: 'CoseEllipticCurveOKP'
    -- * Description: EC identifier
    --
    -- This contains an identifier of the curve to be used with the key.
    CoseKeyTypeParameterOKPCrv
  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.2)
    --
    -- * COSE value type: bstr
    -- * Description: Public Key
    --
    -- This contains the public key. The byte string contains the public key as defined by the algorithm.
    CoseKeyTypeParameterOKPX
  deriving (Eq, Show, Bounded, Enum)

-- | Serialises the parameters using the @Label@ column from the
-- [COSE Key Type Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
instance Serialise CoseKeyTypeParameterOKP where
  encode CoseKeyTypeParameterOKPCrv = encodeInt (-1)
  encode CoseKeyTypeParameterOKPX = encodeInt (-2)
  decode =
    decodeIntCanonical >>= \case
      -1 -> pure CoseKeyTypeParameterOKPCrv
      -2 -> pure CoseKeyTypeParameterOKPX
      value -> fail $ "Unknown COSE key type parameter " <> show value <> " for key type OKP"

-- | Elliptic curves for key type 'CoseKeyTypeOKP' from the
-- [COSE Elliptic Curves registry](https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves),
-- limited to the ones that are currently needed for Webauthn
data CoseEllipticCurveOKP
  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)
    -- Ed25519 for use w/ EdDSA only
    CoseEllipticCurveEd25519
  deriving (Eq, Show)

-- | Serialises COSE Elliptic Curves using the @Value@ column from the
-- [COSE Elliptic Curves registry](https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves).
instance Serialise CoseEllipticCurveOKP where
  encode CoseEllipticCurveEd25519 = encodeInt 6
  decode =
    decodeIntCanonical >>= \case
      6 -> pure CoseEllipticCurveEd25519
      value -> fail $ "Unknown COSE elliptic curve " <> show value <> " for key type OKP"

-- | [(spec)](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
-- All the entries from the [COSE Key Type Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
-- for key type 'CoseKeyTypeEC2' (aka @Key Type@ is @2@) that are required for
-- public keys
data CoseKeyTypeParameterEC2
  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)
    --
    -- * COSE value type: int / tstr
    -- * Value registry: 'CoseEllipticCurveEC2'
    -- * Description: EC identifier
    --
    -- This contains an identifier of the curve to be used with the key.
    CoseKeyTypeParameterEC2Crv
  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)
    --
    -- * COSE value type: bstr
    -- * Description: x-coordinate
    --
    -- 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.
    CoseKeyTypeParameterEC2X
  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1.1)
    --
    -- * COSE value type: bstr / bool
    -- * Description: y-coordinate
    --
    -- This contains either the sign bit or 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. The compressed point encoding is also supported.
    -- Compute the sign bit as laid out in the Elliptic-Curve-Point-to-
    -- Octet-String Conversion function of
    -- [SEC1](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#ref-SEC1).
    -- If the sign bit is zero, then encode y as a CBOR false value;
    -- otherwise, encode y as a CBOR true value.
    -- The encoding of the infinity point is not supported.
    CoseKeyTypeParameterEC2Y
  deriving (Eq, Show, Bounded, Enum)

-- | Serialises the parameters using the @Label@ column from the
-- [COSE Key Type Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
instance Serialise CoseKeyTypeParameterEC2 where
  encode CoseKeyTypeParameterEC2Crv = encodeInt (-1)
  encode CoseKeyTypeParameterEC2X = encodeInt (-2)
  encode CoseKeyTypeParameterEC2Y = encodeInt (-3)
  decode =
    decodeIntCanonical >>= \case
      -1 -> pure CoseKeyTypeParameterEC2Crv
      -2 -> pure CoseKeyTypeParameterEC2X
      -3 -> pure CoseKeyTypeParameterEC2Y
      value -> fail $ "Unknown COSE key type parameter " <> show value <> " for key type EC2"

-- | Elliptic curves for key type 'CoseKeyTypeEC2' from the
-- [COSE Elliptic Curves registry](https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves),
-- limited to the ones that are currently needed for Webauthn
data CoseEllipticCurveEC2
  = -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)
    -- NIST P-256 also known as secp256r1
    CoseEllipticCurveEC2P256
  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)
    -- NIST P-384 also known as secp384r1
    CoseEllipticCurveEC2P384
  | -- | [(spec)](https://datatracker.ietf.org/doc/html/draft-ietf-cose-rfc8152bis-algs-12#section-7.1)
    -- NIST P-521 also known as secp521r1
    CoseEllipticCurveEC2P521
  deriving (Eq, Show)

-- | Serialises COSE Elliptic Curves using the @Value@ column from the
-- [COSE Elliptic Curves registry](https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves).
instance Serialise CoseEllipticCurveEC2 where
  encode CoseEllipticCurveEC2P256 = encodeInt 1
  encode CoseEllipticCurveEC2P384 = encodeInt 2
  encode CoseEllipticCurveEC2P521 = encodeInt 3
  decode =
    decodeIntCanonical >>= \case
      1 -> pure CoseEllipticCurveEC2P256
      2 -> pure CoseEllipticCurveEC2P384
      3 -> pure CoseEllipticCurveEC2P521
      value -> fail $ "Unknown COSE elliptic curve " <> show value <> " for key type EC2"

-- | [(spec)](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
-- All the entries from the [COSE Key Type Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
-- for key type 'CoseKeyTypeRSA' (aka @Key Type@ is @3@) that are required for
-- public keys
data CoseKeyTypeParameterRSA
  = -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)
    --
    -- * COSE value type: bstr
    -- * Description: the RSA modulus n
    --
    -- The RSA modulus n is a product of u distinct odd primes
    -- r_i, i = 1, 2, ..., u, where u >= 2
    --
    -- All numeric key parameters are encoded in an unsigned big-endian
    -- representation as an octet sequence using the CBOR byte string
    -- type (major type 2). The octet sequence MUST utilize the minimum
    -- number of octets needed to represent the value. For instance, the
    -- value 32,768 is represented as the CBOR byte sequence 0b010_00010,
    -- 0x80 0x00 (major type 2, additional information 2 for the length).
    CoseKeyTypeParameterRSAN
  | -- | [(spec)](https://www.rfc-editor.org/rfc/rfc8230.html#section-4)
    --
    -- * COSE value type: bstr
    -- * Description: the RSA public exponent e
    --
    -- 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)
    --
    -- All numeric key parameters are encoded in an unsigned big-endian
    -- representation as an octet sequence using the CBOR byte string
    -- type (major type 2). The octet sequence MUST utilize the minimum
    -- number of octets needed to represent the value. For instance, the
    -- value 32,768 is represented as the CBOR byte sequence 0b010_00010,
    -- 0x80 0x00 (major type 2, additional information 2 for the length).
    CoseKeyTypeParameterRSAE
  deriving (Eq, Show, Bounded, Enum)

-- | Serialises the parameters using the @Label@ column from the
-- [COSE Key Type Parameters registry](https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters)
instance Serialise CoseKeyTypeParameterRSA where
  encode CoseKeyTypeParameterRSAN = encodeInt (-1)
  encode CoseKeyTypeParameterRSAE = encodeInt (-2)
  decode =
    decodeIntCanonical >>= \case
      -1 -> pure CoseKeyTypeParameterRSAN
      -2 -> pure CoseKeyTypeParameterRSAE
      value -> fail $ "Unknown COSE key type parameter " <> show value <> " for key type RSA"

-- | The number of parameters for a 'CoseKeyType' relevant for Webauthn public
-- keys
parameterCount :: CoseKeyType -> Word
parameterCount CoseKeyTypeOKP = cardinality @CoseKeyCommonParameter + cardinality @CoseKeyTypeParameterOKP
parameterCount CoseKeyTypeEC2 = cardinality @CoseKeyCommonParameter + cardinality @CoseKeyTypeParameterEC2
parameterCount CoseKeyTypeRSA = cardinality @CoseKeyCommonParameter + cardinality @CoseKeyTypeParameterRSA

-- | A utility function for getting the number of constructors for a type
-- that implements both 'Bounded' and 'Enum'
cardinality :: forall a b. (Bounded a, Enum a, Num b) => b
cardinality = fromIntegral $ 1 + fromEnum @a maxBound - fromEnum @a minBound