github.com/letsencrypt/boulder@v0.20251208.0/precert/corr_test.go (about) 1 package precert 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/elliptic" 6 "crypto/rand" 7 "crypto/x509" 8 "crypto/x509/pkix" 9 "encoding/pem" 10 "fmt" 11 "math/big" 12 "os" 13 "strings" 14 "testing" 15 "time" 16 ) 17 18 func TestCorrespondIncorrectArgumentOrder(t *testing.T) { 19 pre, final, err := readPair("testdata/good/precert.pem", "testdata/good/final.pem") 20 if err != nil { 21 t.Fatal(err) 22 } 23 24 // The final cert is in the precert position and vice versa. 25 err = Correspond(final, pre) 26 if err == nil { 27 t.Errorf("expected failure when final and precertificates were in wrong order, got success") 28 } 29 } 30 31 func TestCorrespondGood(t *testing.T) { 32 pre, final, err := readPair("testdata/good/precert.pem", "testdata/good/final.pem") 33 if err != nil { 34 t.Fatal(err) 35 } 36 37 err = Correspond(pre, final) 38 if err != nil { 39 t.Errorf("expected testdata/good/ certs to correspond, got %s", err) 40 } 41 } 42 43 func TestCorrespondBad(t *testing.T) { 44 pre, final, err := readPair("testdata/bad/precert.pem", "testdata/bad/final.pem") 45 if err != nil { 46 t.Fatal(err) 47 } 48 49 err = Correspond(pre, final) 50 if err == nil { 51 t.Errorf("expected testdata/bad/ certs to not correspond, got nil error") 52 } 53 expected := "precert extension 7 (0603551d20040c300a3008060667810c010201) not equal to final cert extension 7 (0603551d20044530433008060667810c0102013037060b2b0601040182df130101013028302606082b06010505070201161a687474703a2f2f6370732e6c657473656e63727970742e6f7267)" 54 if !strings.Contains(err.Error(), expected) { 55 t.Errorf("expected error to contain %q, got %q", expected, err.Error()) 56 } 57 } 58 59 func TestCorrespondCompleteMismatch(t *testing.T) { 60 pre, final, err := readPair("testdata/good/precert.pem", "testdata/bad/final.pem") 61 if err != nil { 62 t.Fatal(err) 63 } 64 65 err = Correspond(pre, final) 66 if err == nil { 67 t.Errorf("expected testdata/good and testdata/bad/ certs to not correspond, got nil error") 68 } 69 expected := "checking for identical field 1: elements differ: 021203d91c3d22b404f20df3c1631c22e1754b8d != 021203e2267b786b7e338317ddd62e764fcb3c71" 70 if !strings.Contains(err.Error(), expected) { 71 t.Errorf("expected error to contain %q, got %q", expected, err.Error()) 72 } 73 } 74 75 func readPair(a, b string) ([]byte, []byte, error) { 76 aDER, err := derFromPEMFile(a) 77 if err != nil { 78 return nil, nil, err 79 } 80 bDER, err := derFromPEMFile(b) 81 if err != nil { 82 return nil, nil, err 83 } 84 return aDER, bDER, nil 85 } 86 87 // derFromPEMFile reads a PEM file and returns the DER-encoded bytes. 88 func derFromPEMFile(filename string) ([]byte, error) { 89 precertPEM, err := os.ReadFile(filename) 90 if err != nil { 91 return nil, fmt.Errorf("reading %s: %w", filename, err) 92 } 93 94 precertPEMBlock, _ := pem.Decode(precertPEM) 95 if precertPEMBlock == nil { 96 return nil, fmt.Errorf("error PEM decoding %s", filename) 97 } 98 99 return precertPEMBlock.Bytes, nil 100 } 101 102 func TestMismatches(t *testing.T) { 103 now := time.Now() 104 105 issuerKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 106 if err != nil { 107 t.Fatal(err) 108 } 109 110 // A separate issuer key, used for signing the final certificate, but 111 // using the same simulated issuer certificate. 112 untrustedIssuerKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 113 if err != nil { 114 t.Fatal(err) 115 } 116 117 subscriberKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 118 if err != nil { 119 t.Fatal(err) 120 } 121 122 // By reading the crypto/x509 code, we know that Subject is the only field 123 // of the issuer certificate that we need to care about for the purposes 124 // of signing below. 125 issuer := x509.Certificate{ 126 Subject: pkix.Name{ 127 CommonName: "Some Issuer", 128 }, 129 } 130 131 precertTemplate := x509.Certificate{ 132 SerialNumber: big.NewInt(3141592653589793238), 133 NotBefore: now, 134 NotAfter: now.Add(24 * time.Hour), 135 DNSNames: []string{"example.com"}, 136 ExtraExtensions: []pkix.Extension{ 137 { 138 Id: poisonOID, 139 Value: []byte{0x5, 0x0}, 140 }, 141 }, 142 } 143 144 precertDER, err := x509.CreateCertificate(rand.Reader, &precertTemplate, &issuer, &subscriberKey.PublicKey, issuerKey) 145 if err != nil { 146 t.Fatal(err) 147 } 148 149 // Sign a final certificate with the untrustedIssuerKey, first applying the 150 // given modify function to the default template. Return the DER encoded bytes. 151 makeFinalCert := func(modify func(c *x509.Certificate)) []byte { 152 t.Helper() 153 finalCertTemplate := &x509.Certificate{ 154 SerialNumber: big.NewInt(3141592653589793238), 155 NotBefore: now, 156 NotAfter: now.Add(24 * time.Hour), 157 DNSNames: []string{"example.com"}, 158 ExtraExtensions: []pkix.Extension{ 159 { 160 Id: sctListOID, 161 Value: nil, 162 }, 163 }, 164 } 165 166 modify(finalCertTemplate) 167 168 finalCertDER, err := x509.CreateCertificate(rand.Reader, finalCertTemplate, 169 &issuer, &subscriberKey.PublicKey, untrustedIssuerKey) 170 if err != nil { 171 t.Fatal(err) 172 } 173 174 return finalCertDER 175 } 176 177 // Expect success with a matching precert and final cert 178 finalCertDER := makeFinalCert(func(c *x509.Certificate) {}) 179 err = Correspond(precertDER, finalCertDER) 180 if err != nil { 181 t.Errorf("expected precert and final cert to correspond, got: %s", err) 182 } 183 184 // Set up a precert / final cert pair where the SCTList and poison extensions are 185 // not in the same position 186 precertTemplate2 := x509.Certificate{ 187 SerialNumber: big.NewInt(3141592653589793238), 188 NotBefore: now, 189 NotAfter: now.Add(24 * time.Hour), 190 DNSNames: []string{"example.com"}, 191 ExtraExtensions: []pkix.Extension{ 192 { 193 Id: poisonOID, 194 Value: []byte{0x5, 0x0}, 195 }, 196 // Arbitrary extension to make poisonOID not be the last extension 197 { 198 Id: []int{1, 2, 3, 4}, 199 Value: []byte{0x5, 0x0}, 200 }, 201 }, 202 } 203 204 precertDER2, err := x509.CreateCertificate(rand.Reader, &precertTemplate2, &issuer, &subscriberKey.PublicKey, issuerKey) 205 if err != nil { 206 t.Fatal(err) 207 } 208 209 finalCertDER = makeFinalCert(func(c *x509.Certificate) { 210 c.ExtraExtensions = []pkix.Extension{ 211 { 212 Id: []int{1, 2, 3, 4}, 213 Value: []byte{0x5, 0x0}, 214 }, 215 { 216 Id: sctListOID, 217 Value: nil, 218 }, 219 } 220 }) 221 err = Correspond(precertDER2, finalCertDER) 222 if err != nil { 223 t.Errorf("expected precert and final cert to correspond with differently positioned extensions, got: %s", err) 224 } 225 226 // Expect failure with a mismatched Issuer 227 issuer = x509.Certificate{ 228 Subject: pkix.Name{ 229 CommonName: "Some Other Issuer", 230 }, 231 } 232 233 finalCertDER = makeFinalCert(func(c *x509.Certificate) {}) 234 err = Correspond(precertDER, finalCertDER) 235 if err == nil { 236 t.Errorf("expected error for mismatched issuer, got nil error") 237 } 238 239 // Restore original issuer 240 issuer = x509.Certificate{ 241 Subject: pkix.Name{ 242 CommonName: "Some Issuer", 243 }, 244 } 245 246 // Expect failure with a mismatched Serial 247 finalCertDER = makeFinalCert(func(c *x509.Certificate) { 248 c.SerialNumber = big.NewInt(2718281828459045) 249 }) 250 err = Correspond(precertDER, finalCertDER) 251 if err == nil { 252 t.Errorf("expected error for mismatched serial, got nil error") 253 } 254 255 // Expect failure with mismatched names 256 finalCertDER = makeFinalCert(func(c *x509.Certificate) { 257 c.DNSNames = []string{"example.com", "www.example.com"} 258 }) 259 260 err = Correspond(precertDER, finalCertDER) 261 if err == nil { 262 t.Errorf("expected error for mismatched names, got nil error") 263 } 264 265 // Expect failure with mismatched NotBefore 266 finalCertDER = makeFinalCert(func(c *x509.Certificate) { 267 c.NotBefore = now.Add(24 * time.Hour) 268 }) 269 270 err = Correspond(precertDER, finalCertDER) 271 if err == nil { 272 t.Errorf("expected error for mismatched NotBefore, got nil error") 273 } 274 275 // Expect failure with mismatched NotAfter 276 finalCertDER = makeFinalCert(func(c *x509.Certificate) { 277 c.NotAfter = now.Add(48 * time.Hour) 278 }) 279 err = Correspond(precertDER, finalCertDER) 280 if err == nil { 281 t.Errorf("expected error for mismatched NotAfter, got nil error") 282 } 283 284 // Expect failure for mismatched extensions 285 finalCertDER = makeFinalCert(func(c *x509.Certificate) { 286 c.ExtraExtensions = append(c.ExtraExtensions, pkix.Extension{ 287 Critical: true, 288 Id: []int{1, 2, 3}, 289 Value: []byte("hello"), 290 }) 291 }) 292 293 err = Correspond(precertDER, finalCertDER) 294 if err == nil { 295 t.Errorf("expected error for mismatched extensions, got nil error") 296 } 297 expectedError := "precert extension 2 () not equal to final cert extension 2 (06022a030101ff040568656c6c6f)" 298 if err.Error() != expectedError { 299 t.Errorf("expected error %q, got %q", expectedError, err) 300 } 301 } 302 303 func TestUnwrapExtensions(t *testing.T) { 304 validExtensionsOuter := []byte{0xA3, 0x3, 0x30, 0x1, 0x0} 305 _, err := unwrapExtensions(validExtensionsOuter) 306 if err != nil { 307 t.Errorf("expected success for validExtensionsOuter, got %s", err) 308 } 309 310 invalidExtensionsOuter := []byte{0xA3, 0x99, 0x30, 0x1, 0x0} 311 _, err = unwrapExtensions(invalidExtensionsOuter) 312 if err == nil { 313 t.Error("expected error for invalidExtensionsOuter, got none") 314 } 315 316 invalidExtensionsInner := []byte{0xA3, 0x3, 0x30, 0x99, 0x0} 317 _, err = unwrapExtensions(invalidExtensionsInner) 318 if err == nil { 319 t.Error("expected error for invalidExtensionsInner, got none") 320 } 321 } 322 323 func TestTBSFromCertDER(t *testing.T) { 324 validCertOuter := []byte{0x30, 0x3, 0x30, 0x1, 0x0} 325 _, err := tbsDERFromCertDER(validCertOuter) 326 if err != nil { 327 t.Errorf("expected success for validCertOuter, got %s", err) 328 } 329 330 invalidCertOuter := []byte{0x30, 0x99, 0x30, 0x1, 0x0} 331 _, err = tbsDERFromCertDER(invalidCertOuter) 332 if err == nil { 333 t.Error("expected error for invalidCertOuter, got none") 334 } 335 336 invalidCertInner := []byte{0x30, 0x3, 0x30, 0x99, 0x0} 337 _, err = tbsDERFromCertDER(invalidCertInner) 338 if err == nil { 339 t.Error("expected error for invalidExtensionsInner, got none") 340 } 341 }