-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.go
139 lines (123 loc) · 3.63 KB
/
config.go
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"crypto"
"crypto/x509"
"encoding/pem"
"flag"
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
)
// Config represents the configuration options for coyote.
var Config struct {
Server *url.URL
AccountKey crypto.Signer
AccountEmail string
AccountTerms string
ChallengeDir string
CSR *x509.CertificateRequest
CertificatePath string
SkipSelfCheck bool
}
const (
rsaPrivateKey = "RSA PRIVATE KEY"
ecPrivateKey = "EC PRIVATE KEY"
x509CSR = "CERTIFICATE REQUEST"
)
var (
acmeServerURL string
accountKeyPath string
csrPath string
)
// init sets up the flags for the configuration.
func init() {
flag.StringVar(&acmeServerURL, "acme-server", "https://acme-v01.api.letsencrypt.org/directory", "URL of the ACME server directory. defaults to the Let's Encrypt live server")
flag.StringVar(&accountKeyPath, "account-key", "", "Path to your Let's Encrypt account private key.")
flag.StringVar(&Config.AccountEmail, "account-email", "", "The email to associate with the registration.")
flag.StringVar(&Config.AccountTerms, "account-terms", "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf", "The terms that need to be accepted before certificate issuance.")
flag.StringVar(&Config.ChallengeDir, "challenge-dir", ".well-known/acme-challenge/", "Path to the challenge directory.")
flag.StringVar(&csrPath, "csr", "", "Path to your CSR file.")
flag.StringVar(&Config.CertificatePath, "cert", "", "Path to the certificate file (with chain)")
flag.BoolVar(&Config.SkipSelfCheck, "skip-load-check", false, "Skip loading the challenge before sending the request to ACME")
}
// parseArgs is called to actually populate the Config structure with the args.
func parseArgs() {
flag.Parse()
defer func() {
if r := recover(); r != nil {
flag.Usage()
//noinspection GoUnhandledErrorResult
fmt.Fprintln(os.Stderr, r)
os.Exit(1)
}
}()
var err error
if acmeServerURL == "" {
panic("no acme discovery URL provided")
}
Config.Server, err = url.Parse(acmeServerURL)
if err != nil {
panic(err)
}
if accountKeyPath == "" {
panic("no account key supplied")
}
privKey, err := readKey(accountKeyPath)
if err != nil {
panic(err)
}
Config.AccountKey = privKey
if csrPath == "" {
panic("no CSR supplied")
}
csr, err := readCSR(csrPath)
if err != nil {
panic(err)
}
Config.CSR = csr
if _, err := os.Stat(Config.ChallengeDir); err != nil {
panic(fmt.Sprintf("can't access %q", Config.ChallengeDir))
}
if Config.CertificatePath == "" {
panic("no Certificate Path supplied")
}
Config.CertificatePath = filepath.Clean(Config.CertificatePath)
}
// readKey reads a private key from a given path.
// The key is expected to be PEM encoded.
func readKey(path string) (crypto.Signer, error) {
raw, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
data, _ := pem.Decode(raw)
if data == nil {
return nil, fmt.Errorf("no block found in %q", path)
}
switch data.Type {
case rsaPrivateKey:
return x509.ParsePKCS1PrivateKey(data.Bytes)
case ecPrivateKey:
return x509.ParseECPrivateKey(data.Bytes)
default:
return nil, fmt.Errorf("%q is unsupported", data.Type)
}
}
// readCSR reads a certificate request from a given path.
// The request is expected to be PEM encoded.
func readCSR(path string) (*x509.CertificateRequest, error) {
raw, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
data, _ := pem.Decode(raw)
if data == nil {
return nil, fmt.Errorf("no block found in %q", path)
}
if data.Type != x509CSR {
return nil, fmt.Errorf("%q is unsupported", data.Type)
}
return x509.ParseCertificateRequest(data.Bytes)
}