github.com/letsencrypt/boulder@v0.20251208.0/test/integration/issuance_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 "fmt" 12 "net" 13 "strings" 14 "testing" 15 16 "github.com/eggsampler/acme/v3" 17 18 "github.com/letsencrypt/boulder/test" 19 ) 20 21 // TestCommonNameInCSR ensures that CSRs which have a CN set result in certs 22 // with the same CN set. 23 func TestCommonNameInCSR(t *testing.T) { 24 t.Parallel() 25 26 // Create an account. 27 client, err := makeClient("mailto:example@letsencrypt.org") 28 test.AssertNotError(t, err, "creating acme client") 29 30 // Create a private key. 31 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 32 test.AssertNotError(t, err, "creating random cert key") 33 34 // Put together some names. 35 cn := random_domain() 36 san1 := random_domain() 37 san2 := random_domain() 38 idents := []acme.Identifier{ 39 {Type: "dns", Value: cn}, 40 {Type: "dns", Value: san1}, 41 {Type: "dns", Value: san2}, 42 } 43 44 // Issue a cert. authAndIssue includes the 0th name as the CN by default. 45 ir, err := authAndIssue(client, key, idents, true, "") 46 test.AssertNotError(t, err, "failed to issue test cert") 47 cert := ir.certs[0] 48 49 // Ensure that the CN is incorporated into the SANs. 50 test.AssertSliceContains(t, cert.DNSNames, cn) 51 test.AssertSliceContains(t, cert.DNSNames, san1) 52 test.AssertSliceContains(t, cert.DNSNames, san2) 53 54 // Ensure that the CN is preserved as the CN. 55 test.AssertEquals(t, cert.Subject.CommonName, cn) 56 } 57 58 // TestFirstCSRSANHoistedToCN ensures that CSRs which have no CN set result in 59 // certs with the first CSR SAN hoisted into the CN field. 60 func TestFirstCSRSANHoistedToCN(t *testing.T) { 61 t.Parallel() 62 63 // Create an account. 64 client, err := makeClient("mailto:example@letsencrypt.org") 65 test.AssertNotError(t, err, "creating acme client") 66 67 // Create a private key. 68 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 69 test.AssertNotError(t, err, "creating random cert key") 70 71 // Create some names that we can sort. 72 san1 := "a" + random_domain() 73 san2 := "b" + random_domain() 74 idents := []acme.Identifier{ 75 {Type: "dns", Value: san2}, 76 {Type: "dns", Value: san1}, 77 } 78 79 // Issue a cert using a CSR with no CN set, and the SANs in *non*-alpha order. 80 ir, err := authAndIssue(client, key, idents, false, "") 81 test.AssertNotError(t, err, "failed to issue test cert") 82 cert := ir.certs[0] 83 84 // Ensure that the SANs are correct, and sorted alphabetically. 85 test.AssertEquals(t, cert.DNSNames[0], san1) 86 test.AssertEquals(t, cert.DNSNames[1], san2) 87 88 // Ensure that the first SAN from the CSR is the CN. 89 test.Assert(t, cert.Subject.CommonName == san2, "first SAN should have been hoisted") 90 } 91 92 // TestCommonNameSANsTooLong tests that, when the names in an order and CSR are 93 // too long to be hoisted into the CN, the correct behavior results. 94 func TestCommonNameSANsTooLong(t *testing.T) { 95 t.Parallel() 96 97 // Create an account. 98 client, err := makeClient("mailto:example@letsencrypt.org") 99 test.AssertNotError(t, err, "creating acme client") 100 101 // Create a private key. 102 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 103 test.AssertNotError(t, err, "creating random cert key") 104 105 // Put together some names. 106 san1 := fmt.Sprintf("thisdomainnameis.morethan64characterslong.forthesakeoftesting.%s", random_domain()) 107 san2 := fmt.Sprintf("thisdomainnameis.morethan64characterslong.forthesakeoftesting.%s", random_domain()) 108 idents := []acme.Identifier{ 109 {Type: "dns", Value: san1}, 110 {Type: "dns", Value: san2}, 111 } 112 113 // Issue a cert using a CSR with no CN set. 114 ir, err := authAndIssue(client, key, idents, false, "") 115 test.AssertNotError(t, err, "failed to issue test cert") 116 cert := ir.certs[0] 117 118 // Ensure that the SANs are correct. 119 test.AssertSliceContains(t, cert.DNSNames, san1) 120 test.AssertSliceContains(t, cert.DNSNames, san2) 121 122 // Ensure that the CN is empty. 123 test.AssertEquals(t, cert.Subject.CommonName, "") 124 } 125 126 // TestIssuanceProfiles verifies that profile selection works, and results in 127 // measurable differences between certificates issued under different profiles. 128 // It does not test the omission of the keyEncipherment KU, because all of our 129 // integration test framework assumes ECDSA pubkeys for the sake of speed, 130 // and ECDSA certs don't get the keyEncipherment KU in either profile. 131 func TestIssuanceProfiles(t *testing.T) { 132 t.Parallel() 133 134 // Create an account. 135 client, err := makeClient("mailto:example@letsencrypt.org") 136 test.AssertNotError(t, err, "creating acme client") 137 138 profiles := client.Directory().Meta.Profiles 139 if len(profiles) < 2 { 140 t.Fatal("ACME server not advertising multiple profiles") 141 } 142 143 // Create a private key. 144 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 145 test.AssertNotError(t, err, "creating random cert key") 146 147 // Create a set of identifiers to request. 148 idents := []acme.Identifier{ 149 {Type: "dns", Value: random_domain()}, 150 } 151 152 // Get one cert for each profile that we know the test server advertises. 153 res, err := authAndIssue(client, key, idents, true, "legacy") 154 test.AssertNotError(t, err, "failed to issue under legacy profile") 155 test.AssertEquals(t, res.Order.Profile, "legacy") 156 legacy := res.certs[0] 157 158 res, err = authAndIssue(client, key, idents, true, "modern") 159 test.AssertNotError(t, err, "failed to issue under modern profile") 160 test.AssertEquals(t, res.Order.Profile, "modern") 161 modern := res.certs[0] 162 163 // Check that each profile worked as expected. 164 test.AssertEquals(t, legacy.Subject.CommonName, idents[0].Value) 165 test.AssertEquals(t, modern.Subject.CommonName, "") 166 167 test.AssertDeepEquals(t, legacy.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) 168 test.AssertDeepEquals(t, modern.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}) 169 170 test.AssertEquals(t, len(legacy.SubjectKeyId), 20) 171 test.AssertEquals(t, len(modern.SubjectKeyId), 0) 172 } 173 174 // TestIPShortLived verifies that we will allow IP address identifiers only in 175 // orders that use the shortlived profile. 176 func TestIPShortLived(t *testing.T) { 177 t.Parallel() 178 179 // Create an account. 180 client, err := makeClient("mailto:example@letsencrypt.org") 181 if err != nil { 182 t.Fatalf("creating acme client: %s", err) 183 } 184 185 // Create a private key. 186 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 187 if err != nil { 188 t.Fatalf("creating random cert key: %s", err) 189 } 190 191 // Create an IP address identifier to request. 192 ip := "64.112.117.122" 193 idents := []acme.Identifier{ 194 {Type: "ip", Value: ip}, 195 } 196 197 // Ensure we fail under each other profile that we know the test server advertises. 198 _, err = authAndIssue(client, key, idents, false, "legacy") 199 if err == nil { 200 t.Error("issued for IP address identifier under legacy profile") 201 } 202 if !strings.Contains(err.Error(), "Profile \"legacy\" does not permit ip type identifiers") { 203 t.Fatalf("issuing under legacy profile failed for the wrong reason: %s", err) 204 } 205 206 _, err = authAndIssue(client, key, idents, false, "modern") 207 if err == nil { 208 t.Error("issued for IP address identifier under modern profile") 209 } 210 if !strings.Contains(err.Error(), "Profile \"modern\" does not permit ip type identifiers") { 211 t.Fatalf("issuing under legacy profile failed for the wrong reason: %s", err) 212 } 213 214 // Get one cert for the shortlived profile. 215 res, err := authAndIssue(client, key, idents, false, "shortlived") 216 if err != nil { 217 t.Errorf("issuing under shortlived profile: %s", err) 218 } 219 if res.Order.Profile != "shortlived" { 220 t.Errorf("got '%s' profile, wanted 'shortlived'", res.Order.Profile) 221 } 222 cert := res.certs[0] 223 224 // Check that the shortlived profile worked as expected. 225 if cert.IPAddresses[0].String() != ip { 226 t.Errorf("got cert with first IP SAN '%s', wanted '%s'", cert.IPAddresses[0], ip) 227 } 228 } 229 230 // TestIPCNRejected verifies that we will reject IP address identifiers when 231 // they occur in the Subject CommonName. 232 func TestIPCNRejected(t *testing.T) { 233 t.Parallel() 234 235 // Create an account. 236 client, err := makeClient("mailto:example@letsencrypt.org") 237 if err != nil { 238 t.Fatalf("creating acme client: %s", err) 239 } 240 241 // Create an IP address identifier to request. 242 ip := "64.112.117.122" 243 ipParsed := net.ParseIP(ip) 244 idents := []acme.Identifier{ 245 {Type: "ip", Value: ip}, 246 } 247 248 order, err := client.Client.NewOrderExtension(client.Account, idents, acme.OrderExtension{Profile: "shortlived"}) 249 if err != nil { 250 t.Fatalf("creating order: %s", err) 251 } 252 253 if len(order.Authorizations) != 1 { 254 t.Fatalf("Got %d authorizations, expected 1", len(order.Authorizations)) 255 } 256 auth, err := client.Client.FetchAuthorization(client.Account, order.Authorizations[0]) 257 chal, ok := auth.ChallengeMap[acme.ChallengeTypeHTTP01] 258 if !ok { 259 t.Fatalf("no HTTP challenge at %s", order.Authorizations[0]) 260 } 261 262 _, err = testSrvClient.AddHTTP01Response(chal.Token, chal.KeyAuthorization) 263 if err != nil { 264 t.Fatalf("adding HTTP challenge response: %s", err) 265 } 266 defer testSrvClient.RemoveHTTP01Response(chal.Token) 267 268 chal, err = client.Client.UpdateChallenge(client.Account, chal) 269 if err != nil { 270 t.Fatalf("updating challenge: %s", err) 271 } 272 273 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 274 if err != nil { 275 t.Fatalf("creating random cert key: %s", err) 276 } 277 csrTemplate := &x509.CertificateRequest{ 278 Subject: pkix.Name{CommonName: ip}, 279 SignatureAlgorithm: x509.ECDSAWithSHA256, 280 PublicKeyAlgorithm: x509.ECDSA, 281 PublicKey: key.Public(), 282 IPAddresses: []net.IP{ipParsed}, 283 } 284 csrDer, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, key) 285 if err != nil { 286 t.Fatalf("making csr: %s", err) 287 } 288 csr, err := x509.ParseCertificateRequest(csrDer) 289 if err != nil { 290 t.Fatalf("parsing csr: %s", err) 291 } 292 293 _, err = client.Client.FinalizeOrder(client.Account, order, csr) 294 if err == nil { 295 t.Errorf("Finalizing order with IP in CN: got nil error, want badCSR error") 296 } 297 if !strings.Contains(err.Error(), "CSR contains IP address in Common Name") { 298 t.Errorf("issuing with IP in CN failed for the wrong reason: %s", err) 299 } 300 301 }