File: Store.hsc

package info (click to toggle)
haskell-hsopenssl 0.11.7.8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 556 kB
  • sloc: haskell: 1,562; ansic: 451; makefile: 16
file content (153 lines) | stat: -rw-r--r-- 5,237 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
{-# LANGUAGE EmptyDataDecls           #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CApiFFI                  #-}
{-# OPTIONS_HADDOCK prune             #-}
-- |An interface to X.509 certificate store.
module OpenSSL.X509.Store
    ( X509Store
    , X509_STORE -- private

    , newX509Store

    , wrapX509Store -- private
    , withX509StorePtr -- private

    , addCertToStore
    , addCRLToStore

    , X509StoreCtx
    , X509_STORE_CTX -- private

    , withX509StoreCtxPtr -- private
    , wrapX509StoreCtx -- private

    , getStoreCtxCert
    , getStoreCtxIssuer
    , getStoreCtxCRL
    , getStoreCtxChain
    )
    where
#include "HsOpenSSL.h"
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Control.Exception (throwIO, mask_)
import Foreign
import Foreign.C
import Foreign.Concurrent as FC
import OpenSSL.X509
import OpenSSL.X509.Revocation
import OpenSSL.Stack
import OpenSSL.Utils

-- |@'X509Store'@ is an opaque object that represents X.509
-- certificate store. The certificate store is usually used for chain
-- verification.
newtype X509Store  = X509Store (ForeignPtr X509_STORE)
data {-# CTYPE "openssl/x509.h" "X509_STORE" #-} X509_STORE


foreign import capi unsafe "openssl/x509.h X509_STORE_new"
        _new :: IO (Ptr X509_STORE)

foreign import capi unsafe "openssl/x509.h X509_STORE_free"
        _free :: Ptr X509_STORE -> IO ()

foreign import capi unsafe "openssl/x509.h X509_STORE_add_cert"
        _add_cert :: Ptr X509_STORE -> Ptr X509_ -> IO CInt

foreign import capi unsafe "openssl/x509.h X509_STORE_add_crl"
        _add_crl :: Ptr X509_STORE -> Ptr X509_CRL -> IO CInt

-- |@'newX509Store'@ creates an empty X.509 certificate store.
newX509Store :: IO X509Store
newX509Store = _new
               >>= failIfNull
               >>= \ ptr -> wrapX509Store (_free ptr) ptr

wrapX509Store :: IO () -> Ptr X509_STORE -> IO X509Store
wrapX509Store finaliser ptr
    = do fp <- newForeignPtr_ ptr
         FC.addForeignPtrFinalizer fp finaliser
         return $ X509Store fp

withX509StorePtr :: X509Store -> (Ptr X509_STORE -> IO a) -> IO a
withX509StorePtr (X509Store store)
    = withForeignPtr store

-- |@'addCertToStore' store cert@ adds a certificate to store.
addCertToStore :: X509Store -> X509 -> IO ()
addCertToStore store cert
    = withX509StorePtr store $ \ storePtr ->
      withX509Ptr cert       $ \ certPtr  ->
      _add_cert storePtr certPtr
           >>= failIf (/= 1)
           >>  return ()

-- |@'addCRLToStore' store crl@ adds a revocation list to store.
addCRLToStore :: X509Store -> CRL -> IO ()
addCRLToStore store crl
    = withX509StorePtr store $ \ storePtr ->
      withCRLPtr crl         $ \ crlPtr   ->
      _add_crl storePtr crlPtr
           >>= failIf (/= 1)
           >>  return ()

data {-# CTYPE "openssl/x509.h" "X509_STORE_CTX" #-} X509_STORE_CTX
newtype X509StoreCtx = X509StoreCtx (ForeignPtr X509_STORE_CTX)

foreign import capi unsafe "openssl/x509.h X509_STORE_CTX_get_current_cert"
  _store_ctx_get_current_cert :: Ptr X509_STORE_CTX -> IO (Ptr X509_)

foreign import capi unsafe "HsOpenSSL.h HsOpenSSL_X509_STORE_CTX_get0_current_issuer"
  _store_ctx_get0_current_issuer :: Ptr X509_STORE_CTX -> IO (Ptr X509_)

foreign import capi unsafe "HsOpenSSL.h HsOpenSSL_X509_STORE_CTX_get0_current_crl"
  _store_ctx_get0_current_crl :: Ptr X509_STORE_CTX -> IO (Ptr X509_CRL)

#if OPENSSL_VERSION_NUMBER >= 0x10100000L
foreign import capi unsafe "openssl/x509.h X509_STORE_CTX_get1_chain"
  _store_ctx_get_chain :: Ptr X509_STORE_CTX -> IO (Ptr STACK)
#else
foreign import capi unsafe "openssl/x509.h X509_STORE_CTX_get_chain"
  _store_ctx_get_chain :: Ptr X509_STORE_CTX -> IO (Ptr STACK)
#endif

foreign import capi unsafe "HsOpenSSL.h HsOpenSSL_X509_ref"
  _x509_ref :: Ptr X509_ -> IO ()

foreign import capi unsafe "HsOpenSSL.h HsOpenSSL_X509_CRL_ref"
  _crl_ref :: Ptr X509_CRL -> IO ()

withX509StoreCtxPtr :: X509StoreCtx -> (Ptr X509_STORE_CTX -> IO a) -> IO a
withX509StoreCtxPtr (X509StoreCtx fp) = withForeignPtr fp

wrapX509StoreCtx :: IO () -> Ptr X509_STORE_CTX -> IO X509StoreCtx
wrapX509StoreCtx finaliser ptr =
  X509StoreCtx <$> FC.newForeignPtr ptr finaliser

getStoreCtxCert :: X509StoreCtx -> IO X509
getStoreCtxCert ctx = withX509StoreCtxPtr ctx $ \pCtx -> do
  pCert <- _store_ctx_get_current_cert pCtx
  if pCert == nullPtr
    then throwIO $ userError "BUG: NULL certificate in X509_STORE_CTX"
    else mask_ $ _x509_ref pCert >> wrapX509 pCert

getStoreCtxIssuer :: X509StoreCtx -> IO (Maybe X509)
getStoreCtxIssuer ctx = withX509StoreCtxPtr ctx $ \pCtx -> do
  pCert <- _store_ctx_get0_current_issuer pCtx
  if pCert == nullPtr
    then return Nothing
    else fmap Just $ mask_ $ _x509_ref pCert >> wrapX509 pCert

getStoreCtxCRL :: X509StoreCtx -> IO (Maybe CRL)
getStoreCtxCRL ctx = withX509StoreCtxPtr ctx $ \pCtx -> do
  pCrl <- _store_ctx_get0_current_crl pCtx
  if pCrl == nullPtr
    then return Nothing
    else fmap Just $ mask_ $ _crl_ref pCrl >> wrapCRL pCrl

getStoreCtxChain :: X509StoreCtx -> IO [X509]
getStoreCtxChain ctx = withX509StoreCtxPtr ctx $ \pCtx -> do
  stack <- _store_ctx_get_chain pCtx
  (`mapStack` stack) $ \pCert -> mask_ $ _x509_ref pCert >> wrapX509 pCert