aws-cloudfront-signed-cookies-0.1.0.0: library/Network/AWS/CloudFront/SignedCookies/Crypto.hs
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
module Network.AWS.CloudFront.SignedCookies.Crypto
(
-- * Reading the private key
readPrivateKeyPemFile
-- * Generating signatures
, sign
-- * Types
, PrivateKey
, ByteString
) where
import Network.AWS.CloudFront.SignedCookies.Crypto.Internal
import Network.AWS.CloudFront.SignedCookies.Types
-- asn1-encoding
import Data.ASN1.BinaryEncoding (DER (DER))
import Data.ASN1.Encoding (decodeASN1')
import Data.ASN1.Error (ASN1Error)
-- asn1-types
import Data.ASN1.Types (ASN1)
-- bytestring
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
-- cryptonite
import Crypto.PubKey.RSA (PrivateKey)
import qualified Crypto.PubKey.RSA.PKCS15 as RSA
import Crypto.Hash.Algorithms (SHA1 (SHA1))
-- pem
import qualified Data.PEM as PEM
-- text
import qualified Data.Text as Text
-- | Construct the signature that will go into the
-- @CloudFront-Signature@ cookie.
sign
:: PrivateKey -- ^ The RSA private key that you read from the @.pem@ file
-> ByteString -- ^ The JSON representation of the 'Policy'
-- (see "Network.AWS.CloudFront.SignedCookies.Policy")
-> IO ByteString
sign key bs =
RSA.signSafer (Just SHA1) key bs >>= either (fail . show) pure
-- | Read an RSA private key from a @.pem@ file you downloaded from AWS.
readPrivateKeyPemFile
:: PemFilePath -- ^ The filesystem path of the @.pem@ file
-> IO PrivateKey
readPrivateKeyPemFile (PemFilePath path) = do
lbs <- BS.readFile (Text.unpack path)
pemSections <- either fail pure (PEM.pemParseBS lbs)
pemBs <- PEM.pemContent <$> case pemSections of
[x] -> pure x
xs ->
let msg = "Expected exactly 1 PEM section but found " ++
show @Int (length xs)
in fail msg
asn1s :: [ASN1] <- either (fail . show) pure (decodeASN1' DER pemBs)
either fail pure (rsaPrivateKeyFromASN1 asn1s)