diff options
author | Andrew Cady <d@jerkface.net> | 2016-01-27 07:41:05 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2016-01-27 07:52:52 -0500 |
commit | 53840cb3e183bebead084a1ed550728b69ed88f3 (patch) | |
tree | 87c06ad89a22d6c589db7cdca1a1fc9b549237b0 | |
parent | 552e6d79204cb6439c86ade4c1bf9bc785e47535 (diff) |
remove Keys type from Network.ACME.Encoding
-rw-r--r-- | acme-certify.hs | 17 | ||||
-rw-r--r-- | src/Network/ACME.hs | 71 | ||||
-rw-r--r-- | src/Network/ACME/Encoding.hs | 24 |
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 @@ | |||
12 | module Main where | 12 | module Main where |
13 | 13 | ||
14 | import BasePrelude | 14 | import BasePrelude |
15 | import Network.ACME (canProvision, certify, | 15 | import Network.ACME (Keys (..), canProvision, certify, |
16 | ensureWritableDir, fileProvisioner, | 16 | ensureWritableDir, fileProvisioner, |
17 | genReq, (</>)) | 17 | genReq, readKeys, (</>)) |
18 | import Network.ACME.Encoding (Keys (..), readKeys) | 18 | import Network.ACME.Issuer (letsEncryptX1CrossSigned) |
19 | import Network.ACME.Issuer (letsEncryptX1CrossSigned) | ||
20 | import Network.URI | 19 | import Network.URI |
21 | import OpenSSL | 20 | import OpenSSL |
22 | import OpenSSL.DH | 21 | import OpenSSL.DH |
23 | import OpenSSL.PEM | 22 | import OpenSSL.PEM |
24 | import OpenSSL.RSA | 23 | import OpenSSL.RSA |
25 | import OpenSSL.X509 (X509) | 24 | import OpenSSL.X509 (X509) |
26 | import Options.Applicative hiding (header) | 25 | import Options.Applicative hiding (header) |
27 | import qualified Options.Applicative as Opt | 26 | import qualified Options.Applicative as Opt |
28 | import System.Directory | 27 | import System.Directory |
29 | import System.IO | 28 | import System.IO |
30 | import Text.Domain.Validate hiding (validate) | 29 | import Text.Domain.Validate hiding (validate) |
31 | import Text.Email.Validate | 30 | import Text.Email.Validate |
32 | 31 | ||
33 | stagingDirectoryUrl, liveDirectoryUrl, defaultTerms :: URI | 32 | stagingDirectoryUrl, 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 | ||
10 | module Network.ACME where | 11 | module Network.ACME where |
11 | 12 | ||
12 | import Control.Lens hiding (each, (.=)) | 13 | import Control.Arrow |
14 | import Control.Error | ||
15 | import Control.Lens hiding (each, (.=)) | ||
13 | import Control.Monad | 16 | import Control.Monad |
14 | import Control.Monad.RWS.Strict | 17 | import Control.Monad.RWS.Strict |
15 | import Data.Aeson (Value) | 18 | import Control.Monad.Trans.Resource hiding (register) |
16 | import Data.Aeson.Lens hiding (key) | 19 | import Data.Aeson (Value) |
17 | import qualified Data.Aeson.Lens as JSON | 20 | import Data.Aeson.Lens hiding (key) |
18 | import Data.ByteString (ByteString) | 21 | import qualified Data.Aeson.Lens as JSON |
19 | import qualified Data.ByteString.Char8 as BC | 22 | import Data.ByteString (ByteString) |
20 | import qualified Data.ByteString.Lazy as LB | 23 | import qualified Data.ByteString.Char8 as BC |
21 | import qualified Data.ByteString.Lazy.Char8 as LC | 24 | import qualified Data.ByteString.Lazy as LB |
25 | import qualified Data.ByteString.Lazy.Char8 as LC | ||
22 | import Data.Coerce | 26 | import Data.Coerce |
23 | import Data.String (fromString) | 27 | import Data.List |
24 | import qualified Data.Text as T | 28 | import Data.String (fromString) |
25 | import Data.Text.Encoding (decodeUtf8, encodeUtf8) | 29 | import qualified Data.Text as T |
26 | import Data.Time.Clock.POSIX (getPOSIXTime) | 30 | import Data.Text.Encoding (decodeUtf8, encodeUtf8) |
31 | import Data.Time.Clock.POSIX (getPOSIXTime) | ||
27 | import Network.ACME.Encoding | 32 | import Network.ACME.Encoding |
28 | import Network.Wreq (Response, checkStatus, defaults, | ||
29 | responseBody, responseHeader, | ||
30 | responseStatus, statusCode, | ||
31 | statusMessage) | ||
32 | import qualified Network.Wreq as W | ||
33 | import qualified Network.Wreq.Session as WS | ||
34 | import System.Directory | ||
35 | import Text.Email.Validate | ||
36 | import Text.Domain.Validate hiding (validate) | ||
37 | import Network.URI | 33 | import Network.URI |
34 | import Network.Wreq (Response, checkStatus, defaults, | ||
35 | responseBody, responseHeader, | ||
36 | responseStatus, statusCode, | ||
37 | statusMessage) | ||
38 | import qualified Network.Wreq as W | ||
39 | import qualified Network.Wreq.Session as WS | ||
38 | import OpenSSL | 40 | import OpenSSL |
39 | import OpenSSL.EVP.Digest | 41 | import OpenSSL.EVP.Digest |
42 | import OpenSSL.EVP.PKey | ||
43 | import OpenSSL.EVP.Sign hiding (sign) | ||
44 | import OpenSSL.PEM | ||
40 | import OpenSSL.RSA | 45 | import OpenSSL.RSA |
46 | import OpenSSL.X509 (X509, readDerX509) | ||
41 | import OpenSSL.X509.Request | 47 | import OpenSSL.X509.Request |
42 | import OpenSSL.X509 (readDerX509, X509) | 48 | import System.Directory |
43 | import Data.List | 49 | import Text.Domain.Validate hiding (validate) |
44 | import Control.Error | 50 | import Text.Email.Validate |
45 | import Control.Arrow | ||
46 | import Control.Monad.Trans.Resource hiding (register) | ||
47 | 51 | ||
48 | genReq :: Keys -> [DomainName] -> IO CSR | 52 | genReq :: Keys -> [DomainName] -> IO CSR |
49 | genReq _ [] = error "genReq called with zero domains" | 53 | genReq _ [] = 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 | ||
66 | data Keys = Keys RSAKeyPair RSAPubKey | ||
67 | readKeys :: String -> IO (Maybe Keys) | ||
68 | readKeys 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 | |||
74 | signPayload :: Keys -> String -> ByteString -> IO LC.ByteString | ||
75 | signPayload (Keys priv pub) = signPayload' sign pub | ||
76 | where | ||
77 | sign x = do | ||
78 | Just dig <- getDigestByName "SHA256" | ||
79 | signBS dig priv x | ||
80 | |||
62 | type HttpProvisioner = URI -> ByteString -> ResIO () | 81 | type HttpProvisioner = URI -> ByteString -> ResIO () |
63 | fileProvisioner :: WritableDir -> HttpProvisioner | 82 | fileProvisioner :: WritableDir -> HttpProvisioner |
64 | fileProvisioner challengeDir uri thumbtoken = do | 83 | fileProvisioner 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 | ||
5 | module Network.ACME.Encoding ( | 5 | module 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 | ||
18 | import Crypto.Number.Serialize (i2osp) | 16 | import Crypto.Number.Serialize (i2osp) |
@@ -27,29 +25,17 @@ import Data.Digest.Pure.SHA (bytestringDigest, sha256) | |||
27 | import Data.Maybe | 25 | import Data.Maybe |
28 | import Data.Text.Encoding (decodeUtf8) | 26 | import Data.Text.Encoding (decodeUtf8) |
29 | import OpenSSL | 27 | import OpenSSL |
30 | import OpenSSL.EVP.Digest | ||
31 | import OpenSSL.EVP.PKey | ||
32 | import OpenSSL.EVP.Sign | ||
33 | import OpenSSL.PEM | ||
34 | import OpenSSL.RSA | 28 | import OpenSSL.RSA |
35 | import Text.Email.Validate | 29 | import Text.Email.Validate |
36 | import qualified Data.Text as T | 30 | import qualified Data.Text as T |
37 | 31 | ||
38 | data Keys = Keys RSAKeyPair RSAPubKey | ||
39 | readKeys :: String -> IO (Maybe Keys) | ||
40 | readKeys 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. |
48 | signPayload :: Keys -> String -> ByteString -> IO LC.ByteString | 34 | |
49 | signPayload (Keys priv pub) nonce_ payload = withOpenSSL $ do | 35 | signPayload' :: (ByteString -> IO ByteString) -> RSAPubKey -> String -> ByteString -> IO LC.ByteString |
36 | signPayload' 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 | -------------------------------------------------------------------------------- |