github.com/letsencrypt/boulder@v0.20251208.0/test/certs/webpki.go (about) 1 // generate.go is a helper utility for integration tests. 2 package main 3 4 import ( 5 "errors" 6 "fmt" 7 "os" 8 "os/exec" 9 "regexp" 10 "strings" 11 "text/template" 12 13 "github.com/letsencrypt/boulder/cmd" 14 blog "github.com/letsencrypt/boulder/log" 15 ) 16 17 // createSlot initializes a SoftHSM slot and token. SoftHSM chooses the highest empty 18 // slot, initializes it, and then assigns it a new randomly chosen slot ID. Since we can't 19 // predict this ID we need to parse out the new ID so that we can use it in the ceremony 20 // configs. 21 func createSlot(label string) (string, error) { 22 output, err := exec.Command("softhsm2-util", "--init-token", "--free", "--label", label, "--pin", "1234", "--so-pin", "5678").CombinedOutput() 23 if err != nil { 24 return "", err 25 } 26 re := regexp.MustCompile(`to slot (\d+)`) 27 matches := re.FindSubmatch(output) 28 if len(matches) != 2 { 29 return "", errors.New("unexpected number of slot matches") 30 } 31 return string(matches[1]), nil 32 } 33 34 // genKey is used to run a root key ceremony with a given config, replacing 35 // SlotID in the YAML with a specific slot ID. 36 func genKey(path string, inSlot string) error { 37 tmpPath, err := rewriteConfig(path, map[string]string{"SlotID": inSlot}) 38 if err != nil { 39 return err 40 } 41 output, err := exec.Command("./bin/ceremony", "-config", tmpPath).CombinedOutput() 42 if err != nil { 43 return fmt.Errorf("error running ceremony for %s: %s:\n%s", tmpPath, err, string(output)) 44 } 45 return nil 46 } 47 48 // rewriteConfig creates a temporary config based on the template at path 49 // using the variables in rewrites. 50 func rewriteConfig(path string, rewrites map[string]string) (string, error) { 51 tmplBytes, err := os.ReadFile(path) 52 if err != nil { 53 return "", err 54 } 55 tmp, err := os.CreateTemp(os.TempDir(), "ceremony-config") 56 if err != nil { 57 return "", err 58 } 59 defer tmp.Close() 60 tmpl, err := template.New("config").Parse(string(tmplBytes)) 61 if err != nil { 62 return "", err 63 } 64 err = tmpl.Execute(tmp, rewrites) 65 if err != nil { 66 return "", err 67 } 68 return tmp.Name(), nil 69 } 70 71 // runCeremony is used to run a ceremony with a given config. 72 func runCeremony(path string) error { 73 output, err := exec.Command("./bin/ceremony", "-config", path).CombinedOutput() 74 if err != nil { 75 return fmt.Errorf("error running ceremony for %s: %s:\n%s", path, err, string(output)) 76 } 77 return nil 78 } 79 80 func main() { 81 _ = blog.Set(blog.StdoutLogger(6)) 82 defer cmd.AuditPanic() 83 84 // Create SoftHSM slots for the root signing keys 85 rsaRootKeySlot, err := createSlot("Root RSA") 86 cmd.FailOnError(err, "failed creating softhsm2 slot for RSA root key") 87 ecdsaRootKeySlot, err := createSlot("Root ECDSA") 88 cmd.FailOnError(err, "failed creating softhsm2 slot for ECDSA root key") 89 90 // Generate the root signing keys and certificates 91 err = genKey("test/certs/root-ceremony-rsa.yaml", rsaRootKeySlot) 92 cmd.FailOnError(err, "failed to generate RSA root key + root cert") 93 err = genKey("test/certs/root-ceremony-ecdsa.yaml", ecdsaRootKeySlot) 94 cmd.FailOnError(err, "failed to generate ECDSA root key + root cert") 95 96 // Do everything for all of the intermediates 97 for _, alg := range []string{"rsa", "ecdsa"} { 98 rootKeySlot := rsaRootKeySlot 99 if alg == "ecdsa" { 100 rootKeySlot = ecdsaRootKeySlot 101 } 102 103 for _, inst := range []string{"a", "b", "c"} { 104 name := fmt.Sprintf("int %s %s", alg, inst) 105 // Note: The file names produced by this script (as a combination of this 106 // line, and the rest of the file name as specified in the various yaml 107 // template files) are meaningful and are consumed by aia-test-srv. If 108 // you change the structure of these file names, you will need to change 109 // aia-test-srv as well to recognize and consume the resulting files. 110 fileName := strings.Replace(name, " ", "-", -1) 111 112 // Create SoftHSM slot 113 keySlot, err := createSlot(name) 114 cmd.FailOnError(err, "failed to create softhsm2 slot for intermediate key") 115 116 // Generate key 117 keyConfigTemplate := fmt.Sprintf("test/certs/intermediate-key-ceremony-%s.yaml", alg) 118 keyConfig, err := rewriteConfig(keyConfigTemplate, map[string]string{ 119 "SlotID": keySlot, 120 "Label": name, 121 "FileName": fileName, 122 }) 123 cmd.FailOnError(err, "failed to rewrite intermediate key ceremony config") 124 125 err = runCeremony(keyConfig) 126 cmd.FailOnError(err, "failed to generate intermediate key") 127 128 // Generate cert 129 certConfigTemplate := fmt.Sprintf("test/certs/intermediate-cert-ceremony-%s.yaml", alg) 130 certConfig, err := rewriteConfig(certConfigTemplate, map[string]string{ 131 "SlotID": rootKeySlot, 132 "CommonName": name, 133 "FileName": fileName, 134 }) 135 cmd.FailOnError(err, "failed to rewrite intermediate cert ceremony config") 136 137 err = runCeremony(certConfig) 138 cmd.FailOnError(err, "failed to generate intermediate cert") 139 140 // Generate cross-certs, if necessary 141 if alg == "rsa" { 142 continue 143 } 144 145 crossConfigTemplate := fmt.Sprintf("test/certs/intermediate-cert-ceremony-%s-cross.yaml", alg) 146 crossConfig, err := rewriteConfig(crossConfigTemplate, map[string]string{ 147 "SlotID": rsaRootKeySlot, 148 "CommonName": name, 149 "FileName": fileName, 150 }) 151 cmd.FailOnError(err, "failed to rewrite intermediate cross-cert ceremony config") 152 153 err = runCeremony(crossConfig) 154 cmd.FailOnError(err, "failed to generate intermediate cross-cert") 155 } 156 } 157 158 // Create CRLs stating that the intermediates are not revoked. 159 rsaTmpCRLConfig, err := rewriteConfig("test/certs/root-crl-rsa.yaml", map[string]string{ 160 "SlotID": rsaRootKeySlot, 161 }) 162 cmd.FailOnError(err, "failed to rewrite RSA root CRL config with key ID") 163 err = runCeremony(rsaTmpCRLConfig) 164 cmd.FailOnError(err, "failed to generate RSA root CRL") 165 166 ecdsaTmpCRLConfig, err := rewriteConfig("test/certs/root-crl-ecdsa.yaml", map[string]string{ 167 "SlotID": ecdsaRootKeySlot, 168 }) 169 cmd.FailOnError(err, "failed to rewrite ECDSA root CRL config with key ID") 170 err = runCeremony(ecdsaTmpCRLConfig) 171 cmd.FailOnError(err, "failed to generate ECDSA root CRL") 172 }