boulder/precert/corr_test.go

342 lines
9.3 KiB
Go

package precert
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"os"
"strings"
"testing"
"time"
)
func TestCorrespondIncorrectArgumentOrder(t *testing.T) {
pre, final, err := readPair("testdata/good/precert.pem", "testdata/good/final.pem")
if err != nil {
t.Fatal(err)
}
// The final cert is in the precert position and vice versa.
err = Correspond(final, pre)
if err == nil {
t.Errorf("expected failure when final and precertificates were in wrong order, got success")
}
}
func TestCorrespondGood(t *testing.T) {
pre, final, err := readPair("testdata/good/precert.pem", "testdata/good/final.pem")
if err != nil {
t.Fatal(err)
}
err = Correspond(pre, final)
if err != nil {
t.Errorf("expected testdata/good/ certs to correspond, got %s", err)
}
}
func TestCorrespondBad(t *testing.T) {
pre, final, err := readPair("testdata/bad/precert.pem", "testdata/bad/final.pem")
if err != nil {
t.Fatal(err)
}
err = Correspond(pre, final)
if err == nil {
t.Errorf("expected testdata/bad/ certs to not correspond, got nil error")
}
expected := "precert extension 7 (0603551d20040c300a3008060667810c010201) not equal to final cert extension 7 (0603551d20044530433008060667810c0102013037060b2b0601040182df130101013028302606082b06010505070201161a687474703a2f2f6370732e6c657473656e63727970742e6f7267)"
if !strings.Contains(err.Error(), expected) {
t.Errorf("expected error to contain %q, got %q", expected, err.Error())
}
}
func TestCorrespondCompleteMismatch(t *testing.T) {
pre, final, err := readPair("testdata/good/precert.pem", "testdata/bad/final.pem")
if err != nil {
t.Fatal(err)
}
err = Correspond(pre, final)
if err == nil {
t.Errorf("expected testdata/good and testdata/bad/ certs to not correspond, got nil error")
}
expected := "checking for identical field 1: elements differ: 021203d91c3d22b404f20df3c1631c22e1754b8d != 021203e2267b786b7e338317ddd62e764fcb3c71"
if !strings.Contains(err.Error(), expected) {
t.Errorf("expected error to contain %q, got %q", expected, err.Error())
}
}
func readPair(a, b string) ([]byte, []byte, error) {
aDER, err := derFromPEMFile(a)
if err != nil {
return nil, nil, err
}
bDER, err := derFromPEMFile(b)
if err != nil {
return nil, nil, err
}
return aDER, bDER, nil
}
// derFromPEMFile reads a PEM file and returns the DER-encoded bytes.
func derFromPEMFile(filename string) ([]byte, error) {
precertPEM, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("reading %s: %w", filename, err)
}
precertPEMBlock, _ := pem.Decode(precertPEM)
if precertPEMBlock == nil {
return nil, fmt.Errorf("error PEM decoding %s", filename)
}
return precertPEMBlock.Bytes, nil
}
func TestMismatches(t *testing.T) {
now := time.Now()
issuerKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
// A separate issuer key, used for signing the final certificate, but
// using the same simulated issuer certificate.
untrustedIssuerKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
subscriberKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
// By reading the crypto/x509 code, we know that Subject is the only field
// of the issuer certificate that we need to care about for the purposes
// of signing below.
issuer := x509.Certificate{
Subject: pkix.Name{
CommonName: "Some Issuer",
},
}
precertTemplate := x509.Certificate{
SerialNumber: big.NewInt(3141592653589793238),
NotBefore: now,
NotAfter: now.Add(24 * time.Hour),
DNSNames: []string{"example.com"},
ExtraExtensions: []pkix.Extension{
{
Id: poisonOID,
Value: []byte{0x5, 0x0},
},
},
}
precertDER, err := x509.CreateCertificate(rand.Reader, &precertTemplate, &issuer, &subscriberKey.PublicKey, issuerKey)
if err != nil {
t.Fatal(err)
}
// Sign a final certificate with the untrustedIssuerKey, first applying the
// given modify function to the default template. Return the DER encoded bytes.
makeFinalCert := func(modify func(c *x509.Certificate)) []byte {
t.Helper()
finalCertTemplate := &x509.Certificate{
SerialNumber: big.NewInt(3141592653589793238),
NotBefore: now,
NotAfter: now.Add(24 * time.Hour),
DNSNames: []string{"example.com"},
ExtraExtensions: []pkix.Extension{
{
Id: sctListOID,
Value: nil,
},
},
}
modify(finalCertTemplate)
finalCertDER, err := x509.CreateCertificate(rand.Reader, finalCertTemplate,
&issuer, &subscriberKey.PublicKey, untrustedIssuerKey)
if err != nil {
t.Fatal(err)
}
return finalCertDER
}
// Expect success with a matching precert and final cert
finalCertDER := makeFinalCert(func(c *x509.Certificate) {})
err = Correspond(precertDER, finalCertDER)
if err != nil {
t.Errorf("expected precert and final cert to correspond, got: %s", err)
}
// Set up a precert / final cert pair where the SCTList and poison extensions are
// not in the same position
precertTemplate2 := x509.Certificate{
SerialNumber: big.NewInt(3141592653589793238),
NotBefore: now,
NotAfter: now.Add(24 * time.Hour),
DNSNames: []string{"example.com"},
ExtraExtensions: []pkix.Extension{
{
Id: poisonOID,
Value: []byte{0x5, 0x0},
},
// Arbitrary extension to make poisonOID not be the last extension
{
Id: []int{1, 2, 3, 4},
Value: []byte{0x5, 0x0},
},
},
}
precertDER2, err := x509.CreateCertificate(rand.Reader, &precertTemplate2, &issuer, &subscriberKey.PublicKey, issuerKey)
if err != nil {
t.Fatal(err)
}
finalCertDER = makeFinalCert(func(c *x509.Certificate) {
c.ExtraExtensions = []pkix.Extension{
{
Id: []int{1, 2, 3, 4},
Value: []byte{0x5, 0x0},
},
{
Id: sctListOID,
Value: nil,
},
}
})
err = Correspond(precertDER2, finalCertDER)
if err != nil {
t.Errorf("expected precert and final cert to correspond with differently positioned extensions, got: %s", err)
}
// Expect failure with a mismatched Issuer
issuer = x509.Certificate{
Subject: pkix.Name{
CommonName: "Some Other Issuer",
},
}
finalCertDER = makeFinalCert(func(c *x509.Certificate) {})
err = Correspond(precertDER, finalCertDER)
if err == nil {
t.Errorf("expected error for mismatched issuer, got nil error")
}
// Restore original issuer
issuer = x509.Certificate{
Subject: pkix.Name{
CommonName: "Some Issuer",
},
}
// Expect failure with a mismatched Serial
finalCertDER = makeFinalCert(func(c *x509.Certificate) {
c.SerialNumber = big.NewInt(2718281828459045)
})
err = Correspond(precertDER, finalCertDER)
if err == nil {
t.Errorf("expected error for mismatched serial, got nil error")
}
// Expect failure with mismatched names
finalCertDER = makeFinalCert(func(c *x509.Certificate) {
c.DNSNames = []string{"example.com", "www.example.com"}
})
err = Correspond(precertDER, finalCertDER)
if err == nil {
t.Errorf("expected error for mismatched names, got nil error")
}
// Expect failure with mismatched NotBefore
finalCertDER = makeFinalCert(func(c *x509.Certificate) {
c.NotBefore = now.Add(24 * time.Hour)
})
err = Correspond(precertDER, finalCertDER)
if err == nil {
t.Errorf("expected error for mismatched NotBefore, got nil error")
}
// Expect failure with mismatched NotAfter
finalCertDER = makeFinalCert(func(c *x509.Certificate) {
c.NotAfter = now.Add(48 * time.Hour)
})
err = Correspond(precertDER, finalCertDER)
if err == nil {
t.Errorf("expected error for mismatched NotAfter, got nil error")
}
// Expect failure for mismatched extensions
finalCertDER = makeFinalCert(func(c *x509.Certificate) {
c.ExtraExtensions = append(c.ExtraExtensions, pkix.Extension{
Critical: true,
Id: []int{1, 2, 3},
Value: []byte("hello"),
})
})
err = Correspond(precertDER, finalCertDER)
if err == nil {
t.Errorf("expected error for mismatched extensions, got nil error")
}
expectedError := "precert extension 2 () not equal to final cert extension 2 (06022a030101ff040568656c6c6f)"
if err.Error() != expectedError {
t.Errorf("expected error %q, got %q", expectedError, err)
}
}
func TestUnwrapExtensions(t *testing.T) {
validExtensionsOuter := []byte{0xA3, 0x3, 0x30, 0x1, 0x0}
_, err := unwrapExtensions(validExtensionsOuter)
if err != nil {
t.Errorf("expected success for validExtensionsOuter, got %s", err)
}
invalidExtensionsOuter := []byte{0xA3, 0x99, 0x30, 0x1, 0x0}
_, err = unwrapExtensions(invalidExtensionsOuter)
if err == nil {
t.Error("expected error for invalidExtensionsOuter, got none")
}
invalidExtensionsInner := []byte{0xA3, 0x3, 0x30, 0x99, 0x0}
_, err = unwrapExtensions(invalidExtensionsInner)
if err == nil {
t.Error("expected error for invalidExtensionsInner, got none")
}
}
func TestTBSFromCertDER(t *testing.T) {
validCertOuter := []byte{0x30, 0x3, 0x30, 0x1, 0x0}
_, err := tbsDERFromCertDER(validCertOuter)
if err != nil {
t.Errorf("expected success for validCertOuter, got %s", err)
}
invalidCertOuter := []byte{0x30, 0x99, 0x30, 0x1, 0x0}
_, err = tbsDERFromCertDER(invalidCertOuter)
if err == nil {
t.Error("expected error for invalidCertOuter, got none")
}
invalidCertInner := []byte{0x30, 0x3, 0x30, 0x99, 0x0}
_, err = tbsDERFromCertDER(invalidCertInner)
if err == nil {
t.Error("expected error for invalidExtensionsInner, got none")
}
}