...

Source file src/github.com/letsencrypt/boulder/precert/corr_test.go

Documentation: github.com/letsencrypt/boulder/precert

     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  }
   342  

View as plain text