{-

This module is based on a part of snaplet-saml. If my hs-certificate PR gets merged, then we probably ought to remove this and use hs-certificate instead.

https://github.com/duairc/snaplet-saml/blob/dd89116f8f0b3d755d2feea73f2c40beb78c409c/src/Data/X509/IO.hs#L87-L102

https://github.com/vincenthz/hs-certificate/pull/98

-}

module Network.AWS.CloudFront.SignedCookies.Crypto.Internal
  ( rsaPrivateKeyFromASN1
  ) where

import Data.ASN1.Types (ASN1 (End, IntVal, Start), ASN1ConstructionType (Sequence))

import qualified Crypto.PubKey.RSA as RSA

rsaPrivateKeyFromASN1 :: [ASN1] -> Either String RSA.PrivateKey

rsaPrivateKeyFromASN1 :: [ASN1] -> Either String PrivateKey
rsaPrivateKeyFromASN1 =
  \case
    ( Start ASN1ConstructionType
Sequence
        : IntVal Integer
version
        : IntVal Integer
n
        : IntVal Integer
e
        : IntVal Integer
d
        : IntVal Integer
p
        : IntVal Integer
q
        : IntVal Integer
dP
        : IntVal Integer
dQ
        : IntVal Integer
qinv
        : End ASN1ConstructionType
Sequence
        : [] ) ->

      case Integer
version of
        Integer
0 -> PrivateKey -> Either String PrivateKey
forall a b. b -> Either a b
Right (Params -> PrivateKey
buildKey Params{Integer
n :: Integer
e :: Integer
d :: Integer
p :: Integer
q :: Integer
dP :: Integer
dQ :: Integer
qinv :: Integer
n :: Integer
e :: Integer
d :: Integer
p :: Integer
q :: Integer
dP :: Integer
dQ :: Integer
qinv :: Integer
..})
        Integer
_ -> String -> Either String PrivateKey
forall a b. a -> Either a b
Left (String -> Either String PrivateKey)
-> String -> Either String PrivateKey
forall a b. (a -> b) -> a -> b
$ String
"rsaPrivateKeyFromASN1: unexpected version " String -> String -> String
forall a. Semigroup a => a -> a -> a
<>
                    forall a. Show a => a -> String
show @Integer Integer
version

    [ASN1]
_ -> String -> Either String PrivateKey
forall a b. a -> Either a b
Left String
"rsaPrivateKeyFromASN1: unexpected format"

-- https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem
data Params =
  Params
    { Params -> Integer
n    :: Integer -- modulus
    , Params -> Integer
e    :: Integer -- publicExponent
    , Params -> Integer
d    :: Integer -- privateExponent
    , Params -> Integer
p    :: Integer -- prime1
    , Params -> Integer
q    :: Integer -- prime2
    , Params -> Integer
dP   :: Integer -- exponent1 = d mod (p-1)
    , Params -> Integer
dQ   :: Integer -- exponent2 = d mod (q-1)
    , Params -> Integer
qinv :: Integer -- coefficient = (inverse of q) mod p
    }

buildKey :: Params -> RSA.PrivateKey
buildKey :: Params -> PrivateKey
buildKey Params{Integer
n :: Params -> Integer
e :: Params -> Integer
d :: Params -> Integer
p :: Params -> Integer
q :: Params -> Integer
dP :: Params -> Integer
dQ :: Params -> Integer
qinv :: Params -> Integer
n :: Integer
e :: Integer
d :: Integer
p :: Integer
q :: Integer
dP :: Integer
dQ :: Integer
qinv :: Integer
..} =
  let
    size :: Int
size = [Int] -> Int
forall a. HasCallStack => [a] -> a
head [Int
i | Int
i <- [Int
1..], Integer
2 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8) Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
n]

    pub :: PublicKey
pub = RSA.PublicKey
      { public_size :: Int
public_size = Int
size
      , public_n :: Integer
public_n = Integer
n
      , public_e :: Integer
public_e = Integer
e
      }

  in
    RSA.PrivateKey
      { private_pub :: PublicKey
RSA.private_pub  = PublicKey
pub
      , private_d :: Integer
RSA.private_d    = Integer
d
      , private_p :: Integer
RSA.private_p    = Integer
p
      , private_q :: Integer
RSA.private_q    = Integer
q
      , private_dP :: Integer
RSA.private_dP   = Integer
dP
      , private_dQ :: Integer
RSA.private_dQ   = Integer
dQ
      , private_qinv :: Integer
RSA.private_qinv = Integer
qinv
      }