x509-store-1.6.5/Data/0000755000000000000000000000000013124231131012410 5ustar0000000000000000x509-store-1.6.5/Data/X509/0000755000000000000000000000000013137710124013065 5ustar0000000000000000x509-store-1.6.5/Tests/0000755000000000000000000000000013137710124012651 5ustar0000000000000000x509-store-1.6.5/Data/X509/CertificateStore.hs0000644000000000000000000001012713124231131016651 0ustar0000000000000000module Data.X509.CertificateStore ( CertificateStore , makeCertificateStore , readCertificateStore -- * Queries , findCertificate , listCertificates ) where import Data.Char (isDigit, isHexDigit) import Data.Either (rights) import Data.List (foldl', isPrefixOf) import Data.Monoid import Data.PEM (pemParseBS, pemContent) import Data.X509 import qualified Data.Map as M import Control.Applicative ((<$>)) import Control.Monad (mplus, filterM) import System.Directory (getDirectoryContents, doesFileExist, doesDirectoryExist) import System.FilePath (()) import qualified Control.Exception as E import qualified Data.ByteString as B -- | A Collection of certificate or store of certificates. data CertificateStore = CertificateStore (M.Map DistinguishedName SignedCertificate) | CertificateStores [CertificateStore] instance Monoid CertificateStore where mempty = CertificateStore M.empty mappend s1@(CertificateStore _) s2@(CertificateStore _) = CertificateStores [s1,s2] mappend (CertificateStores l) s2@(CertificateStore _) = CertificateStores (l ++ [s2]) mappend s1@(CertificateStore _) (CertificateStores l) = CertificateStores ([s1] ++ l) mappend (CertificateStores l1) (CertificateStores l2) = CertificateStores (l1 ++ l2) -- | Create a certificate store out of a list of X509 certificate makeCertificateStore :: [SignedCertificate] -> CertificateStore makeCertificateStore = CertificateStore . foldl' accumulate M.empty where accumulate m x509 = M.insert (certSubjectDN $ getCertificate x509) x509 m -- | Find a certificate using the subject distinguished name findCertificate :: DistinguishedName -> CertificateStore -> Maybe SignedCertificate findCertificate dn store = lookupIn store where lookupIn (CertificateStore m) = M.lookup dn m lookupIn (CertificateStores l) = foldl mplus Nothing $ map lookupIn l -- | List all certificates in a store listCertificates :: CertificateStore -> [SignedCertificate] listCertificates (CertificateStore store) = map snd $ M.toList store listCertificates (CertificateStores l) = concatMap listCertificates l -- | Create certificate store by reading certificates from file or directory -- -- This function can be used to read multiple certificates from either -- single file (multiple PEM formatted certificates concanated) or -- directory (one certificate per file, file names are hashes from -- certificate). readCertificateStore :: FilePath -> IO (Maybe CertificateStore) readCertificateStore path = do isDir <- doesDirectoryExist path isFile <- doesFileExist path wrapStore <$> (if isDir then makeDirStore else if isFile then makeFileStore else return []) where wrapStore :: [SignedCertificate] -> Maybe CertificateStore wrapStore [] = Nothing wrapStore l = Just $ makeCertificateStore l makeFileStore = readCertificates path makeDirStore = do certFiles <- listDirectoryCerts path concat <$> mapM readCertificates certFiles -- Try to read certificate from the content of a file. -- -- The file may contains multiple certificates readCertificates :: FilePath -> IO [SignedCertificate] readCertificates file = E.catch (either (const []) (rights . map getCert) . pemParseBS <$> B.readFile file) skipIOError where getCert = decodeSignedCertificate . pemContent skipIOError :: E.IOException -> IO [SignedCertificate] skipIOError _ = return [] -- List all the path susceptible to contains a certificate in a directory -- -- if the parameter is not a directory, hilarity follows. listDirectoryCerts :: FilePath -> IO [FilePath] listDirectoryCerts path = getDirContents >>= filterM doesFileExist where isHashedFile s = length s == 10 && isDigit (s !! 9) && (s !! 8) == '.' && all isHexDigit (take 8 s) isCert x = (not $ isPrefixOf "." x) && (not $ isHashedFile x) getDirContents = E.catch (map (path ) . filter isCert <$> getDirectoryContents path) emptyPaths where emptyPaths :: E.IOException -> IO [FilePath] emptyPaths _ = return [] x509-store-1.6.5/Data/X509/File.hs0000644000000000000000000000210113137710124014272 0ustar0000000000000000module Data.X509.File ( readSignedObject , readKeyFile ) where import Control.Applicative import Data.ASN1.Types import Data.ASN1.BinaryEncoding import Data.ASN1.Encoding import Data.Maybe import qualified Data.X509 as X509 import Data.X509.Memory (pemToKey) import Data.PEM (pemParseLBS, pemContent, pemName, PEM) import qualified Data.ByteString.Lazy as L readPEMs :: FilePath -> IO [PEM] readPEMs filepath = do content <- L.readFile filepath return $ either error id $ pemParseLBS content -- | return all the signed objects in a file. -- -- (only one type at a time). readSignedObject :: (ASN1Object a, Eq a, Show a) => FilePath -> IO [X509.SignedExact a] readSignedObject filepath = decodePEMs <$> readPEMs filepath where decodePEMs pems = [ obj | pem <- pems, Right obj <- [X509.decodeSignedObject $ pemContent pem] ] -- | return all the private keys that were successfully read from a file. readKeyFile :: FilePath -> IO [X509.PrivKey] readKeyFile path = catMaybes . foldl pemToKey [] <$> readPEMs path x509-store-1.6.5/Data/X509/Memory.hs0000644000000000000000000002051413137710124014673 0ustar0000000000000000-- | -- Module : Data.X509.Memory -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unknown -- -- module Data.X509.Memory ( readKeyFileFromMemory , readSignedObjectFromMemory , pemToKey ) where import Data.ASN1.Types import Data.ASN1.BinaryEncoding import Data.ASN1.BitArray import Data.ASN1.Encoding import Data.ASN1.Stream import Data.Maybe import qualified Data.X509 as X509 import Data.X509.EC as X509 import Data.PEM (pemParseBS, pemContent, pemName, PEM) import qualified Data.ByteString as B import Crypto.Number.Serialize (os2ip) import qualified Crypto.PubKey.DSA as DSA import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import qualified Crypto.PubKey.RSA as RSA readKeyFileFromMemory :: B.ByteString -> [X509.PrivKey] readKeyFileFromMemory = either (const []) (catMaybes . foldl pemToKey []) . pemParseBS readSignedObjectFromMemory :: (ASN1Object a, Eq a, Show a) => B.ByteString -> [X509.SignedExact a] readSignedObjectFromMemory = either (const []) (foldl pemToSigned []) . pemParseBS where pemToSigned acc pem = case X509.decodeSignedObject $ pemContent pem of Left _ -> acc Right obj -> obj : acc pemToKey :: [Maybe X509.PrivKey] -> PEM -> [Maybe X509.PrivKey] pemToKey acc pem = case decodeASN1' BER (pemContent pem) of Left _ -> acc Right asn1 -> case pemName pem of "PRIVATE KEY" -> tryRSA asn1 : tryECDSA asn1 : tryDSA asn1 : acc "RSA PRIVATE KEY" -> tryRSA asn1 : acc "DSA PRIVATE KEY" -> tryDSA asn1 : acc "EC PRIVATE KEY" -> tryECDSA asn1 : acc _ -> acc where tryRSA asn1 = case rsaFromASN1 asn1 of Left _ -> Nothing Right (k,_) -> Just $ X509.PrivKeyRSA k tryDSA asn1 = case dsaFromASN1 asn1 of Left _ -> Nothing Right (k,_) -> Just $ X509.PrivKeyDSA $ DSA.toPrivateKey k tryECDSA asn1 = case ecdsaFromASN1 [] asn1 of Left _ -> Nothing Right (k,_) -> Just $ X509.PrivKeyEC k dsaFromASN1 :: [ASN1] -> Either String (DSA.KeyPair, [ASN1]) dsaFromASN1 (Start Sequence : IntVal n : xs) | n /= 0 = Left "fromASN1: DSA.KeyPair: unknown format" | otherwise = case xs of IntVal p : IntVal q : IntVal g : IntVal pub : IntVal priv : End Sequence : xs2 -> let params = DSA.Params { DSA.params_p = p, DSA.params_g = g, DSA.params_q = q } in Right (DSA.KeyPair params pub priv, xs2) (Start Sequence : OID [1, 2, 840, 10040, 4, 1] : Start Sequence : IntVal p : IntVal q : IntVal g : End Sequence : End Sequence : OctetString bs : End Sequence : xs2) -> let params = DSA.Params { DSA.params_p = p, DSA.params_g = g, DSA.params_q = q } in case decodeASN1' BER bs of Right [IntVal priv] -> let pub = DSA.calculatePublic params priv in Right (DSA.KeyPair params pub priv, xs2) Right _ -> Left "dsaFromASN1: DSA.PrivateKey: unexpected format" Left e -> Left $ "dsaFromASN1: DSA.PrivateKey: " ++ show e _ -> Left "dsaFromASN1: DSA.KeyPair: invalid format (version=0)" dsaFromASN1 _ = Left "dsaFromASN1: DSA.KeyPair: unexpected format" ecdsaFromASN1 :: [ASN1] -> [ASN1] -> Either String (X509.PrivKeyEC, [ASN1]) ecdsaFromASN1 curveOid1 (Start Sequence : IntVal 1 : OctetString ds : xs) = do let (curveOid2, ys) = containerWithTag 0 xs privKey <- getPrivKeyEC (os2ip ds) (curveOid2 ++ curveOid1) case containerWithTag 1 ys of (_, End Sequence : zs) -> return (privKey, zs) _ -> Left "ecdsaFromASN1: unexpected EC format" ecdsaFromASN1 curveOid1 (Start Sequence : IntVal 0 : Start Sequence : OID [1, 2, 840, 10045, 2, 1] : xs) = let strError = Left . ("ecdsaFromASN1: ECDSA.PrivateKey: " ++) . show (curveOid2, ys) = getConstructedEnd 0 xs in case ys of (OctetString bs : zs) -> do let curveOids = curveOid2 ++ curveOid1 inner = either strError (ecdsaFromASN1 curveOids) (decodeASN1' BER bs) either Left (\(k, _) -> Right (k, zs)) inner _ -> Left "ecdsaFromASN1: unexpected format" ecdsaFromASN1 _ _ = Left "ecdsaFromASN1: unexpected format" getPrivKeyEC :: ECDSA.PrivateNumber -> [ASN1] -> Either String X509.PrivKeyEC getPrivKeyEC _ [] = Left "ecdsaFromASN1: curve is missing" getPrivKeyEC d (OID curveOid : _) = case X509.lookupCurveNameByOID curveOid of Just name -> Right X509.PrivKeyEC_Named { X509.privkeyEC_name = name , X509.privkeyEC_priv = d } Nothing -> Left ("ecdsaFromASN1: unknown curve " ++ show curveOid) getPrivKeyEC d (Null : xs) = getPrivKeyEC d xs getPrivKeyEC d (Start Sequence : IntVal 1 : Start Sequence : OID [1, 2, 840, 10045, 1, 1] : IntVal prime : End Sequence : Start Sequence : OctetString a : OctetString b : BitString seed : End Sequence : OctetString generator : IntVal order : IntVal cofactor : End Sequence : _) = Right X509.PrivKeyEC_Prime { X509.privkeyEC_priv = d , X509.privkeyEC_a = os2ip a , X509.privkeyEC_b = os2ip b , X509.privkeyEC_prime = prime , X509.privkeyEC_generator = X509.SerializedPoint generator , X509.privkeyEC_order = order , X509.privkeyEC_cofactor = cofactor , X509.privkeyEC_seed = os2ip $ bitArrayGetData seed } getPrivKeyEC _ _ = Left "ecdsaFromASN1: unexpected curve format" containerWithTag :: ASN1Tag -> [ASN1] -> ([ASN1], [ASN1]) containerWithTag etag (Start (Container _ atag) : xs) | etag == atag = getConstructedEnd 0 xs containerWithTag _ xs = ([], xs) rsaFromASN1 :: [ASN1] -> Either String (RSA.PrivateKey, [ASN1]) rsaFromASN1 (Start Sequence : IntVal 0 : IntVal n : IntVal e : IntVal d : IntVal p1 : IntVal p2 : IntVal pexp1 : IntVal pexp2 : IntVal pcoef : End Sequence : xs) = Right (privKey, xs) where calculate_modulus m i = if (2 ^ (i * 8)) > m then i else calculate_modulus m (i+1) pubKey = RSA.PublicKey { RSA.public_size = calculate_modulus n 1 , RSA.public_n = n , RSA.public_e = e } privKey = RSA.PrivateKey { RSA.private_pub = pubKey , RSA.private_d = d , RSA.private_p = p1 , RSA.private_q = p2 , RSA.private_dP = pexp1 , RSA.private_dQ = pexp2 , RSA.private_qinv = pcoef } rsaFromASN1 ( Start Sequence : IntVal 0 : Start Sequence : OID [1, 2, 840, 113549, 1, 1, 1] : Null : End Sequence : OctetString bs : xs) = let inner = either strError rsaFromASN1 $ decodeASN1' BER bs strError = Left . ("rsaFromASN1: RSA.PrivateKey: " ++) . show in either Left (\(k, _) -> Right (k, xs)) inner rsaFromASN1 _ = Left "rsaFromASN1: unexpected format" x509-store-1.6.5/Tests/Tests.hs0000644000000000000000000003101413137710124014306 0ustar0000000000000000-- | x509-store test suite. module Main (main) where import qualified Data.ByteString as B import Data.String (fromString) import Data.X509 import Data.X509.Memory import Test.Tasty import Test.Tasty.HUnit {- openssl req -new -x509 -subj /CN=Test -newkey rsa:1024 -nodes -reqexts v3_req \ | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' privkey.pem openssl rsa -in privkey.pem | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' -} rsaCertificate, rsaKey1, rsaKey2 :: B.ByteString rsaCertificate = fromString $ "-----BEGIN CERTIFICATE-----\n" ++ "MIIB7DCCAVWgAwIBAgIJAPmzhcKJcLZtMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV\n" ++ "BAMMBFRlc3QwHhcNMTcwMzAyMTgwODU3WhcNMTcwNDAxMTgwODU3WjAPMQ0wCwYD\n" ++ "VQQDDARUZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzkysIZyZ1UYFl\n" ++ "OFKOhZ+T7Usgove7Z9z9zBSXM7ufXl5NF5QV+u76bDo5ITD81NYiqCLoNGRVC1FY\n" ++ "srVmx97AyqQ6Hj2IGfar2JyymTO2Y4E7kYO21hxJSrIJOVnAbGdxHYwiKVFZkP5g\n" ++ "PS5FzYqwfMet4gpbPJcvBjfZVo2MIQIDAQABo1AwTjAdBgNVHQ4EFgQUhJgtg9dO\n" ++ "jcpA08w0BuXptQw+JVkwHwYDVR0jBBgwFoAUhJgtg9dOjcpA08w0BuXptQw+JVkw\n" ++ "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQA2OIHfXV9Ro7208mNaz6Bi\n" ++ "QYhW4gGbQA6/5N/BYby5kHLC+veJ9qAXjILn5qW5hsuf4X4Nq7VO3HKQ89Jo2COc\n" ++ "6fAvjhCWKqlZFAIBKbcEcg3QZqAdXJ4Q8RLMvG3y/vDzixp1Xuxk0Zbr88D7SX7i\n" ++ "Lx+S385X8OT7Wiu6qhM6ig==\n" ++ "-----END CERTIFICATE-----\n" rsaKey1 = fromString $ "-----BEGIN PRIVATE KEY-----\n" ++ "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALOTKwhnJnVRgWU4\n" ++ "Uo6Fn5PtSyCi97tn3P3MFJczu59eXk0XlBX67vpsOjkhMPzU1iKoIug0ZFULUViy\n" ++ "tWbH3sDKpDoePYgZ9qvYnLKZM7ZjgTuRg7bWHElKsgk5WcBsZ3EdjCIpUVmQ/mA9\n" ++ "LkXNirB8x63iCls8ly8GN9lWjYwhAgMBAAECgYAxGVkXyBRU2X82rMqt201Bhg0X\n" ++ "lFeF7yUWY7lxihyPu56vF3ZO+DhlUjgtLK0XRB50hWJd+Q1Bz4FjbiF5Q8bcm/rz\n" ++ "4BzyojpoCHoMnrcPyP+7+LE50MFsySvjQWCJkz0WSoFBsoEVQOvkAkhCEiR4vqoJ\n" ++ "UNjZczb2PAvWjlUsvQJBAOyLOm+P4RnrRaV/dMXx3pfNTolJp7KQ0zXghKc4clF5\n" ++ "ESMsWHwHRGU++/tW90m/j8ApDvlIrXTmYOyQ4jKCCk8CQQDCWGAzeVa4xL+p2SaO\n" ++ "TP5aqRjfEIVf0O3HjB9GklrdwtnDF4JrUUILdUKJ3qxqEetNpSZjzc3H6dDtxvy1\n" ++ "yRaPAkEAp+fMexRufK98qJVolnmxv5+Ed/9IgoA67KuKfgibXSnK+GSqCqA99IBY\n" ++ "7Xg14KuRpp1+e4UTWz+M3V+asK+OEQJBAKvQW8RGCqAw+M0c+FQnx1q5Ug6q2W77\n" ++ "E6wtudy3OPQC9mfemeNspDnjAd9HaCAiFWfAkK79XGbX1GjSWcoQrAsCQQDRoscG\n" ++ "Udtf0rxGk4y79YNXPeTReF+0wCdWdDNpAdnhpYCnFE+74LyiY8YRbfe2jP7X2uyn\n" ++ "/h1HwfRSKCZ7Epcv\n" ++ "-----END PRIVATE KEY-----\n" rsaKey2 = fromString $ "-----BEGIN RSA PRIVATE KEY-----\n" ++ "MIICXgIBAAKBgQCzkysIZyZ1UYFlOFKOhZ+T7Usgove7Z9z9zBSXM7ufXl5NF5QV\n" ++ "+u76bDo5ITD81NYiqCLoNGRVC1FYsrVmx97AyqQ6Hj2IGfar2JyymTO2Y4E7kYO2\n" ++ "1hxJSrIJOVnAbGdxHYwiKVFZkP5gPS5FzYqwfMet4gpbPJcvBjfZVo2MIQIDAQAB\n" ++ "AoGAMRlZF8gUVNl/NqzKrdtNQYYNF5RXhe8lFmO5cYocj7uerxd2Tvg4ZVI4LSyt\n" ++ "F0QedIViXfkNQc+BY24heUPG3Jv68+Ac8qI6aAh6DJ63D8j/u/ixOdDBbMkr40Fg\n" ++ "iZM9FkqBQbKBFUDr5AJIQhIkeL6qCVDY2XM29jwL1o5VLL0CQQDsizpvj+EZ60Wl\n" ++ "f3TF8d6XzU6JSaeykNM14ISnOHJReREjLFh8B0RlPvv7VvdJv4/AKQ75SK105mDs\n" ++ "kOIyggpPAkEAwlhgM3lWuMS/qdkmjkz+WqkY3xCFX9Dtx4wfRpJa3cLZwxeCa1FC\n" ++ "C3VCid6sahHrTaUmY83Nx+nQ7cb8tckWjwJBAKfnzHsUbnyvfKiVaJZ5sb+fhHf/\n" ++ "SIKAOuyrin4Im10pyvhkqgqgPfSAWO14NeCrkaadfnuFE1s/jN1fmrCvjhECQQCr\n" ++ "0FvERgqgMPjNHPhUJ8dauVIOqtlu+xOsLbnctzj0AvZn3pnjbKQ54wHfR2ggIhVn\n" ++ "wJCu/Vxm19Ro0lnKEKwLAkEA0aLHBlHbX9K8RpOMu/WDVz3k0XhftMAnVnQzaQHZ\n" ++ "4aWApxRPu+C8omPGEW33toz+19rsp/4dR8H0UigmexKXLw==\n" ++ "-----END RSA PRIVATE KEY-----\n" {- openssl dsaparam 1024 -out dsaparams openssl req -new -x509 -subj /CN=Test -newkey dsa:dsaparams -nodes -reqexts v3_req \ | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' privkey.pem openssl dsa -in privkey.pem | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' -} dsaCertificate, dsaKey1, dsaKey2 :: B.ByteString dsaCertificate = fromString $ "-----BEGIN CERTIFICATE-----\n" ++ "MIICrzCCAmugAwIBAgIJALFEpgowHmcXMAsGCWCGSAFlAwQDAjAPMQ0wCwYDVQQD\n" ++ "DARUZXN0MB4XDTE3MDMwMjE4MTA0OFoXDTE3MDQwMTE4MTA0OFowDzENMAsGA1UE\n" ++ "AwwEVGVzdDCCAbYwggErBgcqhkjOOAQBMIIBHgKBgQCsH77mdMUYCgpdNnqljOoG\n" ++ "OLOkPb+9pIrV/LWoX9TvhyfoVOJli5dEWqcui9eTZZ4LW+2F1//0HpTjW5d+aZk7\n" ++ "znkSRg9yihhzYzqGL7GEinFGHIPBL5uKoCW7a2HlJ+OdLBNQ/yeCDpTvt+/agLlA\n" ++ "K1CgpBd1NeG7jFmfgmJ+gwIVAOs+Q1CAhIZzqH7Ymgp4X2buU1plAoGALiXg/kXS\n" ++ "DSWVzbP6kEKMjkpc0KMmUQCErJgcTZmqe2IddoghCHq44ofbdMyJivk0V3lAfprP\n" ++ "l2LMKKnwc0NgWEcPPmR+ZyYXODxOeXlZd1qznDKWdvpciOkMdWOsxF+cbtmGBrxs\n" ++ "+Rm86f+95+EsptH/8FeLFMw7L8u/0FNgAyoDgYQAAoGAIBhO3gbkWHsZSic+5rdh\n" ++ "HS0z0h/kBqbqY2BHFXchaMAgzMrzD/rTpeZ+mND8tIRzOw73tKckeHrfauBNPstc\n" ++ "c2SCFy9lc7eITD/HmoCJFuMLbYxpWlOYL5JU5EQT/1VlH58RprfMp5+HA1tSMZov\n" ++ "zf7ck2W7Rt6zH77Io5lt0aujUDBOMB0GA1UdDgQWBBQOlmp9KHZbomx3TbKxBiGL\n" ++ "oVUB1zAfBgNVHSMEGDAWgBQOlmp9KHZbomx3TbKxBiGLoVUB1zAMBgNVHRMEBTAD\n" ++ "AQH/MAsGCWCGSAFlAwQDAgMxADAuAhUAp/XUpSnDENVgqr2MS1XCXHjI9kACFQDq\n" ++ "jV1C0EYgKTRYKjrztFjBEHv3Ig==\n" ++ "-----END CERTIFICATE-----\n" dsaKey1 = fromString $ "-----BEGIN PRIVATE KEY-----\n" ++ "MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAKwfvuZ0xRgKCl02eqWM6gY4s6Q9\n" ++ "v72kitX8tahf1O+HJ+hU4mWLl0Rapy6L15Nlngtb7YXX//QelONbl35pmTvOeRJG\n" ++ "D3KKGHNjOoYvsYSKcUYcg8Evm4qgJbtrYeUn450sE1D/J4IOlO+379qAuUArUKCk\n" ++ "F3U14buMWZ+CYn6DAhUA6z5DUICEhnOoftiaCnhfZu5TWmUCgYAuJeD+RdINJZXN\n" ++ "s/qQQoyOSlzQoyZRAISsmBxNmap7Yh12iCEIerjih9t0zImK+TRXeUB+ms+XYswo\n" ++ "qfBzQ2BYRw8+ZH5nJhc4PE55eVl3WrOcMpZ2+lyI6Qx1Y6zEX5xu2YYGvGz5Gbzp\n" ++ "/73n4Sym0f/wV4sUzDsvy7/QU2ADKgQWAhQ/q2pbQjljQ7CD3Uc6FA63FS7fYg==\n" ++ "-----END PRIVATE KEY-----\n" dsaKey2 = fromString $ "-----BEGIN DSA PRIVATE KEY-----\n" ++ "MIIBugIBAAKBgQCsH77mdMUYCgpdNnqljOoGOLOkPb+9pIrV/LWoX9TvhyfoVOJl\n" ++ "i5dEWqcui9eTZZ4LW+2F1//0HpTjW5d+aZk7znkSRg9yihhzYzqGL7GEinFGHIPB\n" ++ "L5uKoCW7a2HlJ+OdLBNQ/yeCDpTvt+/agLlAK1CgpBd1NeG7jFmfgmJ+gwIVAOs+\n" ++ "Q1CAhIZzqH7Ymgp4X2buU1plAoGALiXg/kXSDSWVzbP6kEKMjkpc0KMmUQCErJgc\n" ++ "TZmqe2IddoghCHq44ofbdMyJivk0V3lAfprPl2LMKKnwc0NgWEcPPmR+ZyYXODxO\n" ++ "eXlZd1qznDKWdvpciOkMdWOsxF+cbtmGBrxs+Rm86f+95+EsptH/8FeLFMw7L8u/\n" ++ "0FNgAyoCgYAgGE7eBuRYexlKJz7mt2EdLTPSH+QGpupjYEcVdyFowCDMyvMP+tOl\n" ++ "5n6Y0Py0hHM7Dve0pyR4et9q4E0+y1xzZIIXL2Vzt4hMP8eagIkW4wttjGlaU5gv\n" ++ "klTkRBP/VWUfnxGmt8ynn4cDW1Ixmi/N/tyTZbtG3rMfvsijmW3RqwIUP6tqW0I5\n" ++ "Y0Owg91HOhQOtxUu32I=\n" ++ "-----END DSA PRIVATE KEY-----\n" {- openssl ecparam -name prime256v1 -out ecparams -param_enc named_curve openssl req -new -x509 -subj /CN=Test -newkey ec:ecparams -nodes -reqexts v3_req \ | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' privkey.pem openssl ec -in privkey.pem | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' -} ecCertificateNc, ecKey1Nc, ecKey2Nc :: B.ByteString ecCertificateNc = fromString $ "-----BEGIN CERTIFICATE-----\n" ++ "MIIBZTCCAQugAwIBAgIJAPF7NB8WKn6XMAoGCCqGSM49BAMCMA8xDTALBgNVBAMM\n" ++ "BFRlc3QwHhcNMTcwMzAyMTgxMTI1WhcNMTcwNDAxMTgxMTI1WjAPMQ0wCwYDVQQD\n" ++ "DARUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETCmVJNQ5HWoFKMpyZFly\n" ++ "kILKFuE0ZTu2t8G5jXpQp0g4g8OqyRo/6iSZSs/WAP3e2vcJuyhnDSd8MocSnEfi\n" ++ "pqNQME4wHQYDVR0OBBYEFKCemJ7KZ+JfExQxOh/0qhKO3cJwMB8GA1UdIwQYMBaA\n" ++ "FKCemJ7KZ+JfExQxOh/0qhKO3cJwMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwID\n" ++ "SAAwRQIhALhWJShVXsrupU8ISSBJVGmzRhPcueHsjuydyyfOsxElAiADbsp0SM/9\n" ++ "6CQCvqX+V8DAwxT1WiRDzN8ilV6ZIfUI3Q==\n" ++ "-----END CERTIFICATE-----\n" ecKey1Nc = fromString $ "-----BEGIN PRIVATE KEY-----\n" ++ "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg1hT2Mdt5IS0Qs9Bb\n" ++ "LJ8ZAW3VTDIq1zn8qSYGiLcMVkShRANCAARMKZUk1DkdagUoynJkWXKQgsoW4TRl\n" ++ "O7a3wbmNelCnSDiDw6rJGj/qJJlKz9YA/d7a9wm7KGcNJ3wyhxKcR+Km\n" ++ "-----END PRIVATE KEY-----\n" ecKey2Nc = fromString $ "-----BEGIN EC PRIVATE KEY-----\n" ++ "MHcCAQEEINYU9jHbeSEtELPQWyyfGQFt1UwyKtc5/KkmBoi3DFZEoAoGCCqGSM49\n" ++ "AwEHoUQDQgAETCmVJNQ5HWoFKMpyZFlykILKFuE0ZTu2t8G5jXpQp0g4g8OqyRo/\n" ++ "6iSZSs/WAP3e2vcJuyhnDSd8MocSnEfipg==\n" ++ "-----END EC PRIVATE KEY-----\n" {- openssl ecparam -name prime256v1 -out ecparams -param_enc explicit openssl req -new -x509 -subj /CN=Test -newkey ec:ecparams -nodes -reqexts v3_req \ | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' privkey.pem openssl ec -in privkey.pem | sed -e 's/^\(.*\)$/ "\1\\n"/' -e '$!s/$/ ++/' -} ecCertificateEpc, ecKey1Epc, ecKey2Epc :: B.ByteString ecCertificateEpc = fromString $ "-----BEGIN CERTIFICATE-----\n" ++ "MIICWTCCAf+gAwIBAgIJAPF9pxfJTwfaMAoGCCqGSM49BAMCMA8xDTALBgNVBAMM\n" ++ "BFRlc3QwHhcNMTcwMzAyMTgxMTUxWhcNMTcwNDAxMTgxMTUxWjAPMQ0wCwYDVQQD\n" ++ "DARUZXN0MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8A\n" ++ "AAABAAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAA\n" ++ "AAAA///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9Jg\n" ++ "SwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt\n" ++ "6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP//\n" ++ "//8AAAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABHXlHgRztuAF/Vs5\n" ++ "GMB5GEfGpFsSsua+GDB8/zvjT4UBgpnb71HJPFOC0yrYliunXds00VlOs3v+FCVL\n" ++ "mU5yW+2jUDBOMB0GA1UdDgQWBBSFV0KwoW1mPah12w3rngU7t1kjETAfBgNVHSME\n" ++ "GDAWgBSFV0KwoW1mPah12w3rngU7t1kjETAMBgNVHRMEBTADAQH/MAoGCCqGSM49\n" ++ "BAMCA0gAMEUCIDqqWyJEIRo2YSvvrQKJZ3wKQSGeWoPnJvWfXMjgODd5AiEAsXCt\n" ++ "LYmBKulTMXATynvrqa/xDi3z2lkwcWQC1AZBZ8M=\n" ++ "-----END CERTIFICATE-----\n" ecKey1Epc = fromString $ "-----BEGIN PRIVATE KEY-----\n" ++ "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB\n" ++ "AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA\n" ++ "///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV\n" ++ "AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg\n" ++ "9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A\n" ++ "AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgBnbFaCHgp5Cn\n" ++ "stu9ntk7QiEP6j/7FzK6GC4dzsID7/ihRANCAAR15R4Ec7bgBf1bORjAeRhHxqRb\n" ++ "ErLmvhgwfP8740+FAYKZ2+9RyTxTgtMq2JYrp13bNNFZTrN7/hQlS5lOclvt\n" ++ "-----END PRIVATE KEY-----\n" ecKey2Epc = fromString $ "-----BEGIN EC PRIVATE KEY-----\n" ++ "MIIBaAIBAQQgBnbFaCHgp5Cnstu9ntk7QiEP6j/7FzK6GC4dzsID7/iggfowgfcC\n" ++ "AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\n" ++ "MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\n" ++ "vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\n" ++ "axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\n" ++ "K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\n" ++ "YyVRAgEBoUQDQgAEdeUeBHO24AX9WzkYwHkYR8akWxKy5r4YMHz/O+NPhQGCmdvv\n" ++ "Uck8U4LTKtiWK6dd2zTRWU6ze/4UJUuZTnJb7Q==\n" ++ "-----END EC PRIVATE KEY-----\n" memoryKeyTests :: TestTree memoryKeyTests = testGroup "Key" [ keyTest "RSA" rsaKey1 rsaKey2 , keyTest "DSA" dsaKey1 dsaKey2 , keyTest "EC (named curve)" ecKey1Nc ecKey2Nc , keyTest "EC (explicit prime curve)" ecKey1Epc ecKey2Epc ] where keyTest name outer inner = let kInner = readKeyFileFromMemory inner kOuter = readKeyFileFromMemory outer in testGroup name [ testCase "read outer" $ length kOuter @?= 1 , testCase "read inner" $ length kInner @?= 1 , testCase "same key" $ assertBool "keys differ" (kInner == kOuter) ] memoryCertificateTests :: TestTree memoryCertificateTests = testGroup "Certificate" [ certTest "RSA" rsaCertificate , certTest "DSA" dsaCertificate , certTest "EC (named curve)" ecCertificateNc , certTest "EC (explicit prime curve)" ecCertificateEpc ] where certTest name bytes = testCase name $ length (readSignedCertificateFromMemory bytes) @?= 1 readSignedCertificateFromMemory :: B.ByteString -> [SignedCertificate] readSignedCertificateFromMemory = readSignedObjectFromMemory -- | Runs the test suite. main :: IO () main = defaultMain $ testGroup "x509-store" [ testGroup "Memory" [ memoryKeyTests , memoryCertificateTests ] ] x509-store-1.6.5/LICENSE0000644000000000000000000000273113124231131012547 0ustar0000000000000000Copyright (c) 2010-2013 Vincent Hanquez All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. x509-store-1.6.5/Setup.hs0000644000000000000000000000005613124231131013174 0ustar0000000000000000import Distribution.Simple main = defaultMain x509-store-1.6.5/x509-store.cabal0000644000000000000000000000326413140301407014371 0ustar0000000000000000Name: x509-store version: 1.6.5 Description: X.509 collection accessing and storing methods for certificate, crl, exception list License: BSD3 License-file: LICENSE Copyright: Vincent Hanquez Author: Vincent Hanquez Maintainer: Vincent Hanquez Synopsis: X.509 collection accessing and storing methods Build-Type: Simple Category: Data stability: experimental Homepage: http://github.com/vincenthz/hs-certificate Cabal-Version: >= 1.10 Library Default-Language: Haskell2010 Build-Depends: base >= 3 && < 5 , bytestring , mtl , containers , directory , filepath , pem >= 0.1 && < 0.3 , asn1-types >= 0.3 && < 0.4 , asn1-encoding >= 0.9 && < 0.10 , cryptonite , x509 >= 1.7.2 Exposed-modules: Data.X509.CertificateStore Data.X509.File Data.X509.Memory ghc-options: -Wall Test-Suite test-x509-store Default-Language: Haskell2010 type: exitcode-stdio-1.0 hs-source-dirs: Tests Main-is: Tests.hs Build-Depends: base >= 3 && < 5 , bytestring , tasty , tasty-hunit , x509 , x509-store ghc-options: -Wall source-repository head type: git location: git://github.com/vincenthz/hs-certificate subdir: x509-store