x509 1.7.4 → 1.7.5
raw patch · 5 files changed
+197/−42 lines, 5 filesdep ~cryptonite
Dependency ranges changed: cryptonite
Files
- Data/X509/AlgorithmIdentifier.hs +16/−4
- Data/X509/PrivateKey.hs +78/−36
- Data/X509/PublicKey.hs +42/−0
- Tests/Tests.hs +59/−0
- x509.cabal +2/−2
Data/X509/AlgorithmIdentifier.hs view
@@ -31,14 +31,20 @@ | 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 (Show,Eq) --- | Signature Algorithm often composed of--- a public key algorithm and a hash algorithm+-- | 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 (Show,Eq) @@ -47,6 +53,10 @@ 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 @@ -71,6 +81,8 @@ , ([2,16,840,1,101,3,4,2,4], SignatureALG HashSHA224 PubKeyALG_RSAPSS) , ([2,16,840,1,101,3,4,3,1], SignatureALG HashSHA224 PubKeyALG_DSA) , ([2,16,840,1,101,3,4,3,2], SignatureALG HashSHA256 PubKeyALG_DSA)+ , ([1,3,101,112], SignatureALG_IntrinsicHash PubKeyALG_Ed25519)+ , ([1,3,101,113], SignatureALG_IntrinsicHash PubKeyALG_Ed448) ] oidSig :: OID -> SignatureALG@@ -99,6 +111,6 @@ Right (oidSig hash1, xs) fromASN1 _ = Left "fromASN1: X509.SignatureALG: unknown format"- toASN1 signatureAlg@(SignatureALG hashAlg PubKeyALG_RSAPSS) = \xs -> Start Sequence:OID [1,2,840,113549,1,1,10]:Start Sequence:Start (Container Context 0):Start Sequence:OID (sigOID signatureAlg):End Sequence:End (Container Context 0):Start (Container Context 1): Start Sequence:OID [1,2,840,113549,1,1,8]:Start Sequence:OID (sigOID signatureAlg):End Sequence:End Sequence:End (Container Context 1):Start (Container Context 2):IntVal (saltLen hashAlg):End (Container Context 2):End Sequence:End Sequence:xs- toASN1 signatureAlg@(SignatureALG _ _) = \xs -> Start Sequence:OID (sigOID signatureAlg):Null:End Sequence:xs toASN1 (SignatureALG_Unknown oid) = \xs -> Start Sequence:OID oid:Null:End Sequence:xs+ toASN1 signatureAlg@(SignatureALG hashAlg PubKeyALG_RSAPSS) = \xs -> Start Sequence:OID [1,2,840,113549,1,1,10]:Start Sequence:Start (Container Context 0):Start Sequence:OID (sigOID signatureAlg):End Sequence:End (Container Context 0):Start (Container Context 1): Start Sequence:OID [1,2,840,113549,1,1,8]:Start Sequence:OID (sigOID signatureAlg):End Sequence:End Sequence:End (Container Context 1):Start (Container Context 2):IntVal (saltLen hashAlg):End (Container Context 2):End Sequence:End Sequence:xs+ toASN1 signatureAlg = \xs -> Start Sequence:OID (sigOID signatureAlg):Null:End Sequence:xs
Data/X509/PrivateKey.hs view
@@ -14,23 +14,31 @@ ) where import Control.Applicative ((<$>), pure)+import Data.Maybe (fromMaybe) import Data.Word (Word) +import Data.ByteArray (ByteArrayAccess, convert) import qualified Data.ByteString as B import Data.ASN1.Types import Data.ASN1.Encoding import Data.ASN1.BinaryEncoding import Data.ASN1.BitArray+import Data.ASN1.Stream (getConstructedEnd) import Data.X509.AlgorithmIdentifier import Data.X509.PublicKey (SerializedPoint(..))-import Data.X509.OID (lookupByOID, curvesOIDTable)+import Data.X509.OID (lookupByOID, lookupOID, curvesOIDTable) +import Crypto.Error (CryptoFailable(..)) import Crypto.Number.Serialize (i2osp, os2ip) import qualified Crypto.PubKey.RSA as RSA import qualified Crypto.PubKey.DSA as DSA import qualified Crypto.PubKey.ECC.Types as ECC+import qualified Crypto.PubKey.Curve25519 as X25519+import qualified Crypto.PubKey.Curve448 as X448+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Crypto.PubKey.Ed448 as Ed448 -- | Elliptic Curve Private Key --@@ -57,6 +65,10 @@ PrivKeyRSA RSA.PrivateKey -- ^ RSA private key | PrivKeyDSA DSA.PrivateKey -- ^ DSA private key | PrivKeyEC PrivKeyEC -- ^ EC private key+ | PrivKeyX25519 X25519.SecretKey -- ^ X25519 private key+ | PrivKeyX448 X448.SecretKey -- ^ X448 private key+ | PrivKeyEd25519 Ed25519.SecretKey -- ^ Ed25519 private key+ | PrivKeyEd448 Ed448.SecretKey -- ^ Ed448 private key deriving (Show,Eq) instance ASN1Object PrivKey where@@ -67,7 +79,8 @@ privkeyFromASN1 asn1 = (mapFst PrivKeyRSA <$> rsaFromASN1 asn1) <!> (mapFst PrivKeyDSA <$> dsaFromASN1 asn1) <!>- (mapFst PrivKeyEC <$> ecdsaFromASN1 asn1)+ (mapFst PrivKeyEC <$> ecdsaFromASN1 asn1) <!>+ newcurveFromASN1 asn1 where mapFst f (a, b) = (f a, b) @@ -161,10 +174,59 @@ spanTag a (Start (Container _ b) : as) | a == b = spanEnd 0 as spanTag _ as = ([], as) +newcurveFromASN1 :: [ASN1] -> Either String (PrivKey, [ASN1])+newcurveFromASN1 ( Start Sequence+ : IntVal v+ : Start Sequence+ : OID oid+ : End Sequence+ : OctetString bs+ : xs)+ | isValidVersion v = do+ let (_, ys) = containerWithTag 0 xs+ case primitiveWithTag 1 ys of+ (_, End Sequence : zs) ->+ case getP oid of+ Just (name, parse) -> do+ let err s = Left (name ++ ".SecretKey.fromASN1: " ++ s)+ case decodeASN1' BER bs of+ Right [OctetString key] ->+ case parse key of+ CryptoPassed s -> Right (s, zs)+ CryptoFailed e -> err ("invalid secret key: " ++ show e)+ Right _ -> err "unexpected inner format"+ Left e -> err (show e)+ Nothing -> Left ("newcurveFromASN1: unexpected OID " ++ show oid)+ _ -> Left "newcurveFromASN1: unexpected end format"+ | otherwise = Left ("newcurveFromASN1: unexpected version: " ++ show v)+ where+ getP [1,3,101,110] = Just ("X25519", fmap PrivKeyX25519 . X25519.secretKey)+ getP [1,3,101,111] = Just ("X448", fmap PrivKeyX448 . X448.secretKey)+ getP [1,3,101,112] = Just ("Ed25519", fmap PrivKeyEd25519 . Ed25519.secretKey)+ getP [1,3,101,113] = Just ("Ed448", fmap PrivKeyEd448 . Ed448.secretKey)+ getP _ = Nothing+ isValidVersion version = version >= 0 && version <= 1+newcurveFromASN1 _ =+ Left "newcurveFromASN1: unexpected format"++containerWithTag :: ASN1Tag -> [ASN1] -> ([ASN1], [ASN1])+containerWithTag etag (Start (Container _ atag) : xs)+ | etag == atag = getConstructedEnd 0 xs+containerWithTag _ xs = ([], xs)++primitiveWithTag :: ASN1Tag -> [ASN1] -> (Maybe B.ByteString, [ASN1])+primitiveWithTag etag (Other _ atag bs : xs)+ | etag == atag = (Just bs, xs)+primitiveWithTag _ xs = (Nothing, xs)+ privkeyToASN1 :: PrivKey -> ASN1S privkeyToASN1 (PrivKeyRSA rsa) = rsaToASN1 rsa privkeyToASN1 (PrivKeyDSA dsa) = dsaToASN1 dsa privkeyToASN1 (PrivKeyEC ecdsa) = ecdsaToASN1 ecdsa+privkeyToASN1 (PrivKeyX25519 k) = newcurveToASN1 [1,3,101,110] k+privkeyToASN1 (PrivKeyX448 k) = newcurveToASN1 [1,3,101,111] k+privkeyToASN1 (PrivKeyEd25519 k) = newcurveToASN1 [1,3,101,112] k+privkeyToASN1 (PrivKeyEd448 k) = newcurveToASN1 [1,3,101,113] k rsaToASN1 :: RSA.PrivateKey -> ASN1S rsaToASN1 key = (++)@@ -189,40 +251,9 @@ , End Sequence ] where- oid = case curveName of- ECC.SEC_p112r1 -> [1, 3, 132, 0, 6]- ECC.SEC_p112r2 -> [1, 3, 132, 0, 7]- ECC.SEC_p128r1 -> [1, 3, 132, 0, 28]- ECC.SEC_p128r2 -> [1, 3, 132, 0, 29]- ECC.SEC_p160k1 -> [1, 3, 132, 0, 9]- ECC.SEC_p160r1 -> [1, 3, 132, 0, 8]- ECC.SEC_p160r2 -> [1, 3, 132, 0, 30]- ECC.SEC_p192k1 -> [1, 3, 132, 0, 31]- ECC.SEC_p192r1 -> [1, 2, 840, 10045, 3, 1, 1]- ECC.SEC_p224k1 -> [1, 3, 132, 0, 32]- ECC.SEC_p224r1 -> [1, 3, 132, 0, 33]- ECC.SEC_p256k1 -> [1, 3, 132, 0, 10]- ECC.SEC_p256r1 -> [1, 2, 840, 10045, 3, 1, 7]- ECC.SEC_p384r1 -> [1, 3, 132, 0, 34]- ECC.SEC_p521r1 -> [1, 3, 132, 0, 35]- ECC.SEC_t113r1 -> [1, 3, 132, 0, 4]- ECC.SEC_t113r2 -> [1, 3, 132, 0, 5]- ECC.SEC_t131r1 -> [1, 3, 132, 0, 22]- ECC.SEC_t131r2 -> [1, 3, 132, 0, 23]- ECC.SEC_t163k1 -> [1, 3, 132, 0, 1]- ECC.SEC_t163r1 -> [1, 3, 132, 0, 2]- ECC.SEC_t163r2 -> [1, 3, 132, 0, 15]- ECC.SEC_t193r1 -> [1, 3, 132, 0, 24]- ECC.SEC_t193r2 -> [1, 3, 132, 0, 25]- ECC.SEC_t233k1 -> [1, 3, 132, 0, 26]- ECC.SEC_t233r1 -> [1, 3, 132, 0, 27]- ECC.SEC_t239k1 -> [1, 3, 132, 0, 3]- ECC.SEC_t283k1 -> [1, 3, 132, 0, 16]- ECC.SEC_t283r1 -> [1, 3, 132, 0, 17]- ECC.SEC_t409k1 -> [1, 3, 132, 0, 36]- ECC.SEC_t409r1 -> [1, 3, 132, 0, 37]- ECC.SEC_t571k1 -> [1, 3, 132, 0, 38]- ECC.SEC_t571r1 -> [1, 3, 132, 0, 39]+ err = error . ("ECDSA.PrivateKey.toASN1: " ++)+ oid = fromMaybe (err $ "missing named curve " ++ show curveName)+ (lookupOID curvesOIDTable curveName) ecdsaToASN1 (PrivKeyEC_Prime d a b p g o c s) = (++) [ Start Sequence, IntVal 1, OctetString (i2osp d) , Start (Container Context 0), Start Sequence, IntVal 1@@ -239,6 +270,13 @@ where bytes = i2osp s +newcurveToASN1 :: ByteArrayAccess key => OID -> key -> ASN1S+newcurveToASN1 oid key = (++)+ [ Start Sequence, IntVal 0, Start Sequence, OID oid, End Sequence+ , OctetString (encodeASN1' DER [OctetString $ convert key])+ , End Sequence+ ]+ mapLeft :: (a0 -> a1) -> Either a0 b -> Either a1 b mapLeft f (Left x) = Left (f x) mapLeft _ (Right x) = Right x@@ -248,3 +286,7 @@ privkeyToAlg (PrivKeyRSA _) = PubKeyALG_RSA privkeyToAlg (PrivKeyDSA _) = PubKeyALG_DSA privkeyToAlg (PrivKeyEC _) = PubKeyALG_EC+privkeyToAlg (PrivKeyX25519 _) = PubKeyALG_X25519+privkeyToAlg (PrivKeyX448 _) = PubKeyALG_X448+privkeyToAlg (PrivKeyEd25519 _) = PubKeyALG_Ed25519+privkeyToAlg (PrivKeyEd448 _) = PubKeyALG_Ed448
Data/X509/PublicKey.hs view
@@ -20,15 +20,21 @@ import Data.ASN1.BitArray import Data.Bits+import Data.ByteArray (convert) import Data.ByteString (ByteString) import Data.X509.Internal import Data.X509.OID import Data.X509.AlgorithmIdentifier +import Crypto.Error (CryptoFailable(..)) import qualified Crypto.PubKey.RSA.Types as RSA import qualified Crypto.PubKey.DSA as DSA import qualified Crypto.PubKey.ECC.Types as ECC+import qualified Crypto.PubKey.Curve25519 as X25519+import qualified Crypto.PubKey.Curve448 as X448+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Crypto.PubKey.Ed448 as Ed448 import Crypto.Number.Serialize (os2ip) import Data.Word @@ -65,6 +71,10 @@ | PubKeyDH (Integer,Integer,Integer,Maybe Integer,([Word8], Integer)) -- ^ DH format with (p,g,q,j,(seed,pgenCounter)) | PubKeyEC PubKeyEC -- ^ EC public key+ | PubKeyX25519 X25519.PublicKey -- ^ X25519 public key+ | PubKeyX448 X448.PublicKey -- ^ X448 public key+ | PubKeyEd25519 Ed25519.PublicKey -- ^ Ed25519 public key+ | PubKeyEd448 Ed448.PublicKey -- ^ Ed448 public key | PubKeyUnknown OID B.ByteString -- ^ unrecognized format deriving (Show,Eq) @@ -132,6 +142,22 @@ }, xs2) _ -> Left $ "fromASN1: X509.PubKey: unknown EC format: " ++ show xs+ | pkalg == getObjectID PubKeyALG_X25519 =+ case xs of+ End Sequence:BitString bits:End Sequence:xs2 -> decodeCF "X25519" PubKeyX25519 bits xs2 X25519.publicKey+ _ -> Left ("fromASN1: X509.PubKey: unknown X25519 format: " ++ show xs)+ | pkalg == getObjectID PubKeyALG_X448 =+ case xs of+ End Sequence:BitString bits:End Sequence:xs2 -> decodeCF "X448" PubKeyX448 bits xs2 X448.publicKey+ _ -> Left ("fromASN1: X509.PubKey: unknown X448 format: " ++ show xs)+ | pkalg == getObjectID PubKeyALG_Ed25519 =+ case xs of+ End Sequence:BitString bits:End Sequence:xs2 -> decodeCF "Ed25519" PubKeyEd25519 bits xs2 Ed25519.publicKey+ _ -> Left ("fromASN1: X509.PubKey: unknown Ed25519 format: " ++ show xs)+ | pkalg == getObjectID PubKeyALG_Ed448 =+ case xs of+ End Sequence:BitString bits:End Sequence:xs2 -> decodeCF "Ed448" PubKeyEd448 bits xs2 Ed448.publicKey+ _ -> Left ("fromASN1: X509.PubKey: unknown Ed448 format: " ++ show xs) | otherwise = Left $ "fromASN1: unknown public key OID: " ++ show pkalg where decodeASN1Err format bits xs2 f = case decodeASN1' BER (bitArrayGetData bits) of@@ -146,6 +172,10 @@ removeNull (Null:r) = r removeNull l = l + decodeCF format c bits xs2 f = case f (bitArrayGetData bits) of+ CryptoPassed pk -> Right (c pk, xs2)+ CryptoFailed err -> Left ("fromASN1: X509.PubKey " ++ format ++ " bitarray contains an invalid public key: " ++ show err)+ fromASN1 l = Left ("fromASN1: X509.PubKey: unknown format:" ++ show l) toASN1 a = \xs -> encodePK a ++ xs @@ -155,6 +185,10 @@ pubkeyToAlg (PubKeyDSA _) = PubKeyALG_DSA pubkeyToAlg (PubKeyDH _) = PubKeyALG_DH pubkeyToAlg (PubKeyEC _) = PubKeyALG_EC+pubkeyToAlg (PubKeyX25519 _) = PubKeyALG_X25519+pubkeyToAlg (PubKeyX448 _) = PubKeyALG_X448+pubkeyToAlg (PubKeyEd25519 _) = PubKeyALG_Ed25519+pubkeyToAlg (PubKeyEd448 _) = PubKeyALG_Ed448 pubkeyToAlg (PubKeyUnknown oid _) = PubKeyALG_Unknown oid encodePK :: PubKey -> [ASN1]@@ -180,6 +214,14 @@ _ -> error ("undefined curve OID: " ++ show curveName) encodeInner (PubKeyEC (PubKeyEC_Prime {})) = error "encodeInner: unimplemented public key EC_Prime"+ encodeInner (PubKeyX25519 pubkey) =+ asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0]+ encodeInner (PubKeyX448 pubkey) =+ asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0]+ encodeInner (PubKeyEd25519 pubkey) =+ asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0]+ encodeInner (PubKeyEd448 pubkey) =+ asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0] encodeInner (PubKeyDH _) = error "encodeInner: unimplemented public key DH" encodeInner (PubKeyUnknown _ l) = asn1Container Sequence [pkalg,Null] ++ [BitString $ toBitArray l 0]
Tests/Tests.hs view
@@ -12,6 +12,11 @@ import Data.List (nub, sort) import Data.ASN1.Types import Data.X509+import Crypto.Error (throwCryptoError)+import qualified Crypto.PubKey.Curve25519 as X25519+import qualified Crypto.PubKey.Curve448 as X448+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Crypto.PubKey.Ed448 as Ed448 import qualified Crypto.PubKey.RSA as RSA import qualified Crypto.PubKey.DSA as DSA @@ -33,13 +38,64 @@ instance Arbitrary DSA.PublicKey where arbitrary = DSA.PublicKey <$> arbitrary <*> arbitrary +instance Arbitrary X25519.PublicKey where+ arbitrary = X25519.toPublic <$> arbitrary++instance Arbitrary X448.PublicKey where+ arbitrary = X448.toPublic <$> arbitrary++instance Arbitrary Ed25519.PublicKey where+ arbitrary = Ed25519.toPublic <$> arbitrary++instance Arbitrary Ed448.PublicKey where+ arbitrary = Ed448.toPublic <$> arbitrary+ instance Arbitrary PubKey where arbitrary = oneof [ PubKeyRSA <$> arbitrary , PubKeyDSA <$> arbitrary --, PubKeyECDSA ECDSA_Hash_SHA384 <$> (B.pack <$> replicateM 384 arbitrary)+ , PubKeyX25519 <$> arbitrary+ , PubKeyX448 <$> arbitrary+ , PubKeyEd25519 <$> arbitrary+ , PubKeyEd448 <$> arbitrary ] +instance Arbitrary RSA.PrivateKey where+ arbitrary = RSA.PrivateKey <$> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary++instance Arbitrary DSA.PrivateKey where+ arbitrary = DSA.PrivateKey <$> arbitrary <*> arbitrary++instance Arbitrary X25519.SecretKey where+ arbitrary = throwCryptoError . X25519.secretKey <$> arbitraryBS 32 32++instance Arbitrary X448.SecretKey where+ arbitrary = throwCryptoError . X448.secretKey <$> arbitraryBS 56 56++instance Arbitrary Ed25519.SecretKey where+ arbitrary = throwCryptoError . Ed25519.secretKey <$> arbitraryBS 32 32++instance Arbitrary Ed448.SecretKey where+ arbitrary = throwCryptoError . Ed448.secretKey <$> arbitraryBS 57 57++instance Arbitrary PrivKey where+ arbitrary = oneof+ [ PrivKeyRSA <$> arbitrary+ , PrivKeyDSA <$> arbitrary+ --, PrivKeyECDSA ECDSA_Hash_SHA384 <$> (B.pack <$> replicateM 384 arbitrary)+ , PrivKeyX25519 <$> arbitrary+ , PrivKeyX448 <$> arbitrary+ , PrivKeyEd25519 <$> arbitrary+ , PrivKeyEd448 <$> arbitrary+ ]+ instance Arbitrary HashALG where arbitrary = elements [HashMD2,HashMD5,HashSHA1,HashSHA224,HashSHA256,HashSHA384,HashSHA512] @@ -65,6 +121,8 @@ , SignatureALG HashSHA256 PubKeyALG_EC , SignatureALG HashSHA384 PubKeyALG_EC , SignatureALG HashSHA512 PubKeyALG_EC+ , SignatureALG_IntrinsicHash PubKeyALG_Ed25519+ , SignatureALG_IntrinsicHash PubKeyALG_Ed448 ] arbitraryBS r1 r2 = choose (r1,r2) >>= \l -> (B.pack <$> replicateM l arbitrary)@@ -152,6 +210,7 @@ main = defaultMain $ testGroup "X509" [ testGroup "marshall" [ testProperty "pubkey" (property_unmarshall_marshall_id :: PubKey -> Bool)+ , testProperty "privkey" (property_unmarshall_marshall_id :: PrivKey -> Bool) , testProperty "signature alg" (property_unmarshall_marshall_id :: SignatureALG -> Bool) , testGroup "extension" [ testProperty "key-usage" (property_extension_id :: ExtKeyUsage -> Bool)
x509.cabal view
@@ -1,5 +1,5 @@ Name: x509-version: 1.7.4+version: 1.7.5 Description: X509 reader and writer. please see README License: BSD3 License-file: LICENSE@@ -25,7 +25,7 @@ , asn1-types >= 0.3.1 && < 0.4 , asn1-encoding >= 0.9 && < 0.10 , asn1-parse >= 0.9.3 && < 0.10- , cryptonite >= 0.8+ , cryptonite >= 0.24 Exposed-modules: Data.X509 Data.X509.EC Other-modules: Data.X509.Internal