summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2016-01-27 07:27:59 -0500
committerAndrew Cady <d@jerkface.net>2016-01-27 07:27:59 -0500
commit552e6d79204cb6439c86ade4c1bf9bc785e47535 (patch)
tree56ab37fc1ab02c9687e7fe1a4c86cd2efa216c1b
parenteaaebe924ba1cebc40a160a28f3779fd08c2181b (diff)
Embed issuer certificate in binary
This permits the program to be run from outside the source directory.
-rw-r--r--acme-certify.cabal4
-rw-r--r--acme-certify.hs23
-rw-r--r--src/Network/ACME/Issuer.hs9
3 files changed, 21 insertions, 15 deletions
diff --git a/acme-certify.cabal b/acme-certify.cabal
index 01b0e7d..42c4192 100644
--- a/acme-certify.cabal
+++ b/acme-certify.cabal
@@ -13,12 +13,12 @@ cabal-version: >=1.10
13 13
14library 14library
15 hs-source-dirs: src 15 hs-source-dirs: src
16 exposed-modules: Network.ACME, Network.ACME.Encoding 16 exposed-modules: Network.ACME, Network.ACME.Encoding, Network.ACME.Issuer
17 build-depends: base >= 4.7 && < 5, 17 build-depends: base >= 4.7 && < 5,
18 cryptonite, aeson, bytestring, base64-bytestring, SHA, 18 cryptonite, aeson, bytestring, base64-bytestring, SHA,
19 mtl, text, HsOpenSSL, wreq, lens, lens-aeson, time, 19 mtl, text, HsOpenSSL, wreq, lens, lens-aeson, time,
20 email-validate, pipes, directory, network-uri, errors, 20 email-validate, pipes, directory, network-uri, errors,
21 resourcet 21 resourcet, file-embed
22 default-language: Haskell2010 22 default-language: Haskell2010
23 23
24executable acme-certify 24executable acme-certify
diff --git a/acme-certify.hs b/acme-certify.hs
index 219b0c1..98f6711 100644
--- a/acme-certify.hs
+++ b/acme-certify.hs
@@ -16,6 +16,7 @@ import Network.ACME (canProvision, certify,
16 ensureWritableDir, fileProvisioner, 16 ensureWritableDir, fileProvisioner,
17 genReq, (</>)) 17 genReq, (</>))
18import Network.ACME.Encoding (Keys (..), readKeys) 18import Network.ACME.Encoding (Keys (..), readKeys)
19import Network.ACME.Issuer (letsEncryptX1CrossSigned)
19import Network.URI 20import Network.URI
20import OpenSSL 21import OpenSSL
21import OpenSSL.DH 22import OpenSSL.DH
@@ -29,9 +30,10 @@ import System.IO
29import Text.Domain.Validate hiding (validate) 30import Text.Domain.Validate hiding (validate)
30import Text.Email.Validate 31import Text.Email.Validate
31 32
32stagingDirectoryUrl, liveDirectoryUrl :: URI 33stagingDirectoryUrl, liveDirectoryUrl, defaultTerms :: URI
33Just liveDirectoryUrl = parseAbsoluteURI "https://acme-v01.api.letsencrypt.org/directory" 34Just liveDirectoryUrl = parseAbsoluteURI "https://acme-v01.api.letsencrypt.org/directory"
34Just stagingDirectoryUrl = parseAbsoluteURI "https://acme-staging.api.letsencrypt.org/directory" 35Just stagingDirectoryUrl = parseAbsoluteURI "https://acme-staging.api.letsencrypt.org/directory"
36Just defaultTerms = parseAbsoluteURI "https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
35 37
36main :: IO () 38main :: IO ()
37main = execParser opts >>= go 39main = execParser opts >>= go
@@ -54,9 +56,6 @@ data CmdOpts = CmdOpts {
54 optSkipProvisionCheck :: Bool 56 optSkipProvisionCheck :: Bool
55} 57}
56 58
57defaultTerms :: URI
58Just defaultTerms = parseAbsoluteURI "https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
59
60cmdopts :: Parser CmdOpts 59cmdopts :: Parser CmdOpts
61cmdopts = CmdOpts <$> strOption (long "key" <> metavar "FILE" <> 60cmdopts = CmdOpts <$> strOption (long "key" <> metavar "FILE" <>
62 help "Filename of your private RSA key") 61 help "Filename of your private RSA key")
@@ -111,26 +110,24 @@ go CmdOpts { .. } = do
111 domainDir = fromMaybe (head optDomains) optDomainDir 110 domainDir = fromMaybe (head optDomains) optDomainDir
112 privKeyFile = optKeyFile 111 privKeyFile = optKeyFile
113 requestDomains = map domainName' optDomains 112 requestDomains = map domainName' optDomains
113 email = either (error . ("Error: invalid email address: " ++)) id . validate . fromString <$> optEmail
114 114
115 doesDirectoryExist domainDir `otherwiseM` createDirectory domainDir 115 issuerCert <- readX509 letsEncryptX1CrossSigned
116 116
117 let issuerCertFile = "lets-encrypt-x1-cross-signed.pem" 117 seq email (return ())
118 issuerCert <- readFile issuerCertFile >>= readX509 118 doesDirectoryExist domainDir `otherwiseM` createDirectory domainDir
119 challengeDir <- ensureWritableDir optChallengeDir "challenge directory"
120 void $ ensureWritableDir domainDir "domain directory"
119 121
120 Just domainKeys <- getOrCreateKeys domainKeyFile 122 Just domainKeys <- getOrCreateKeys domainKeyFile
121 Just keys <- getOrCreateKeys privKeyFile 123 Just keys <- getOrCreateKeys privKeyFile
122 124
123 challengeDir <- ensureWritableDir optChallengeDir "challenge directory"
124 void $ ensureWritableDir domainDir "domain directory"
125
126 unless optSkipProvisionCheck $ 125 unless optSkipProvisionCheck $
127 forM_ requestDomains $ canProvision challengeDir >=> 126 forM_ requestDomains $ canProvision challengeDir >=>
128 (`unless` error "Error: cannot provision files to web server via challenge directory") 127 (`unless` error "Error: cannot provision files to web server via challenge directory")
129 128
130 certReq <- genReq domainKeys requestDomains 129 certReq <- genReq domainKeys requestDomains
131 130
132 let email = either (error . ("Error: invalid email address: " ++)) id . validate . fromString <$> optEmail
133
134 dh <- if optSkipDH then return Nothing else Just <$> getOrCreateDH domainDhFile 131 dh <- if optSkipDH then return Nothing else Just <$> getOrCreateDH domainDhFile
135 132
136 certificate <- certify directoryUrl keys ((,) terms <$> email) (fileProvisioner challengeDir) certReq 133 certificate <- certify directoryUrl keys ((,) terms <$> email) (fileProvisioner challengeDir) certReq
diff --git a/src/Network/ACME/Issuer.hs b/src/Network/ACME/Issuer.hs
new file mode 100644
index 0000000..451aa14
--- /dev/null
+++ b/src/Network/ACME/Issuer.hs
@@ -0,0 +1,9 @@
1{-# LANGUAGE TemplateHaskell #-}
2
3module Network.ACME.Issuer where
4
5import Data.ByteString.Char8
6import Data.FileEmbed
7
8letsEncryptX1CrossSigned :: String
9letsEncryptX1CrossSigned = unpack $(embedFile "lets-encrypt-x1-cross-signed.pem")