1
2 package main
3
4 import (
5 "errors"
6 "fmt"
7 "os"
8 "os/exec"
9 "regexp"
10 "text/template"
11
12 "github.com/letsencrypt/boulder/cmd"
13 blog "github.com/letsencrypt/boulder/log"
14 )
15
16
17
18
19
20 func createSlot(label string) (string, error) {
21 output, err := exec.Command("softhsm2-util", "--init-token", "--free", "--label", label, "--pin", "1234", "--so-pin", "5678").CombinedOutput()
22 if err != nil {
23 return "", err
24 }
25 re := regexp.MustCompile(`to slot (\d+)`)
26 matches := re.FindSubmatch(output)
27 if len(matches) != 2 {
28 return "", errors.New("unexpected number of slot matches")
29 }
30 return string(matches[1]), nil
31 }
32
33
34
35 func genKey(path string, inSlot string) error {
36 tmpPath, err := rewriteConfig(path, map[string]string{"SlotID": inSlot})
37 if err != nil {
38 return err
39 }
40 output, err := exec.Command("bin/ceremony", "-config", tmpPath).CombinedOutput()
41 if err != nil {
42 return fmt.Errorf("error running ceremony for %s: %s:\n%s", tmpPath, err, string(output))
43 }
44 return nil
45 }
46
47
48
49 func rewriteConfig(path string, rewrites map[string]string) (string, error) {
50 tmplBytes, err := os.ReadFile(path)
51 if err != nil {
52 return "", err
53 }
54 tmp, err := os.CreateTemp(os.TempDir(), "ceremony-config")
55 if err != nil {
56 return "", err
57 }
58 defer tmp.Close()
59 tmpl, err := template.New("config").Parse(string(tmplBytes))
60 if err != nil {
61 return "", err
62 }
63 err = tmpl.Execute(tmp, rewrites)
64 if err != nil {
65 return "", err
66 }
67 return tmp.Name(), nil
68 }
69
70
71 func genCert(path string) error {
72 output, err := exec.Command("bin/ceremony", "-config", path).CombinedOutput()
73 if err != nil {
74 return fmt.Errorf("error running ceremony for %s: %s:\n%s", path, err, string(output))
75 }
76 return nil
77 }
78
79 func main() {
80 _ = blog.Set(blog.StdoutLogger(6))
81 defer cmd.AuditPanic()
82
83
84
85 outputFile := "/hierarchy/root-signing-pub-rsa.pem"
86 if loc, err := os.Stat(outputFile); err == nil && loc.Mode().IsRegular() {
87 fmt.Println("skipping certificate generation: already exists")
88 return
89 } else if err == nil && !loc.Mode().IsRegular() {
90 cmd.Fail(fmt.Sprintf("statting %q: not a regular file", outputFile))
91 } else if err != nil && !os.IsNotExist(err) {
92 cmd.Fail(fmt.Sprintf("statting %q: %s", outputFile, err))
93 }
94
95 rsaRootKeySlot, err := createSlot("root signing key (rsa)")
96 cmd.FailOnError(err, "failed creating softhsm2 slot for RSA root key")
97 ecdsaRootKeySlot, err := createSlot("root signing key (ecdsa)")
98 cmd.FailOnError(err, "failed creating softhsm2 slot for root key")
99
100
101 err = genKey("test/cert-ceremonies/root-ceremony-rsa.yaml", rsaRootKeySlot)
102 cmd.FailOnError(err, "failed to generate RSA root key + root cert")
103 err = genKey("test/cert-ceremonies/root-ceremony-ecdsa.yaml", ecdsaRootKeySlot)
104 cmd.FailOnError(err, "failed to generate ECDSA root key + root cert")
105
106
107 rsaIntermediateKeySlot, err := createSlot("intermediate signing key (rsa)")
108 cmd.FailOnError(err, "failed to create softhsm2 slot for RSA intermediate key")
109 ecdsaIntermediateKeySlot, err := createSlot("intermediate signing key (ecdsa)")
110 cmd.FailOnError(err, "failed to create softhsm2 slot for ECDSA intermediate key")
111
112
113 err = genKey("test/cert-ceremonies/intermediate-key-ceremony-rsa.yaml", rsaIntermediateKeySlot)
114 cmd.FailOnError(err, "failed to generate RSA intermediate key")
115 err = genKey("test/cert-ceremonies/intermediate-key-ceremony-ecdsa.yaml", ecdsaIntermediateKeySlot)
116 cmd.FailOnError(err, "failed to generate ECDSA intermediate key")
117
118
119
120 rsaTmpIntermediateA, err := rewriteConfig("test/cert-ceremonies/intermediate-ceremony-rsa.yaml", map[string]string{
121 "SlotID": rsaRootKeySlot,
122 "CertPath": "/hierarchy/intermediate-cert-rsa-a.pem",
123 "CommonName": "CA intermediate (RSA) A",
124 })
125 cmd.FailOnError(err, "failed to rewrite RSA intermediate cert config with key ID")
126 ecdsaTmpIntermediateA, err := rewriteConfig("test/cert-ceremonies/intermediate-ceremony-ecdsa.yaml", map[string]string{
127 "SlotID": ecdsaRootKeySlot,
128 "CertPath": "/hierarchy/intermediate-cert-ecdsa-a.pem",
129 "CommonName": "CA intermediate (ECDSA) A",
130 })
131 cmd.FailOnError(err, "failed to rewrite ECDSA intermediate cert config with key ID")
132
133
134 err = genCert(rsaTmpIntermediateA)
135 cmd.FailOnError(err, "failed to generate RSA intermediate cert")
136 err = genCert(ecdsaTmpIntermediateA)
137 cmd.FailOnError(err, "failed to generate ECDSA intermediate cert")
138
139
140
141 rsaTmpIntermediateB, err := rewriteConfig("test/cert-ceremonies/intermediate-ceremony-rsa.yaml", map[string]string{
142 "SlotID": rsaRootKeySlot,
143 "CertPath": "/hierarchy/intermediate-cert-rsa-b.pem",
144 "CommonName": "CA intermediate (RSA) B",
145 })
146 cmd.FailOnError(err, "failed to rewrite RSA intermediate cert config with key ID")
147 ecdsaTmpIntermediateB, err := rewriteConfig("test/cert-ceremonies/intermediate-ceremony-ecdsa.yaml", map[string]string{
148 "SlotID": ecdsaRootKeySlot,
149 "CertPath": "/hierarchy/intermediate-cert-ecdsa-b.pem",
150 "CommonName": "CA intermediate (ECDSA) B",
151 })
152 cmd.FailOnError(err, "failed to rewrite ECDSA intermediate cert config with key ID")
153
154
155 err = genCert(rsaTmpIntermediateB)
156 cmd.FailOnError(err, "failed to generate RSA intermediate cert")
157 err = genCert(ecdsaTmpIntermediateB)
158 cmd.FailOnError(err, "failed to generate ECDSA intermediate cert")
159
160
161
162
163 ecdsaTmpCrossIntermediateA, err := rewriteConfig("test/cert-ceremonies/intermediate-cross-cert-ceremony.yaml", map[string]string{
164 "SlotID": rsaRootKeySlot,
165 "RootAlgorithm": "rsa",
166 "PublicKeyPath": "/hierarchy/intermediate-signing-pub-ecdsa.pem",
167 "IssuerCertPath": "/hierarchy/root-cert-rsa.pem",
168 "InputCertPath": "/hierarchy/intermediate-cert-ecdsa-a.pem",
169 "OutputCertPath": "/hierarchy/intermediate-cross-cert-ecdsa-a.pem",
170 "CommonName": "CA intermediate (ECDSA) A",
171 "SigAlgorithm": "SHA256WithRSA",
172 })
173 cmd.FailOnError(err, "failed to rewrite ECDSA intermediate cert config with key ID")
174 err = genCert(ecdsaTmpCrossIntermediateA)
175 cmd.FailOnError(err, "failed to generate ECDSA cross-signed intermediate cert A")
176
177 ecdsaTmpCrossIntermediateB, err := rewriteConfig("test/cert-ceremonies/intermediate-cross-cert-ceremony.yaml", map[string]string{
178 "SlotID": rsaRootKeySlot,
179 "RootAlgorithm": "rsa",
180 "PublicKeyPath": "/hierarchy/intermediate-signing-pub-ecdsa.pem",
181 "IssuerCertPath": "/hierarchy/root-cert-rsa.pem",
182 "InputCertPath": "/hierarchy/intermediate-cert-ecdsa-b.pem",
183 "OutputCertPath": "/hierarchy/intermediate-cross-cert-ecdsa-b.pem",
184 "CommonName": "CA intermediate (ECDSA) B",
185 "SigAlgorithm": "SHA256WithRSA",
186 })
187 cmd.FailOnError(err, "failed to rewrite ECDSA cross-signed intermediate cert config with key ID")
188 err = genCert(ecdsaTmpCrossIntermediateB)
189 cmd.FailOnError(err, "failed to generate ECDSA cross-signed intermediate cert B")
190
191
192 rsaTmpCRLConfig, err := rewriteConfig("test/cert-ceremonies/root-crl-rsa.yaml", map[string]string{
193 "SlotID": rsaRootKeySlot,
194 })
195 cmd.FailOnError(err, "failed to rewrite RSA root CRL config with key ID")
196 err = genCert(rsaTmpCRLConfig)
197 cmd.FailOnError(err, "failed to generate RSA root CRL")
198
199 ecdsaTmpCRLConfig, err := rewriteConfig("test/cert-ceremonies/root-crl-ecdsa.yaml", map[string]string{
200 "SlotID": ecdsaRootKeySlot,
201 })
202 cmd.FailOnError(err, "failed to rewrite ECDSA root CRL config with key ID")
203 err = genCert(ecdsaTmpCRLConfig)
204 cmd.FailOnError(err, "failed to generate ECDSA root CRL")
205 }
206
View as plain text