File: Win32.hsc

package info (click to toggle)
haskell-hsopenssl-x509-system 0.1.0.4-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 76 kB
  • sloc: haskell: 94; makefile: 4
file content (89 lines) | stat: -rw-r--r-- 3,006 bytes parent folder | download | duplicates (5)
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
module OpenSSL.X509.SystemStore.Win32
    ( contextLoadSystemCerts
    ) where

import Control.Exception (bracket)
import Control.Monad (when, (>=>))
import OpenSSL.X509 (X509)
import qualified OpenSSL.Session as SSL
import qualified OpenSSL.PEM as SSL
import qualified OpenSSL.X509.Store as SSL
import qualified OpenSSL.EVP.Base64 as SSL
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C8

import Foreign (Ptr, nullPtr, peekByteOff)
import System.Win32.Types (DWORD, BOOL, LPCTSTR, withTString)

contextLoadSystemCerts :: SSL.SSLContext -> IO () 
contextLoadSystemCerts ctx = do
    st <- SSL.contextGetCAStore ctx
    iterCertStoreX509 "ROOT" (SSL.addCertToStore st)

iterCertStoreX509 :: String -> (X509 -> IO ()) -> IO ()
iterCertStoreX509 subsystemProtocol action =
    iterCertStorePEM subsystemProtocol (SSL.readX509 >=> action)

iterCertStorePEM :: String -> (String -> IO ()) -> IO ()
iterCertStorePEM subsystemProtocol action =
    iterCertStoreDER subsystemProtocol (action . derToPem)

iterCertStoreDER :: String -> (B.ByteString -> IO ()) -> IO ()
iterCertStoreDER subsystemProtocol action =
    withTString subsystemProtocol $ \ssProtPtr ->
        bracket
            (certOpenSystemStore nullPtr ssProtPtr)
            (flip certCloseStore 0)
            (loop nullPtr)
  where
    loop prevCertCtx certStore = do
        certCtx <- certEnumCertificatesInStore certStore prevCertCtx
        when (certCtx /= nullPtr) $ do
            certEncType <- (#peek struct _CERT_CONTEXT, dwCertEncodingType) certCtx
            when (certEncType == x509EncType) $ do
                len <- (#peek struct _CERT_CONTEXT, cbCertEncoded) certCtx :: IO DWORD
                certBuf <- (#peek struct _CERT_CONTEXT, pbCertEncoded) certCtx
                cert <- B.packCStringLen (certBuf, fromIntegral len)
                action cert
                loop certCtx certStore

derToPem :: B.ByteString -> String
derToPem der = unlines ([beginCert] ++ ls ++ [endCert])
  where
    ls = map C8.unpack $ splitChunks $ SSL.encodeBase64BS der
    splitChunks s
        | B.null s = []
        | otherwise = chunk : splitChunks rest
          where
            (chunk, rest) = B.splitAt 64 s
    beginCert = "-----BEGIN CERTIFICATE-----"
    endCert = "-----END CERTIFICATE-----"

--------------------------------------------------------------------------------

#include <windows.h>
#include <Wincrypt.h>

data HCERTSTORE

data PCCERT_CONTEXT

data HCRYPTPROV_LEGACY

foreign import stdcall unsafe "CertOpenSystemStoreW"
    certOpenSystemStore
        :: Ptr HCRYPTPROV_LEGACY
        -> LPCTSTR
        -> IO (Ptr HCERTSTORE)

foreign import stdcall unsafe "CertCloseStore"
    certCloseStore :: Ptr HCERTSTORE -> DWORD -> IO BOOL

foreign import stdcall unsafe "CertEnumCertificatesInStore"
    certEnumCertificatesInStore
        :: Ptr HCERTSTORE
        -> Ptr PCCERT_CONTEXT
        -> IO (Ptr PCCERT_CONTEXT)

x509EncType :: DWORD
x509EncType = (#const X509_ASN_ENCODING)