-- |
-- Module      : Data.X509.AlgorithmIdentifier
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
--
module Data.X509.AlgorithmIdentifier
    ( HashALG(..)
    , PubKeyALG(..)
    , SignatureALG(..)
    ) where

import Data.ASN1.Types
import Data.List (find)

-- | Hash Algorithm
data HashALG =
      HashMD2
    | HashMD5
    | HashSHA1
    | HashSHA224
    | HashSHA256
    | HashSHA384
    | HashSHA512
    deriving (Int -> HashALG -> ShowS
[HashALG] -> ShowS
HashALG -> String
(Int -> HashALG -> ShowS)
-> (HashALG -> String) -> ([HashALG] -> ShowS) -> Show HashALG
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [HashALG] -> ShowS
$cshowList :: [HashALG] -> ShowS
show :: HashALG -> String
$cshow :: HashALG -> String
showsPrec :: Int -> HashALG -> ShowS
$cshowsPrec :: Int -> HashALG -> ShowS
Show,HashALG -> HashALG -> Bool
(HashALG -> HashALG -> Bool)
-> (HashALG -> HashALG -> Bool) -> Eq HashALG
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HashALG -> HashALG -> Bool
$c/= :: HashALG -> HashALG -> Bool
== :: HashALG -> HashALG -> Bool
$c== :: HashALG -> HashALG -> Bool
Eq)

-- | Public Key Algorithm
data PubKeyALG =
      PubKeyALG_RSA         -- ^ RSA Public Key algorithm
    | PubKeyALG_RSAPSS      -- ^ RSA PSS Key algorithm (RFC 3447)
    | PubKeyALG_DSA         -- ^ DSA Public Key algorithm
    | PubKeyALG_EC          -- ^ ECDSA & ECDH Public Key algorithm
    | PubKeyALG_X25519      -- ^ ECDH 25519 key agreement
    | PubKeyALG_X448        -- ^ ECDH 448 key agreement
    | PubKeyALG_Ed25519     -- ^ EdDSA 25519 signature algorithm
    | PubKeyALG_Ed448       -- ^ EdDSA 448 signature algorithm
    | PubKeyALG_DH          -- ^ Diffie Hellman Public Key algorithm
    | PubKeyALG_Unknown OID -- ^ Unknown Public Key algorithm
    deriving (Int -> PubKeyALG -> ShowS
[PubKeyALG] -> ShowS
PubKeyALG -> String
(Int -> PubKeyALG -> ShowS)
-> (PubKeyALG -> String)
-> ([PubKeyALG] -> ShowS)
-> Show PubKeyALG
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PubKeyALG] -> ShowS
$cshowList :: [PubKeyALG] -> ShowS
show :: PubKeyALG -> String
$cshow :: PubKeyALG -> String
showsPrec :: Int -> PubKeyALG -> ShowS
$cshowsPrec :: Int -> PubKeyALG -> ShowS
Show,PubKeyALG -> PubKeyALG -> Bool
(PubKeyALG -> PubKeyALG -> Bool)
-> (PubKeyALG -> PubKeyALG -> Bool) -> Eq PubKeyALG
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PubKeyALG -> PubKeyALG -> Bool
$c/= :: PubKeyALG -> PubKeyALG -> Bool
== :: PubKeyALG -> PubKeyALG -> Bool
$c== :: PubKeyALG -> PubKeyALG -> Bool
Eq)

-- | Signature Algorithm, often composed of a public key algorithm and a hash
-- algorithm.  For some signature algorithms the hash algorithm is intrinsic to
-- the public key algorithm and is not needed in the data type.
data SignatureALG =
      SignatureALG HashALG PubKeyALG
    | SignatureALG_IntrinsicHash PubKeyALG
    | SignatureALG_Unknown OID
    deriving (Int -> SignatureALG -> ShowS
[SignatureALG] -> ShowS
SignatureALG -> String
(Int -> SignatureALG -> ShowS)
-> (SignatureALG -> String)
-> ([SignatureALG] -> ShowS)
-> Show SignatureALG
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SignatureALG] -> ShowS
$cshowList :: [SignatureALG] -> ShowS
show :: SignatureALG -> String
$cshow :: SignatureALG -> String
showsPrec :: Int -> SignatureALG -> ShowS
$cshowsPrec :: Int -> SignatureALG -> ShowS
Show,SignatureALG -> SignatureALG -> Bool
(SignatureALG -> SignatureALG -> Bool)
-> (SignatureALG -> SignatureALG -> Bool) -> Eq SignatureALG
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SignatureALG -> SignatureALG -> Bool
$c/= :: SignatureALG -> SignatureALG -> Bool
== :: SignatureALG -> SignatureALG -> Bool
$c== :: SignatureALG -> SignatureALG -> Bool
Eq)

instance OIDable PubKeyALG where
    getObjectID :: PubKeyALG -> OID
getObjectID PubKeyALG_RSA    = [1,2,840,113549,1,1,1]
    getObjectID PubKeyALG_RSAPSS = [1,2,840,113549,1,1,10]
    getObjectID PubKeyALG_DSA    = [1,2,840,10040,4,1]
    getObjectID PubKeyALG_EC     = [1,2,840,10045,2,1]
    getObjectID PubKeyALG_X25519    = [1,3,101,110]
    getObjectID PubKeyALG_X448      = [1,3,101,111]
    getObjectID PubKeyALG_Ed25519   = [1,3,101,112]
    getObjectID PubKeyALG_Ed448     = [1,3,101,113]
    getObjectID PubKeyALG_DH     = [1,2,840,10046,2,1]
    getObjectID (PubKeyALG_Unknown oid :: OID
oid) = OID
oid

sig_table :: [ (OID, SignatureALG) ]
sig_table :: [(OID, SignatureALG)]
sig_table =
        [ ([1,2,840,113549,1,1,5], HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA1 PubKeyALG
PubKeyALG_RSA)
        , ([1,2,840,113549,1,1,4], HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashMD5 PubKeyALG
PubKeyALG_RSA)
        , ([1,2,840,113549,1,1,2], HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashMD2 PubKeyALG
PubKeyALG_RSA)
        , ([1,2,840,113549,1,1,11], HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA256 PubKeyALG
PubKeyALG_RSA)
        , ([1,2,840,113549,1,1,12], HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA384 PubKeyALG
PubKeyALG_RSA)
        , ([1,2,840,113549,1,1,13], HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA512 PubKeyALG
PubKeyALG_RSA)
        , ([1,2,840,113549,1,1,14], HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA224 PubKeyALG
PubKeyALG_RSA)
        , ([1,2,840,10040,4,3],    HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA1 PubKeyALG
PubKeyALG_DSA)
        , ([1,2,840,10045,4,1],    HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA1 PubKeyALG
PubKeyALG_EC)
        , ([1,2,840,10045,4,3,1],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA224 PubKeyALG
PubKeyALG_EC)
        , ([1,2,840,10045,4,3,2],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA256 PubKeyALG
PubKeyALG_EC)
        , ([1,2,840,10045,4,3,3],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA384 PubKeyALG
PubKeyALG_EC)
        , ([1,2,840,10045,4,3,4],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA512 PubKeyALG
PubKeyALG_EC)
        , ([2,16,840,1,101,3,4,2,1],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA256 PubKeyALG
PubKeyALG_RSAPSS)
        , ([2,16,840,1,101,3,4,2,2],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA384 PubKeyALG
PubKeyALG_RSAPSS)
        , ([2,16,840,1,101,3,4,2,3],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA512 PubKeyALG
PubKeyALG_RSAPSS)
        , ([2,16,840,1,101,3,4,2,4],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA224 PubKeyALG
PubKeyALG_RSAPSS)
        , ([2,16,840,1,101,3,4,3,1],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA224 PubKeyALG
PubKeyALG_DSA)
        , ([2,16,840,1,101,3,4,3,2],  HashALG -> PubKeyALG -> SignatureALG
SignatureALG HashALG
HashSHA256 PubKeyALG
PubKeyALG_DSA)
        , ([1,3,101,112], PubKeyALG -> SignatureALG
SignatureALG_IntrinsicHash PubKeyALG
PubKeyALG_Ed25519)
        , ([1,3,101,113], PubKeyALG -> SignatureALG
SignatureALG_IntrinsicHash PubKeyALG
PubKeyALG_Ed448)
        ]

oidSig :: OID -> SignatureALG
oidSig :: OID -> SignatureALG
oidSig oid :: OID
oid = SignatureALG
-> (SignatureALG -> SignatureALG)
-> Maybe SignatureALG
-> SignatureALG
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (OID -> SignatureALG
SignatureALG_Unknown OID
oid) SignatureALG -> SignatureALG
forall a. a -> a
id (Maybe SignatureALG -> SignatureALG)
-> Maybe SignatureALG -> SignatureALG
forall a b. (a -> b) -> a -> b
$ OID -> [(OID, SignatureALG)] -> Maybe SignatureALG
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup OID
oid [(OID, SignatureALG)]
sig_table

sigOID :: SignatureALG -> OID
sigOID :: SignatureALG -> OID
sigOID (SignatureALG_Unknown oid :: OID
oid) = OID
oid
sigOID sig :: SignatureALG
sig = OID
-> ((OID, SignatureALG) -> OID) -> Maybe (OID, SignatureALG) -> OID
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> OID
forall a. HasCallStack => String -> a
error ("unknown OID for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ SignatureALG -> String
forall a. Show a => a -> String
show SignatureALG
sig)) (OID, SignatureALG) -> OID
forall a b. (a, b) -> a
fst (Maybe (OID, SignatureALG) -> OID)
-> Maybe (OID, SignatureALG) -> OID
forall a b. (a -> b) -> a -> b
$ ((OID, SignatureALG) -> Bool)
-> [(OID, SignatureALG)] -> Maybe (OID, SignatureALG)
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (SignatureALG -> SignatureALG -> Bool
forall a. Eq a => a -> a -> Bool
(==) SignatureALG
sig (SignatureALG -> Bool)
-> ((OID, SignatureALG) -> SignatureALG)
-> (OID, SignatureALG)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (OID, SignatureALG) -> SignatureALG
forall a b. (a, b) -> b
snd) [(OID, SignatureALG)]
sig_table

-- | PSS salt length. Always assume ``-sigopt rsa_pss_saltlen:-1``
saltLen :: HashALG -> Integer
saltLen :: HashALG -> Integer
saltLen HashSHA256 = 32
saltLen HashSHA384 = 48
saltLen HashSHA512 = 64
saltLen HashSHA224 = 28
saltLen _          = String -> Integer
forall a. HasCallStack => String -> a
error "toASN1: X509.SignatureAlg.HashAlg: Unknown hash"

instance ASN1Object SignatureALG where
    fromASN1 :: [ASN1] -> Either String (SignatureALG, [ASN1])
fromASN1 (Start Sequence:OID oid :: OID
oid:Null:End Sequence:xs :: [ASN1]
xs) =
        case OID -> SignatureALG
oidSig OID
oid of
            SignatureALG_IntrinsicHash _ ->
                String -> Either String (SignatureALG, [ASN1])
forall a b. a -> Either a b
Left "fromASN1: X509.SignatureALG: EdDSA requires absent parameter"
            signatureAlg :: SignatureALG
signatureAlg -> (SignatureALG, [ASN1]) -> Either String (SignatureALG, [ASN1])
forall a b. b -> Either a b
Right (SignatureALG
signatureAlg, [ASN1]
xs)
    fromASN1 (Start Sequence:OID oid :: OID
oid:End Sequence:xs :: [ASN1]
xs) =
        (SignatureALG, [ASN1]) -> Either String (SignatureALG, [ASN1])
forall a b. b -> Either a b
Right (OID -> SignatureALG
oidSig OID
oid, [ASN1]
xs)
    fromASN1 (Start Sequence:OID [1,2,840,113549,1,1,10]:Start Sequence:Start _:Start Sequence:OID hash1 :: OID
hash1:End Sequence:End _:Start _:Start Sequence:OID [1,2,840,113549,1,1,8]:Start Sequence:OID _hash2 :: OID
_hash2:End Sequence:End Sequence:End _:Start _: IntVal _iv :: Integer
_iv: End _: End Sequence : End Sequence:xs :: [ASN1]
xs) =
        (SignatureALG, [ASN1]) -> Either String (SignatureALG, [ASN1])
forall a b. b -> Either a b
Right (OID -> SignatureALG
oidSig OID
hash1, [ASN1]
xs)
    fromASN1 (Start Sequence:OID [1,2,840,113549,1,1,10]:Start Sequence:Start _:Start Sequence:OID hash1 :: OID
hash1:Null:End Sequence:End _:Start _:Start Sequence:OID [1,2,840,113549,1,1,8]:Start Sequence:OID _hash2 :: OID
_hash2:Null:End Sequence:End Sequence:End _:Start _: IntVal _iv :: Integer
_iv: End _: End Sequence : End Sequence:xs :: [ASN1]
xs) =
        (SignatureALG, [ASN1]) -> Either String (SignatureALG, [ASN1])
forall a b. b -> Either a b
Right (OID -> SignatureALG
oidSig OID
hash1, [ASN1]
xs)
    fromASN1 _ =
        String -> Either String (SignatureALG, [ASN1])
forall a b. a -> Either a b
Left "fromASN1: X509.SignatureALG: unknown format"
    toASN1 :: SignatureALG -> ASN1S
toASN1 (SignatureALG_Unknown oid :: OID
oid) = \xs :: [ASN1]
xs -> ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:OID -> ASN1
OID OID
oidASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1
NullASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:[ASN1]
xs
    toASN1 signatureAlg :: SignatureALG
signatureAlg@(SignatureALG hashAlg :: HashALG
hashAlg PubKeyALG_RSAPSS) = \xs :: [ASN1]
xs -> ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:OID -> ASN1
OID [1,2,840,113549,1,1,10]ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
Start (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context 0)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:OID -> ASN1
OID (SignatureALG -> OID
sigOID SignatureALG
signatureAlg)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context 0)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
Start (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context 1)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
: ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:OID -> ASN1
OID [1,2,840,113549,1,1,8]ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:OID -> ASN1
OID (SignatureALG -> OID
sigOID SignatureALG
signatureAlg)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context 1)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
Start (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context 2)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:Integer -> ASN1
IntVal (HashALG -> Integer
saltLen HashALG
hashAlg)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context 2)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:[ASN1]
xs
    toASN1 signatureAlg :: SignatureALG
signatureAlg@(SignatureALG_IntrinsicHash _) = \xs :: [ASN1]
xs -> ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:OID -> ASN1
OID (SignatureALG -> OID
sigOID SignatureALG
signatureAlg)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:[ASN1]
xs
    toASN1 signatureAlg :: SignatureALG
signatureAlg = \xs :: [ASN1]
xs -> ASN1ConstructionType -> ASN1
Start ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:OID -> ASN1
OID (SignatureALG -> OID
sigOID SignatureALG
signatureAlg)ASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1
NullASN1 -> ASN1S
forall a. a -> [a] -> [a]
:ASN1ConstructionType -> ASN1
End ASN1ConstructionType
SequenceASN1 -> ASN1S
forall a. a -> [a] -> [a]
:[ASN1]
xs