github.com/letsencrypt/boulder@v0.20251208.0/test/integration/common_test.go (about) 1 //go:build integration 2 3 package integration 4 5 import ( 6 "crypto/ecdsa" 7 "crypto/elliptic" 8 "crypto/rand" 9 "crypto/x509" 10 "crypto/x509/pkix" 11 "encoding/asn1" 12 "encoding/hex" 13 "fmt" 14 "net" 15 "os" 16 17 challTestSrvClient "github.com/letsencrypt/boulder/test/chall-test-srv-client" 18 19 "github.com/eggsampler/acme/v3" 20 ) 21 22 var testSrvClient = challTestSrvClient.NewClient("") 23 24 func init() { 25 // Go tests get run in the directory their source code lives in. For these 26 // test cases, that would be "test/integration." However, it's easier to 27 // reference test data and config files for integration tests relative to the 28 // root of the Boulder repo, so we run all of these tests from there instead. 29 os.Chdir("../../") 30 } 31 32 var ( 33 OIDExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} 34 ) 35 36 func random_domain() string { 37 var bytes [3]byte 38 rand.Read(bytes[:]) 39 return hex.EncodeToString(bytes[:]) + ".com" 40 } 41 42 type client struct { 43 acme.Account 44 acme.Client 45 } 46 47 func makeClient(contacts ...string) (*client, error) { 48 c, err := acme.NewClient("http://boulder.service.consul:4001/directory") 49 if err != nil { 50 return nil, fmt.Errorf("Error connecting to acme directory: %v", err) 51 } 52 privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 53 if err != nil { 54 return nil, fmt.Errorf("error creating private key: %v", err) 55 } 56 account, err := c.NewAccount(privKey, false, true, contacts...) 57 if err != nil { 58 return nil, err 59 } 60 return &client{account, c}, nil 61 } 62 63 func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Identifier, cn bool, profile string, certToReplace *x509.Certificate) (*client, *acme.Order, error) { 64 var err error 65 if c == nil { 66 c, err = makeClient() 67 if err != nil { 68 return nil, nil, err 69 } 70 } 71 72 var order acme.Order 73 if certToReplace != nil { 74 order, err = c.Client.ReplacementOrderExtension(c.Account, certToReplace, idents, acme.OrderExtension{Profile: profile}) 75 } else { 76 order, err = c.Client.NewOrderExtension(c.Account, idents, acme.OrderExtension{Profile: profile}) 77 } 78 if err != nil { 79 return nil, nil, err 80 } 81 82 for _, authUrl := range order.Authorizations { 83 auth, err := c.Client.FetchAuthorization(c.Account, authUrl) 84 if err != nil { 85 return nil, nil, fmt.Errorf("fetching authorization at %s: %s", authUrl, err) 86 } 87 88 chal, ok := auth.ChallengeMap[acme.ChallengeTypeHTTP01] 89 if !ok { 90 return nil, nil, fmt.Errorf("no HTTP challenge at %s", authUrl) 91 } 92 93 _, err = testSrvClient.AddHTTP01Response(chal.Token, chal.KeyAuthorization) 94 if err != nil { 95 return nil, nil, err 96 } 97 chal, err = c.Client.UpdateChallenge(c.Account, chal) 98 if err != nil { 99 testSrvClient.RemoveHTTP01Response(chal.Token) 100 return nil, nil, err 101 } 102 _, err = testSrvClient.RemoveHTTP01Response(chal.Token) 103 if err != nil { 104 return nil, nil, err 105 } 106 } 107 108 csr, err := makeCSR(csrKey, idents, cn) 109 if err != nil { 110 return nil, nil, err 111 } 112 113 order, err = c.Client.FinalizeOrder(c.Account, order, csr) 114 if err != nil { 115 return nil, nil, fmt.Errorf("finalizing order: %s", err) 116 } 117 118 return c, &order, nil 119 } 120 121 type issuanceResult struct { 122 acme.Order 123 certs []*x509.Certificate 124 } 125 126 func authAndIssue(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Identifier, cn bool, profile string) (*issuanceResult, error) { 127 var err error 128 129 c, order, err := makeClientAndOrder(c, csrKey, idents, cn, profile, nil) 130 if err != nil { 131 return nil, err 132 } 133 134 certs, err := c.Client.FetchCertificates(c.Account, order.Certificate) 135 if err != nil { 136 return nil, fmt.Errorf("fetching certificates: %s", err) 137 } 138 return &issuanceResult{*order, certs}, nil 139 } 140 141 type issuanceResultAllChains struct { 142 acme.Order 143 certs map[string][]*x509.Certificate 144 } 145 146 func authAndIssueFetchAllChains(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Identifier, cn bool) (*issuanceResultAllChains, error) { 147 c, order, err := makeClientAndOrder(c, csrKey, idents, cn, "", nil) 148 if err != nil { 149 return nil, err 150 } 151 152 // Retrieve all the certificate chains served by the WFE2. 153 certs, err := c.Client.FetchAllCertificates(c.Account, order.Certificate) 154 if err != nil { 155 return nil, fmt.Errorf("fetching certificates: %s", err) 156 } 157 158 return &issuanceResultAllChains{*order, certs}, nil 159 } 160 161 func makeCSR(k *ecdsa.PrivateKey, idents []acme.Identifier, cn bool) (*x509.CertificateRequest, error) { 162 var err error 163 if k == nil { 164 k, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 165 if err != nil { 166 return nil, fmt.Errorf("generating certificate key: %s", err) 167 } 168 } 169 170 var names []string 171 var ips []net.IP 172 for _, ident := range idents { 173 switch ident.Type { 174 case "dns": 175 names = append(names, ident.Value) 176 case "ip": 177 ips = append(ips, net.ParseIP(ident.Value)) 178 default: 179 return nil, fmt.Errorf("unrecognized identifier type %q", ident.Type) 180 } 181 } 182 183 tmpl := &x509.CertificateRequest{ 184 SignatureAlgorithm: x509.ECDSAWithSHA256, 185 PublicKeyAlgorithm: x509.ECDSA, 186 PublicKey: k.Public(), 187 DNSNames: names, 188 IPAddresses: ips, 189 } 190 if cn && len(names) > 0 { 191 tmpl.Subject = pkix.Name{CommonName: names[0]} 192 } 193 194 csrDer, err := x509.CreateCertificateRequest(rand.Reader, tmpl, k) 195 if err != nil { 196 return nil, fmt.Errorf("making csr: %s", err) 197 } 198 csr, err := x509.ParseCertificateRequest(csrDer) 199 if err != nil { 200 return nil, fmt.Errorf("parsing csr: %s", err) 201 } 202 return csr, nil 203 }