Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ examples/Server

.cabal-sandbox
cabal.sandbox.config
.stack-work/
2 changes: 1 addition & 1 deletion HsOpenSSL.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Library
bytestring >= 0.9 && < 0.11,
network >= 2.1 && < 2.7,
old-locale >= 1.0 && < 1.1,
time >= 1.1.1 && < 1.6
time >= 1.1.1 && < 1.9
-- old-locale is only needed if time < 1.5, but Cabal does not
-- allow us to express conditional dependencies like this.

Expand Down
40 changes: 40 additions & 0 deletions OpenSSL/X509.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ module OpenSSL.X509
, unsafeX509ToPtr -- private
, touchX509 -- private

, writeDerX509
, readDerX509
, compareX509

, signX509
Expand Down Expand Up @@ -68,6 +70,7 @@ import OpenSSL.EVP.Internal
import OpenSSL.Utils
import OpenSSL.Stack
import OpenSSL.X509.Name
import Data.ByteString.Lazy (ByteString)

-- |@'X509'@ is an opaque object that represents X.509 certificate.
newtype X509 = X509 (ForeignPtr X509_)
Expand Down Expand Up @@ -140,6 +143,16 @@ foreign import ccall unsafe "X509_sign"
foreign import ccall unsafe "X509_verify"
_verify :: Ptr X509_ -> Ptr EVP_PKEY -> IO CInt

foreign import ccall safe "i2d_X509_bio"
_write_bio_X509 :: Ptr BIO_
-> Ptr X509_
-> IO CInt

foreign import ccall safe "d2i_X509_bio"
_read_bio_X509 :: Ptr BIO_
-> Ptr (Ptr X509_)
-> IO (Ptr X509_)

-- |@'newX509'@ creates an empty certificate. You must set the
-- following properties to and sign it (see 'signX509') to actually
-- use the certificate.
Expand Down Expand Up @@ -179,6 +192,33 @@ unsafeX509ToPtr (X509 x509) = Unsafe.unsafeForeignPtrToPtr x509
touchX509 :: X509 -> IO ()
touchX509 (X509 x509) = touchForeignPtr x509

writeX509' :: BIO -> X509 -> IO ()
writeX509' bio x509
= withBioPtr bio $ \ bioPtr ->
withX509Ptr x509 $ \ x509Ptr ->
_write_bio_X509 bioPtr x509Ptr
>>= failIf (< 0)
>> return ()

-- |@'writeDerX509' cert@ writes an X.509 certificate to DER string.
writeDerX509 :: X509 -> IO ByteString
writeDerX509 x509
= do mem <- newMem
writeX509' mem x509
bioReadLBS mem

readX509' :: BIO -> IO X509
readX509' bio
= withBioPtr bio $ \ bioPtr ->
_read_bio_X509 bioPtr nullPtr
>>= failIfNull
>>= wrapX509

-- |@'readDerX509' der@ reads in a certificate.
readDerX509 :: ByteString -> IO X509
readDerX509 derStr
= newConstMemLBS derStr >>= readX509'

-- |@'compareX509' cert1 cert2@ compares two certificates.
compareX509 :: X509 -> X509 -> IO Ordering
compareX509 cert1 cert2
Expand Down
44 changes: 44 additions & 0 deletions OpenSSL/X509/Request.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module OpenSSL.X509.Request
, verifyX509Req

, printX509Req
, writeX509ReqDER

, makeX509FromReq

Expand All @@ -28,6 +29,8 @@ module OpenSSL.X509.Request

, getPublicKey
, setPublicKey

, addExtensions
)
where

Expand All @@ -44,12 +47,15 @@ import OpenSSL.Utils
import OpenSSL.X509 (X509)
import qualified OpenSSL.X509 as Cert
import OpenSSL.X509.Name
import Data.ByteString.Lazy (ByteString)
import OpenSSL.Stack

-- |@'X509Req'@ is an opaque object that represents PKCS#10
-- certificate request.
newtype X509Req = X509Req (ForeignPtr X509_REQ)
data X509_REQ

data X509_EXT

foreign import ccall unsafe "X509_REQ_new"
_new :: IO (Ptr X509_REQ)
Expand All @@ -66,6 +72,9 @@ foreign import ccall unsafe "X509_REQ_verify"
foreign import ccall unsafe "X509_REQ_print"
_print :: Ptr BIO_ -> Ptr X509_REQ -> IO CInt

foreign import ccall unsafe "i2d_X509_REQ_bio"
_req_to_der :: Ptr BIO_ -> Ptr X509_REQ -> IO CInt

foreign import ccall unsafe "HsOpenSSL_X509_REQ_get_version"
_get_version :: Ptr X509_REQ -> IO CLong

Expand All @@ -84,6 +93,13 @@ foreign import ccall unsafe "X509_REQ_get_pubkey"
foreign import ccall unsafe "X509_REQ_set_pubkey"
_set_pubkey :: Ptr X509_REQ -> Ptr EVP_PKEY -> IO CInt

foreign import ccall unsafe "X509V3_EXT_nconf_nid"
_ext_create :: Ptr a -> Ptr b -> CInt -> CString -> IO (Ptr X509_EXT)

foreign import ccall unsafe "X509_REQ_add_extensions"
_req_add_extensions :: Ptr X509_REQ -> Ptr STACK -> IO CInt


-- |@'newX509Req'@ creates an empty certificate request. You must set
-- the following properties to and sign it (see 'signX509Req') to
-- actually use the certificate request.
Expand Down Expand Up @@ -152,6 +168,19 @@ printX509Req req
>>= failIf_ (/= 1)
bioRead mem

{- DER encoding ------------------------------------------------------------- -}

-- |@'writeX509ReqDER' req@ writes a PKCS#10 certificate request to DER string.
writeX509ReqDER :: X509Req -> IO ByteString
writeX509ReqDER req
= do mem <- newMem
withBioPtr mem $ \ memPtr ->
withX509ReqPtr req $ \ reqPtr ->
_req_to_der memPtr reqPtr
>>= failIf_ (< 0)
bioReadLBS mem


-- |@'getVersion' req@ returns the version number of certificate
-- request.
getVersion :: X509Req -> IO Int
Expand Down Expand Up @@ -211,6 +240,21 @@ setPublicKey req pkey
>> return ()


-- |@'addExtensions' req [(nid, str)]@
--
-- E.g., nid 85 = 'subjectAltName' http://osxr.org:8080/openssl/source/crypto/objects/objects.h#0476
--
-- (TODO: more docs; NID type)
addExtensions :: X509Req -> [(Int, String)] -> IO CInt
addExtensions req exts =
withX509ReqPtr req $ \reqPtr -> do
extPtrs <- forM exts make
withStack extPtrs $ _req_add_extensions reqPtr

where
make (nid, str) = withCString str $ _ext_create nullPtr nullPtr (fromIntegral nid)


-- |@'makeX509FromReq' req cert@ creates an empty X.509 certificate
-- and copies as much data from the request as possible. The resulting
-- certificate doesn't have the following data and it isn't signed so
Expand Down
8 changes: 8 additions & 0 deletions stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resolver: lts-8.3

packages:
- '.'

flags:
HsOpenSSL:
fast-bignum: false