x509-util (empty) → 1.4.0
raw patch · 4 files changed
+372/−0 lines, 4 filesdep +asn1-encodingdep +asn1-typesdep +basesetup-changed
Dependencies added: asn1-encoding, asn1-types, base, bytestring, crypto-pubkey, crypto-pubkey-types, cryptohash, directory, pem, text, x509, x509-store, x509-system, x509-validation
Files
- LICENSE +27/−0
- Setup.hs +2/−0
- src/Certificate.hs +306/−0
- x509-util.cabal +37/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org>++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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Certificate.hs view
@@ -0,0 +1,306 @@+{-# LANGUAGE DeriveDataTypeable, OverloadedStrings #-}++import Data.Either+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Char8 as LC+import qualified Data.ByteString as B+import qualified Data.Text.Lazy as T+import Data.Text.Lazy.Encoding (decodeUtf8)+import Data.X509+import qualified Data.X509 as X509+import Data.List (find)+import Data.PEM (pemParseBS, pemContent, pemName)+import System.Console.GetOpt+import System.Environment+import Control.Monad+import Control.Applicative ((<$>))+import Data.Maybe+import System.Exit+import System.X509+import Data.X509.CertificateStore+import Data.X509.Validation++-- for signing/verifying certificate+import qualified Crypto.Hash.SHA1 as SHA1+import qualified Crypto.Hash.SHA224 as SHA224+import qualified Crypto.Hash.SHA256 as SHA256+import qualified Crypto.Hash.SHA512 as SHA512+import qualified Crypto.Hash.MD2 as MD2+import qualified Crypto.Hash.MD5 as MD5+import qualified Crypto.PubKey.HashDescr as HD+import qualified Crypto.PubKey.RSA as RSA+import qualified Crypto.Types.PubKey.RSA as RSA+import qualified Crypto.Types.PubKey.DSA as DSA+import qualified Crypto.PubKey.RSA.PKCS15 as RSA+import qualified Crypto.PubKey.DSA as DSA++import Data.ASN1.Encoding+import Data.ASN1.BinaryEncoding+import Data.ASN1.Types+import Data.ASN1.BitArray+import Text.Printf+import Numeric++hexdump :: B.ByteString -> String+hexdump bs = concatMap hex $ B.unpack bs+ where hex n+ | n > 0xa = showHex n ""+ | otherwise = "0" ++ showHex n ""++hexdump' = hexdump++showDN (X509.DistinguishedName dn) = mapM_ toStr dn+ where toStr (oid, cs@(ASN1CharacterString e t)) =+ putStrLn (" " ++ key ++ ": " ++ value)+ where key = show oid+ value = case asn1CharacterToString cs of+ Nothing -> show e ++ " " ++ show t ++ " (decoding to string failed)"+ Just s -> show s ++ " (encoding : " ++ show e ++ ")"++showExts es@(Extensions Nothing) = do+ return ()+showExts es@(Extensions (Just exts)) = do+ mapM_ showExt exts+ putStrLn "known extensions decoded: "+ showKnownExtension (X509.extensionGet es :: Maybe X509.ExtBasicConstraints)+ showKnownExtension (X509.extensionGet es :: Maybe X509.ExtKeyUsage)+ showKnownExtension (X509.extensionGet es :: Maybe X509.ExtSubjectKeyId)+ showKnownExtension (X509.extensionGet es :: Maybe X509.ExtSubjectAltName)+ showKnownExtension (X509.extensionGet es :: Maybe X509.ExtAuthorityKeyId)+ where+ showExt (ExtensionRaw oid critical asn1) = do+ putStrLn (" OID: " ++ show oid ++ " critical: " ++ show critical)+ putStrLn (" " ++ show asn1)+ showKnownExtension Nothing = return ()+ showKnownExtension (Just e) = putStrLn (" " ++ show e)++showCert :: SignedCertificate -> IO ()+showCert signedCert = do+ putStrLn ("version: " ++ show (X509.certVersion cert))+ putStrLn ("serial: " ++ show (X509.certSerial cert))+ putStrLn ("sigalg: " ++ show (X509.certSignatureAlg cert))+ putStrLn "issuer:"+ showDN $ X509.certIssuerDN cert+ putStrLn "subject:"+ showDN $ X509.certSubjectDN cert+ putStrLn ("valid: " ++ show (X509.certValidity cert))+ case X509.certPubKey cert of+ X509.PubKeyRSA pubkey -> do+ putStrLn "public key RSA:"+ printf " len : %d bits\n" (RSA.public_size pubkey * 8)+ printf " modulus: %x\n" (RSA.public_n pubkey)+ printf " e : %x\n" (RSA.public_e pubkey)+ X509.PubKeyDSA pubkey -> do+ let params = DSA.public_params pubkey+ putStrLn "public key DSA:"+ printf " pub : %x\n" (DSA.public_y pubkey)+ printf " p : %d\n" (DSA.params_p params)+ printf " q : %x\n" (DSA.params_q params)+ printf " g : %x\n" (DSA.params_g params)+ X509.PubKeyUnknown oid ws -> do+ printf "public key unknown: %s\n" (show oid)+ printf " raw bytes: %s\n" (show ws)+ --case decodeASN1 BER $ L.pack ws of+ -- Left err -> printf " asn1 decoding failed: %s\n" (show err)+ -- Right l -> printf " asn1 decoding:\n" >> showASN1 4 l+ pk ->+ printf "public key: %s\n" (show pk)+ case X509.certExtensions cert of+ (Extensions Nothing) -> return ()+ (Extensions (Just es)) -> putStrLn "extensions:" >> showExts (X509.certExtensions cert)+ putStrLn ("sigAlg: " ++ show sigalg)+ putStrLn ("sig: " ++ show sigbits)+ where+ signed = X509.getSigned signedCert+ sigalg = X509.signedAlg signed+ sigbits = X509.signedSignature signed+ cert = X509.signedObject signed+++showRSAKey :: (RSA.KeyPair) -> String+showRSAKey (RSA.KeyPair privkey) = unlines+ [ "len-modulus: " ++ (show $ RSA.public_size pubkey)+ , "modulus: " ++ (show $ RSA.public_n pubkey)+ , "public exponant: " ++ (show $ RSA.public_e pubkey)+ , "private exponant: " ++ (show $ RSA.private_d privkey)+ , "p1: " ++ (show $ RSA.private_p privkey)+ , "p2: " ++ (show $ RSA.private_q privkey)+ , "exp1: " ++ (show $ RSA.private_dP privkey)+ , "exp2: " ++ (show $ RSA.private_dQ privkey)+ , "coefficient: " ++ (show $ RSA.private_qinv privkey)+ ]+ where pubkey = RSA.private_pub privkey++showDSAKey :: DSA.KeyPair -> String+showDSAKey (DSA.KeyPair params pubnum privnum) = unlines+ [ "priv " ++ (printf "%x" $ privnum)+ , "pub: " ++ (printf "%x" $ pubnum)+ , "p: " ++ (printf "%x" $ DSA.params_p params)+ , "q: " ++ (printf "%x" $ DSA.params_q params)+ , "g: " ++ (printf "%x" $ DSA.params_g params)+ ]++showASN1 :: Int -> [ASN1] -> IO ()+showASN1 at = prettyPrint at where+ indent n = putStr (replicate n ' ')++ prettyPrint n [] = return ()+ prettyPrint n (x@(Start _) : xs) = indent n >> p x >> putStrLn "" >> prettyPrint (n+1) xs+ prettyPrint n (x@(End _) : xs) = indent (n-1) >> p x >> putStrLn "" >> prettyPrint (n-1) xs+ prettyPrint n (x : xs) = indent n >> p x >> putStrLn "" >> prettyPrint n xs++ p (Boolean b) = putStr ("bool: " ++ show b)+ p (IntVal i) = putStr ("int: " ++ showHex i "")+ p (BitString bits) = putStr ("bitstring: " ++ (hexdump $ bitArrayGetData bits))+ p (OctetString bs) = putStr ("octetstring: " ++ hexdump bs)+ p (Null) = putStr "null"+ p (OID is) = putStr ("OID: " ++ show is)+ p (Real d) = putStr "real"+ p (Enumerated _) = putStr "enum"+ p (Start Sequence) = putStr "sequence"+ p (End Sequence) = putStr "end-sequence"+ p (Start Set) = putStr "set"+ p (End Set) = putStr "end-set"+ p (Start _) = putStr "container"+ p (End _) = putStr "end-container"+ p (ASN1String cs) = putCS cs+ p (ASN1Time TimeUTC time tz) = putStr ("utctime: " ++ show time)+ p (ASN1Time TimeGeneralized time tz) = putStr ("generalizedtime: " ++ show time)+ p (Other tc tn x) = putStr ("other(" ++ show tc ++ "," ++ show tn ++ ")")++ putCS (ASN1CharacterString UTF8 t) = putStr ("utf8string:" ++ show t)+ putCS (ASN1CharacterString Numeric bs) = putStr "numericstring:"+ putCS (ASN1CharacterString Printable t) = putStr ("printablestring: " ++ show t)+ putCS (ASN1CharacterString T61 bs) = putStr "t61string:"+ putCS (ASN1CharacterString VideoTex bs) = putStr "videotexstring:"+ putCS (ASN1CharacterString IA5 bs) = putStr "ia5string:"+ putCS (ASN1CharacterString Graphic bs) = putStr "graphicstring:"+ putCS (ASN1CharacterString Visible bs) = putStr "visiblestring:"+ putCS (ASN1CharacterString General bs) = putStr "generalstring:"+ putCS (ASN1CharacterString UTF32 t) = putStr ("universalstring:" ++ show t)+ putCS (ASN1CharacterString Character bs) = putStr "characterstring:"+ putCS (ASN1CharacterString BMP t) = putStr ("bmpstring: " ++ show t)++{-+ when (verify opts) $ getSystemCertificateStore >>= flip verifyCert x509+ where+ verifyCert store x509@(X509.X509 cert _ _ sigalg sig) = do+ case findCertificate (X509.certIssuerDN cert) store of+ Nothing -> putStrLn "couldn't find signing certificate"+ Just (X509.X509 syscert _ _ _ _) -> do+ verifyAlg (B.concat $ L.toChunks $ X509.getSigningData x509)+ (B.pack sig)+ sigalg+ (X509.certPubKey syscert)+-}++data X509Opts =+ DumpedRaw+ | DumpedText+ | ShowHash+ | Validate+ | ValidationHost String+ deriving (Show,Eq)++readPEMFile file = do+ content <- B.readFile file+ return $ either error id $ pemParseBS content++readSignedObject file = do+ content <- B.readFile file+ return $ either error (map (X509.decodeSignedObject . pemContent)) $ pemParseBS content++doCertMain opts files = do+ objs <- readSignedObject (head files)+ forM_ objs $ \o ->+ case o of+ Left err -> error ("decoding Certificate failed: " ++ show err)+ Right signed -> do+ showCert signed+ when (ShowHash `elem` opts) $ hashCert signed+ when (Validate `elem` opts) $ do+ let cc = CertificateChain (rights objs)+ store <- getSystemCertificateStore+ failed <- validate validationChecks store cc+ if failed /= []+ then putStrLn ("validation failed: " ++ show failed)+ else putStrLn "validation success"+ where+ hashCert signedCert = do+ putStrLn ("subject(MD5) old: " ++ hexdump' (X509.hashDN_old subject))+ putStrLn ("issuer(MD5) old: " ++ hexdump' (X509.hashDN_old issuer))+ putStrLn ("subject(SHA1): " ++ hexdump' (X509.hashDN subject))+ putStrLn ("issuer(SHA1): " ++ hexdump' (X509.hashDN issuer))+ where+ subject = X509.certSubjectDN cert+ issuer = X509.certIssuerDN cert+ cert = X509.signedObject $ X509.getSigned signedCert+ validationChecks = (defaultChecks "") { checkFQHN = foldl accHost Nothing opts+ , checkExhaustive = True+ }+ accHost Nothing (ValidationHost h) = Just h+ accHost a _ = a++doCRLMain opts files = do+ readSignedObject (head files) >>= \objs -> forM_ objs $ \o ->+ case o of+ Left err -> error ("decoding CRL failed: " ++ show err)+ Right signed -> do+ putStrLn $ show $ getCRL signed++doASN1Main files = do+ pem <- readPEMFile (head files)+ forM_ pem $ \p ->+ case decodeASN1' BER $ pemContent p of+ Left err -> error ("decoding ASN1 failed: " ++ show err)+ Right asn1 -> showASN1 0 asn1+ +doKeyMain files = do+ pems <- readPEMFile (head files)+ forM_ pems $ \pem -> do+ let content = either (error . show) id $ decodeASN1' BER (pemContent pem)+ case pemName pem of+ "RSA PRIVATE KEY" ->+ case fromASN1 content of+ Left err -> error ("not a valid RSA key: " ++ err)+ Right (k,_) -> putStrLn "RSA KEY" >> putStrLn (showRSAKey k)+ "DSA PRIVATE KEY" ->+ case fromASN1 content of+ Left err -> error ("not a valid DSA key: " ++ err)+ Right (k,_) -> putStrLn "DSA KEY" >> putStrLn (showDSAKey k)+ _ ->+ putStrLn ("unknown private key: " ++ show (pemName pem))++optionsCert =+ [ Option [] ["hash"] (NoArg ShowHash) "output certificate hash"+ , Option ['v'] ["validate"] (NoArg Validate) "validate certificate"+ , Option [] ["validation-host"] (ReqArg ValidationHost "host") "validation host use for validation"+ ]++certMain = getoptMain optionsCert $ \o n -> doCertMain o n+crlMain = getoptMain [] $ \o n -> doCRLMain o n+keyMain = getoptMain [] $ \o n -> doKeyMain n+asn1Main = getoptMain [] $ \o n -> doASN1Main n++getoptMain opts f as =+ case getOpt Permute opts as of+ (o,n,[]) -> f o n+ (_,_,err) -> error (show err)++usage = do+ putStrLn "usage: x509-util <cmd>"+ putStrLn " key : process public key"+ putStrLn " cert: process X509 certificate"+ putStrLn " crl : process CRL certificate"+ putStrLn " asn1: show file asn1"++main = do+ args <- getArgs+ case args of+ [] -> usage+ "x509":as -> certMain as+ "cert":as -> certMain as+ "key":as -> keyMain as+ "crl":as -> crlMain as+ "asn1":as -> asn1Main as+ _ -> usage
+ x509-util.cabal view
@@ -0,0 +1,37 @@+Name: x509-util+Version: 1.4.0+Description: utility to parse, show, validate, sign and produce X509 certificates and chain.+License: BSD3+License-file: LICENSE+Copyright: Vincent Hanquez <vincent@snarc.org>+Author: Vincent Hanquez <vincent@snarc.org>+Maintainer: Vincent Hanquez <vincent@snarc.org>+Synopsis: Utility for X509 certificate and chain+Build-Type: Simple+Category: Data+stability: experimental+Homepage: http://github.com/vincenthz/hs-certificate+Cabal-Version: >=1.6++Executable x509-util+ Main-Is: Certificate.hs+ hs-source-dirs: src+ Buildable: True+ Build-depends: base >= 3 && < 5+ , bytestring+ , text >= 0.11+ , crypto-pubkey-types+ , x509+ , x509-store+ , x509-system+ , x509-validation+ , asn1-types >= 0.2+ , asn1-encoding+ , pem+ , cryptohash+ , crypto-pubkey+ , directory++source-repository head+ type: git+ location: git://github.com/vincenthz/hs-certificate