summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2016-01-27 07:41:05 -0500
committerAndrew Cady <d@jerkface.net>2016-01-27 07:52:52 -0500
commit53840cb3e183bebead084a1ed550728b69ed88f3 (patch)
tree87c06ad89a22d6c589db7cdca1a1fc9b549237b0
parent552e6d79204cb6439c86ade4c1bf9bc785e47535 (diff)
remove Keys type from Network.ACME.Encoding
-rw-r--r--acme-certify.hs17
-rw-r--r--src/Network/ACME.hs71
-rw-r--r--src/Network/ACME/Encoding.hs24
3 files changed, 58 insertions, 54 deletions
diff --git a/acme-certify.hs b/acme-certify.hs
index 98f6711..352be21 100644
--- a/acme-certify.hs
+++ b/acme-certify.hs
@@ -12,22 +12,21 @@
12module Main where 12module Main where
13 13
14import BasePrelude 14import BasePrelude
15import Network.ACME (canProvision, certify, 15import Network.ACME (Keys (..), canProvision, certify,
16 ensureWritableDir, fileProvisioner, 16 ensureWritableDir, fileProvisioner,
17 genReq, (</>)) 17 genReq, readKeys, (</>))
18import Network.ACME.Encoding (Keys (..), readKeys) 18import Network.ACME.Issuer (letsEncryptX1CrossSigned)
19import Network.ACME.Issuer (letsEncryptX1CrossSigned)
20import Network.URI 19import Network.URI
21import OpenSSL 20import OpenSSL
22import OpenSSL.DH 21import OpenSSL.DH
23import OpenSSL.PEM 22import OpenSSL.PEM
24import OpenSSL.RSA 23import OpenSSL.RSA
25import OpenSSL.X509 (X509) 24import OpenSSL.X509 (X509)
26import Options.Applicative hiding (header) 25import Options.Applicative hiding (header)
27import qualified Options.Applicative as Opt 26import qualified Options.Applicative as Opt
28import System.Directory 27import System.Directory
29import System.IO 28import System.IO
30import Text.Domain.Validate hiding (validate) 29import Text.Domain.Validate hiding (validate)
31import Text.Email.Validate 30import Text.Email.Validate
32 31
33stagingDirectoryUrl, liveDirectoryUrl, defaultTerms :: URI 32stagingDirectoryUrl, liveDirectoryUrl, defaultTerms :: URI
diff --git a/src/Network/ACME.hs b/src/Network/ACME.hs
index 85a27e4..2734132 100644
--- a/src/Network/ACME.hs
+++ b/src/Network/ACME.hs
@@ -1,4 +1,5 @@
1{-# LANGUAGE FlexibleContexts #-} 1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE MultiParamTypeClasses #-}
2{-# LANGUAGE OverloadedStrings #-} 3{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE ScopedTypeVariables #-} 4{-# LANGUAGE ScopedTypeVariables #-}
4 5
@@ -9,41 +10,44 @@
9 10
10module Network.ACME where 11module Network.ACME where
11 12
12import Control.Lens hiding (each, (.=)) 13import Control.Arrow
14import Control.Error
15import Control.Lens hiding (each, (.=))
13import Control.Monad 16import Control.Monad
14import Control.Monad.RWS.Strict 17import Control.Monad.RWS.Strict
15import Data.Aeson (Value) 18import Control.Monad.Trans.Resource hiding (register)
16import Data.Aeson.Lens hiding (key) 19import Data.Aeson (Value)
17import qualified Data.Aeson.Lens as JSON 20import Data.Aeson.Lens hiding (key)
18import Data.ByteString (ByteString) 21import qualified Data.Aeson.Lens as JSON
19import qualified Data.ByteString.Char8 as BC 22import Data.ByteString (ByteString)
20import qualified Data.ByteString.Lazy as LB 23import qualified Data.ByteString.Char8 as BC
21import qualified Data.ByteString.Lazy.Char8 as LC 24import qualified Data.ByteString.Lazy as LB
25import qualified Data.ByteString.Lazy.Char8 as LC
22import Data.Coerce 26import Data.Coerce
23import Data.String (fromString) 27import Data.List
24import qualified Data.Text as T 28import Data.String (fromString)
25import Data.Text.Encoding (decodeUtf8, encodeUtf8) 29import qualified Data.Text as T
26import Data.Time.Clock.POSIX (getPOSIXTime) 30import Data.Text.Encoding (decodeUtf8, encodeUtf8)
31import Data.Time.Clock.POSIX (getPOSIXTime)
27import Network.ACME.Encoding 32import Network.ACME.Encoding
28import Network.Wreq (Response, checkStatus, defaults,
29 responseBody, responseHeader,
30 responseStatus, statusCode,
31 statusMessage)
32import qualified Network.Wreq as W
33import qualified Network.Wreq.Session as WS
34import System.Directory
35import Text.Email.Validate
36import Text.Domain.Validate hiding (validate)
37import Network.URI 33import Network.URI
34import Network.Wreq (Response, checkStatus, defaults,
35 responseBody, responseHeader,
36 responseStatus, statusCode,
37 statusMessage)
38import qualified Network.Wreq as W
39import qualified Network.Wreq.Session as WS
38import OpenSSL 40import OpenSSL
39import OpenSSL.EVP.Digest 41import OpenSSL.EVP.Digest
42import OpenSSL.EVP.PKey
43import OpenSSL.EVP.Sign hiding (sign)
44import OpenSSL.PEM
40import OpenSSL.RSA 45import OpenSSL.RSA
46import OpenSSL.X509 (X509, readDerX509)
41import OpenSSL.X509.Request 47import OpenSSL.X509.Request
42import OpenSSL.X509 (readDerX509, X509) 48import System.Directory
43import Data.List 49import Text.Domain.Validate hiding (validate)
44import Control.Error 50import Text.Email.Validate
45import Control.Arrow
46import Control.Monad.Trans.Resource hiding (register)
47 51
48genReq :: Keys -> [DomainName] -> IO CSR 52genReq :: Keys -> [DomainName] -> IO CSR
49genReq _ [] = error "genReq called with zero domains" 53genReq _ [] = error "genReq called with zero domains"
@@ -59,6 +63,21 @@ genReq (Keys priv pub) domains@(domain:_) = withOpenSSL $ do
59 where 63 where
60 nidSubjectAltName = 85 64 nidSubjectAltName = 85
61 65
66data Keys = Keys RSAKeyPair RSAPubKey
67readKeys :: String -> IO (Maybe Keys)
68readKeys privKeyData = do
69 keypair :: SomeKeyPair <- readPrivateKey privKeyData PwTTY
70 let (priv :: Maybe RSAKeyPair) = toKeyPair keypair
71 pub <- maybe (return Nothing) (fmap Just . rsaCopyPublic) priv
72 return $ Keys <$> priv <*> pub
73
74signPayload :: Keys -> String -> ByteString -> IO LC.ByteString
75signPayload (Keys priv pub) = signPayload' sign pub
76 where
77 sign x = do
78 Just dig <- getDigestByName "SHA256"
79 signBS dig priv x
80
62type HttpProvisioner = URI -> ByteString -> ResIO () 81type HttpProvisioner = URI -> ByteString -> ResIO ()
63fileProvisioner :: WritableDir -> HttpProvisioner 82fileProvisioner :: WritableDir -> HttpProvisioner
64fileProvisioner challengeDir uri thumbtoken = do 83fileProvisioner challengeDir uri thumbtoken = do
diff --git a/src/Network/ACME/Encoding.hs b/src/Network/ACME/Encoding.hs
index dc2c963..315ff49 100644
--- a/src/Network/ACME/Encoding.hs
+++ b/src/Network/ACME/Encoding.hs
@@ -3,8 +3,6 @@
3{-# LANGUAGE ScopedTypeVariables #-} 3{-# LANGUAGE ScopedTypeVariables #-}
4 4
5module Network.ACME.Encoding ( 5module Network.ACME.Encoding (
6 Keys(..),
7 readKeys,
8 thumbprint, 6 thumbprint,
9 JWK(..), 7 JWK(..),
10 toStrict, 8 toStrict,
@@ -12,7 +10,7 @@ module Network.ACME.Encoding (
12 challenge, 10 challenge,
13 registration, 11 registration,
14 authz, 12 authz,
15 signPayload, 13 signPayload',
16 ) where 14 ) where
17 15
18import Crypto.Number.Serialize (i2osp) 16import Crypto.Number.Serialize (i2osp)
@@ -27,29 +25,17 @@ import Data.Digest.Pure.SHA (bytestringDigest, sha256)
27import Data.Maybe 25import Data.Maybe
28import Data.Text.Encoding (decodeUtf8) 26import Data.Text.Encoding (decodeUtf8)
29import OpenSSL 27import OpenSSL
30import OpenSSL.EVP.Digest
31import OpenSSL.EVP.PKey
32import OpenSSL.EVP.Sign
33import OpenSSL.PEM
34import OpenSSL.RSA 28import OpenSSL.RSA
35import Text.Email.Validate 29import Text.Email.Validate
36import qualified Data.Text as T 30import qualified Data.Text as T
37 31
38data Keys = Keys RSAKeyPair RSAPubKey
39readKeys :: String -> IO (Maybe Keys)
40readKeys privKeyData = do
41 keypair :: SomeKeyPair <- readPrivateKey privKeyData PwTTY
42 let (priv :: Maybe RSAKeyPair) = toKeyPair keypair
43 pub <- maybe (return Nothing) (fmap Just . rsaCopyPublic) priv
44 return $ Keys <$> priv <*> pub
45
46-------------------------------------------------------------------------------- 32--------------------------------------------------------------------------------
47-- | Sign return a payload with a nonce-protected header. 33-- | Sign return a payload with a nonce-protected header.
48signPayload :: Keys -> String -> ByteString -> IO LC.ByteString 34
49signPayload (Keys priv pub) nonce_ payload = withOpenSSL $ do 35signPayload' :: (ByteString -> IO ByteString) -> RSAPubKey -> String -> ByteString -> IO LC.ByteString
36signPayload' sign pub nonce_ payload = withOpenSSL $ do
50 let protected = b64 (header pub nonce_) 37 let protected = b64 (header pub nonce_)
51 Just dig <- getDigestByName "SHA256" 38 sig <- b64 <$> sign (B.concat [protected, ".", payload])
52 sig <- b64 <$> signBS dig priv (B.concat [protected, ".", payload])
53 return $ encode (Request (header' pub) protected payload sig) 39 return $ encode (Request (header' pub) protected payload sig)
54 40
55-------------------------------------------------------------------------------- 41--------------------------------------------------------------------------------