summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2016-01-20 11:12:59 -0500
committerAndrew Cady <d@jerkface.net>2016-01-20 11:12:59 -0500
commitba128c5b8fedeb77e8d014b968884b570a698468 (patch)
tree18098e4f69f46cf57ea9eaa863f75efaefbceb67
parent010742ccd357994b2784a862378e6329a19147d2 (diff)
Generate signatures without external calls
-rw-r--r--acme.hs24
1 files changed, 15 insertions, 9 deletions
diff --git a/acme.hs b/acme.hs
index 57dafe6..82d728f 100644
--- a/acme.hs
+++ b/acme.hs
@@ -31,6 +31,9 @@ import Options.Applicative hiding (header)
31import qualified Options.Applicative as Opt 31import qualified Options.Applicative as Opt
32import System.Directory 32import System.Directory
33import System.Process (readProcess) 33import System.Process (readProcess)
34import OpenSSL.EVP.Sign
35import OpenSSL.EVP.Digest
36import OpenSSL
34 37
35directoryUrl :: String 38directoryUrl :: String
36directoryUrl = "https://acme-v01.api.letsencrypt.org/directory" 39directoryUrl = "https://acme-v01.api.letsencrypt.org/directory"
@@ -64,8 +67,8 @@ go :: CmdOpts -> IO ()
64go (CmdOpts privKeyFile domain email termOverride) = do 67go (CmdOpts privKeyFile domain email termOverride) = do
65 let terms = fromMaybe defaultTerms termOverride 68 let terms = fromMaybe defaultTerms termOverride
66 doesFileExist privKeyFile >>= flip unless (genKey privKeyFile) 69 doesFileExist privKeyFile >>= flip unless (genKey privKeyFile)
67 userKey_ <- readFile privKeyFile >>= flip readPrivateKey PwTTY 70 priv <- readFile privKeyFile >>= flip readPrivateKey PwTTY
68 pub <- maybe (return Nothing) (rsaCopyPublic >=> return . Just) (toKeyPair userKey_ :: Maybe RSAKeyPair) 71 pub <- maybe (return Nothing) (rsaCopyPublic >=> return . Just) (toKeyPair priv :: Maybe RSAKeyPair)
69 case pub of 72 case pub of
70 Nothing -> error "Error: failed to parse RSA key." 73 Nothing -> error "Error: failed to parse RSA key."
71 Just (userKey :: RSAPubKey) -> do 74 Just (userKey :: RSAPubKey) -> do
@@ -75,10 +78,10 @@ go (CmdOpts privKeyFile domain email termOverride) = do
75 let protected = b64 (header userKey nonce_) 78 let protected = b64 (header userKey nonce_)
76 79
77 -- Create user account 80 -- Create user account
78 forM_ email $ \m -> signPayload "registration" privKeyFile userKey protected (registration m terms) 81 forM_ email $ \m -> signPayload "registration" priv privKeyFile userKey protected (registration m terms)
79 82
80 -- Obtain a challenge 83 -- Obtain a challenge
81 signPayload "challenge-request" privKeyFile userKey protected (authz domain) 84 signPayload "challenge-request" priv privKeyFile userKey protected (authz domain)
82 85
83 -- Answser the challenge 86 -- Answser the challenge
84 let thumb = thumbprint (JWK (rsaE userKey) "RSA" (rsaN userKey)) 87 let thumb = thumbprint (JWK (rsaE userKey) "RSA" (rsaN userKey))
@@ -91,13 +94,13 @@ go (CmdOpts privKeyFile domain email termOverride) = do
91 putStrLn ("With content:\n" ++ BC.unpack thumbtoken) 94 putStrLn ("With content:\n" ++ BC.unpack thumbtoken)
92 95
93 -- Notify Let's Encrypt we answsered the challenge 96 -- Notify Let's Encrypt we answsered the challenge
94 signPayload "challenge-response" privKeyFile userKey protected (challenge thumbtoken) 97 signPayload "challenge-response" priv privKeyFile userKey protected (challenge thumbtoken)
95 98
96 -- Wait for challenge validation 99 -- Wait for challenge validation
97 100
98 -- Send a CSR and get a certificate 101 -- Send a CSR and get a certificate
99 csr_ <- B.readFile (domain ++ ".csr.der") 102 csr_ <- B.readFile (domain ++ ".csr.der")
100 signPayload "csr-request" privKeyFile userKey protected (csr csr_) 103 signPayload "csr-request" priv privKeyFile userKey protected (csr csr_)
101 104
102data Directory = Directory { 105data Directory = Directory {
103 _newCert :: String, 106 _newCert :: String,
@@ -119,11 +122,14 @@ getNonce = fmap _nonce <$> getDirectory directoryUrl
119 122
120-------------------------------------------------------------------------------- 123--------------------------------------------------------------------------------
121-- | Sign and write a payload to a file with a nonce-protected header. 124-- | Sign and write a payload to a file with a nonce-protected header.
122signPayload :: RSAKey k => String -> String -> k -> ByteString -> ByteString -> IO () 125signPayload :: (RSAKey k, KeyPair kp) => String -> kp -> String -> k -> ByteString -> ByteString -> IO ()
123signPayload name privKeyFile key protected payload = do 126signPayload name priv privKeyFile key protected payload = withOpenSSL $ do
124 writePayload name protected payload 127 writePayload name protected payload
125 sig <- sign privKeyFile name 128 sig <- Main.sign privKeyFile name
129 Just dig <- getDigestByName "SHA256"
130 sig' <- signBS dig priv (B.concat [protected, ".", payload])
126 writeBody name key protected payload sig 131 writeBody name key protected payload sig
132 writeBody (name ++ ".internal") key protected payload (b64 sig')
127 133
128-- | Write a payload to file with a nonce-protected header. 134-- | Write a payload to file with a nonce-protected header.
129writePayload :: String -> ByteString -> ByteString -> IO () 135writePayload :: String -> ByteString -> ByteString -> IO ()