github.com/letsencrypt/boulder@v0.20251208.0/issuance/cert_test.go (about)

     1  package issuance
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/dsa"
     6  	"crypto/ecdsa"
     7  	"crypto/elliptic"
     8  	"crypto/rand"
     9  	"crypto/rsa"
    10  	"crypto/x509"
    11  	"crypto/x509/pkix"
    12  	"encoding/base64"
    13  	"net"
    14  	"reflect"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  
    19  	ct "github.com/google/certificate-transparency-go"
    20  	"github.com/jmhodges/clock"
    21  
    22  	"github.com/letsencrypt/boulder/config"
    23  	"github.com/letsencrypt/boulder/ctpolicy/loglist"
    24  	"github.com/letsencrypt/boulder/linter"
    25  	"github.com/letsencrypt/boulder/test"
    26  )
    27  
    28  var (
    29  	goodSKID = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    30  )
    31  
    32  func defaultProfile() *Profile {
    33  	p, _ := NewProfile(defaultProfileConfig())
    34  	return p
    35  }
    36  
    37  func TestGenerateValidity(t *testing.T) {
    38  	fc := clock.NewFake()
    39  	fc.Set(time.Date(2015, time.June, 04, 11, 04, 38, 0, time.UTC))
    40  
    41  	tests := []struct {
    42  		name      string
    43  		backdate  time.Duration
    44  		validity  time.Duration
    45  		notBefore time.Time
    46  		notAfter  time.Time
    47  	}{
    48  		{
    49  			name:      "normal usage",
    50  			backdate:  time.Hour, // 90% of one hour is 54 minutes
    51  			validity:  7 * 24 * time.Hour,
    52  			notBefore: time.Date(2015, time.June, 04, 10, 10, 38, 0, time.UTC),
    53  			notAfter:  time.Date(2015, time.June, 11, 10, 10, 37, 0, time.UTC),
    54  		},
    55  		{
    56  			name:      "zero backdate",
    57  			backdate:  0,
    58  			validity:  7 * 24 * time.Hour,
    59  			notBefore: time.Date(2015, time.June, 04, 11, 04, 38, 0, time.UTC),
    60  			notAfter:  time.Date(2015, time.June, 11, 11, 04, 37, 0, time.UTC),
    61  		},
    62  	}
    63  
    64  	for _, tc := range tests {
    65  		t.Run(tc.name, func(t *testing.T) {
    66  			p := Profile{maxBackdate: tc.backdate, maxValidity: tc.validity}
    67  			notBefore, notAfter := p.GenerateValidity(fc.Now())
    68  			test.AssertEquals(t, notBefore, tc.notBefore)
    69  			test.AssertEquals(t, notAfter, tc.notAfter)
    70  		})
    71  	}
    72  }
    73  
    74  func TestCRLURL(t *testing.T) {
    75  	issuer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, clock.NewFake())
    76  	if err != nil {
    77  		t.Fatalf("newIssuer: %s", err)
    78  	}
    79  	url := issuer.crlURL(4928)
    80  	want := "http://crl-url.example.org/4928.crl"
    81  	if url != want {
    82  		t.Errorf("crlURL(4928)=%s, want %s", url, want)
    83  	}
    84  }
    85  
    86  func TestRequestValid(t *testing.T) {
    87  	fc := clock.NewFake()
    88  	fc.Add(time.Hour * 24)
    89  
    90  	tests := []struct {
    91  		name          string
    92  		issuer        *Issuer
    93  		profile       *Profile
    94  		request       *IssuanceRequest
    95  		expectedError string
    96  	}{
    97  		{
    98  			name:          "unsupported key type",
    99  			issuer:        &Issuer{},
   100  			profile:       &Profile{},
   101  			request:       &IssuanceRequest{PublicKey: MarshalablePublicKey{&dsa.PublicKey{}}},
   102  			expectedError: "unsupported public key type",
   103  		},
   104  		{
   105  			name:          "inactive (rsa)",
   106  			issuer:        &Issuer{},
   107  			profile:       &Profile{},
   108  			request:       &IssuanceRequest{PublicKey: MarshalablePublicKey{&rsa.PublicKey{}}},
   109  			expectedError: "inactive issuer cannot issue precert",
   110  		},
   111  		{
   112  			name:          "inactive (ecdsa)",
   113  			issuer:        &Issuer{},
   114  			profile:       &Profile{},
   115  			request:       &IssuanceRequest{PublicKey: MarshalablePublicKey{&ecdsa.PublicKey{}}},
   116  			expectedError: "inactive issuer cannot issue precert",
   117  		},
   118  		{
   119  			name: "skid too short",
   120  			issuer: &Issuer{
   121  				active: true,
   122  			},
   123  			profile: &Profile{},
   124  			request: &IssuanceRequest{
   125  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   126  				SubjectKeyId: []byte{0, 1, 2, 3, 4},
   127  			},
   128  			expectedError: "unexpected subject key ID length",
   129  		},
   130  		{
   131  			name: "both sct list and ct poison provided",
   132  			issuer: &Issuer{
   133  				active: true,
   134  			},
   135  			profile: &Profile{},
   136  			request: &IssuanceRequest{
   137  				PublicKey:       MarshalablePublicKey{&ecdsa.PublicKey{}},
   138  				SubjectKeyId:    goodSKID,
   139  				IncludeCTPoison: true,
   140  				sctList:         []ct.SignedCertificateTimestamp{},
   141  			},
   142  			expectedError: "cannot include both ct poison and sct list extensions",
   143  		},
   144  		{
   145  			name: "negative validity",
   146  			issuer: &Issuer{
   147  				active: true,
   148  			},
   149  			profile: &Profile{},
   150  			request: &IssuanceRequest{
   151  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   152  				SubjectKeyId: goodSKID,
   153  				NotBefore:    fc.Now().Add(time.Hour),
   154  				NotAfter:     fc.Now(),
   155  			},
   156  			expectedError: "NotAfter must be after NotBefore",
   157  		},
   158  		{
   159  			name: "validity larger than max",
   160  			issuer: &Issuer{
   161  				active: true,
   162  			},
   163  			profile: &Profile{
   164  				maxValidity: time.Minute,
   165  			},
   166  			request: &IssuanceRequest{
   167  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   168  				SubjectKeyId: goodSKID,
   169  				NotBefore:    fc.Now(),
   170  				NotAfter:     fc.Now().Add(time.Hour - time.Second),
   171  			},
   172  			expectedError: "validity period is more than the maximum allowed period (1h0m0s>1m0s)",
   173  		},
   174  		{
   175  			name: "validity larger than max due to inclusivity",
   176  			issuer: &Issuer{
   177  				active: true,
   178  			},
   179  			profile: &Profile{
   180  				maxValidity: time.Hour,
   181  			},
   182  			request: &IssuanceRequest{
   183  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   184  				SubjectKeyId: goodSKID,
   185  				NotBefore:    fc.Now(),
   186  				NotAfter:     fc.Now().Add(time.Hour),
   187  			},
   188  			expectedError: "validity period is more than the maximum allowed period (1h0m1s>1h0m0s)",
   189  		},
   190  		{
   191  			name: "validity backdated more than max",
   192  			issuer: &Issuer{
   193  				active: true,
   194  			},
   195  			profile: &Profile{
   196  				maxValidity: time.Hour * 2,
   197  				maxBackdate: time.Hour,
   198  			},
   199  			request: &IssuanceRequest{
   200  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   201  				SubjectKeyId: goodSKID,
   202  				NotBefore:    fc.Now().Add(-time.Hour * 2),
   203  				NotAfter:     fc.Now().Add(-time.Hour),
   204  			},
   205  			expectedError: "NotBefore is backdated more than the maximum allowed period (2h0m0s>1h0m0s)",
   206  		},
   207  		{
   208  			name: "validity is forward dated",
   209  			issuer: &Issuer{
   210  				active: true,
   211  			},
   212  			profile: &Profile{
   213  				maxValidity: time.Hour * 2,
   214  				maxBackdate: time.Hour,
   215  			},
   216  			request: &IssuanceRequest{
   217  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   218  				SubjectKeyId: goodSKID,
   219  				NotBefore:    fc.Now().Add(time.Hour),
   220  				NotAfter:     fc.Now().Add(time.Hour * 2),
   221  			},
   222  			expectedError: "NotBefore is in the future",
   223  		},
   224  		{
   225  			name: "serial too short",
   226  			issuer: &Issuer{
   227  				active: true,
   228  			},
   229  			profile: &Profile{
   230  				maxValidity: time.Hour * 2,
   231  			},
   232  			request: &IssuanceRequest{
   233  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   234  				SubjectKeyId: goodSKID,
   235  				NotBefore:    fc.Now(),
   236  				NotAfter:     fc.Now().Add(time.Hour),
   237  				Serial:       []byte{0, 1, 2, 3, 4, 5, 6, 7},
   238  			},
   239  			expectedError: "serial must be between 9 and 19 bytes",
   240  		},
   241  		{
   242  			name: "serial too long",
   243  			issuer: &Issuer{
   244  				active: true,
   245  			},
   246  			profile: &Profile{
   247  				maxValidity: time.Hour * 2,
   248  			},
   249  			request: &IssuanceRequest{
   250  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   251  				SubjectKeyId: goodSKID,
   252  				NotBefore:    fc.Now(),
   253  				NotAfter:     fc.Now().Add(time.Hour),
   254  				Serial:       []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
   255  			},
   256  			expectedError: "serial must be between 9 and 19 bytes",
   257  		},
   258  		{
   259  			name: "good with poison",
   260  			issuer: &Issuer{
   261  				active: true,
   262  			},
   263  			profile: &Profile{
   264  				maxValidity: time.Hour * 2,
   265  			},
   266  			request: &IssuanceRequest{
   267  				PublicKey:       MarshalablePublicKey{&ecdsa.PublicKey{}},
   268  				SubjectKeyId:    goodSKID,
   269  				NotBefore:       fc.Now(),
   270  				NotAfter:        fc.Now().Add(time.Hour),
   271  				Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   272  				IncludeCTPoison: true,
   273  			},
   274  		},
   275  		{
   276  			name: "good with scts",
   277  			issuer: &Issuer{
   278  				active: true,
   279  			},
   280  			profile: &Profile{
   281  				maxValidity: time.Hour * 2,
   282  			},
   283  			request: &IssuanceRequest{
   284  				PublicKey:    MarshalablePublicKey{&ecdsa.PublicKey{}},
   285  				SubjectKeyId: goodSKID,
   286  				NotBefore:    fc.Now(),
   287  				NotAfter:     fc.Now().Add(time.Hour),
   288  				Serial:       []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   289  				sctList:      []ct.SignedCertificateTimestamp{},
   290  			},
   291  		},
   292  	}
   293  	for _, tc := range tests {
   294  		t.Run(tc.name, func(t *testing.T) {
   295  			err := tc.issuer.requestValid(fc, tc.profile, tc.request)
   296  			if err != nil {
   297  				if tc.expectedError == "" {
   298  					t.Errorf("failed with unexpected error: %s", err)
   299  				} else if tc.expectedError != err.Error() {
   300  					t.Errorf("failed with unexpected error, wanted: %q, got: %q", tc.expectedError, err.Error())
   301  				}
   302  				return
   303  			} else if tc.expectedError != "" {
   304  				t.Errorf("didn't fail, expected %q", tc.expectedError)
   305  			}
   306  		})
   307  	}
   308  }
   309  
   310  func TestGenerateTemplate(t *testing.T) {
   311  	issuer := &Issuer{
   312  		issuerURL:  "http://issuer",
   313  		crlURLBase: "http://crl/",
   314  		sigAlg:     x509.SHA256WithRSA,
   315  	}
   316  
   317  	actual := issuer.generateTemplate()
   318  
   319  	expected := &x509.Certificate{
   320  		BasicConstraintsValid: true,
   321  		SignatureAlgorithm:    x509.SHA256WithRSA,
   322  		IssuingCertificateURL: []string{"http://issuer"},
   323  		Policies:              []x509.OID{domainValidatedOID},
   324  		// This field is computed based on the serial, so is not included in the template.
   325  		CRLDistributionPoints: nil,
   326  	}
   327  
   328  	test.AssertDeepEquals(t, actual, expected)
   329  }
   330  
   331  func TestIssue(t *testing.T) {
   332  	for _, tc := range []struct {
   333  		name         string
   334  		generateFunc func() (crypto.Signer, error)
   335  		ku           x509.KeyUsage
   336  	}{
   337  		{
   338  			name: "RSA",
   339  			generateFunc: func() (crypto.Signer, error) {
   340  				return rsa.GenerateKey(rand.Reader, 2048)
   341  			},
   342  			ku: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
   343  		},
   344  		{
   345  			name: "ECDSA",
   346  			generateFunc: func() (crypto.Signer, error) {
   347  				return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   348  			},
   349  			ku: x509.KeyUsageDigitalSignature,
   350  		},
   351  	} {
   352  		t.Run(tc.name, func(t *testing.T) {
   353  			fc := clock.NewFake()
   354  			fc.Set(time.Now())
   355  			signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   356  			test.AssertNotError(t, err, "NewIssuer failed")
   357  			pk, err := tc.generateFunc()
   358  			test.AssertNotError(t, err, "failed to generate test key")
   359  			lintCertBytes, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{
   360  				PublicKey:       MarshalablePublicKey{pk.Public()},
   361  				SubjectKeyId:    goodSKID,
   362  				Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   363  				DNSNames:        []string{"example.com"},
   364  				IPAddresses:     []net.IP{net.ParseIP("128.101.101.101"), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")},
   365  				NotBefore:       fc.Now(),
   366  				NotAfter:        fc.Now().Add(time.Hour - time.Second),
   367  				IncludeCTPoison: true,
   368  			})
   369  			test.AssertNotError(t, err, "Prepare failed")
   370  			_, err = x509.ParseCertificate(lintCertBytes)
   371  			test.AssertNotError(t, err, "failed to parse certificate")
   372  			certBytes, err := signer.Issue(issuanceToken)
   373  			test.AssertNotError(t, err, "Issue failed")
   374  			cert, err := x509.ParseCertificate(certBytes)
   375  			test.AssertNotError(t, err, "failed to parse certificate")
   376  			err = cert.CheckSignatureFrom(issuerCert.Certificate)
   377  			test.AssertNotError(t, err, "signature validation failed")
   378  			test.AssertDeepEquals(t, cert.DNSNames, []string{"example.com"})
   379  			// net.ParseIP always returns a 16-byte address; IPv4 addresses are
   380  			// returned in IPv4-mapped IPv6 form. But RFC 5280, Sec. 4.2.1.6
   381  			// requires that IPv4 addresses be encoded as 4 bytes.
   382  			//
   383  			// The issuance pipeline calls x509.marshalSANs, which reduces IPv4
   384  			// addresses back to 4 bytes. Adding .To4() both allows this test to
   385  			// succeed, and covers this requirement.
   386  			test.AssertDeepEquals(t, cert.IPAddresses, []net.IP{net.ParseIP("128.101.101.101").To4(), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")})
   387  			test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
   388  			test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
   389  			test.AssertEquals(t, len(cert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison
   390  			test.AssertEquals(t, cert.KeyUsage, tc.ku)
   391  			if len(cert.CRLDistributionPoints) != 1 || !strings.HasPrefix(cert.CRLDistributionPoints[0], "http://crl-url.example.org/") {
   392  				t.Errorf("want CRLDistributionPoints=[http://crl-url.example.org/x.crl], got %v", cert.CRLDistributionPoints)
   393  			}
   394  		})
   395  	}
   396  }
   397  
   398  func TestIssueDNSNamesOnly(t *testing.T) {
   399  	fc := clock.NewFake()
   400  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   401  	if err != nil {
   402  		t.Fatalf("newIssuer: %s", err)
   403  	}
   404  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   405  	if err != nil {
   406  		t.Fatalf("ecdsa.GenerateKey: %s", err)
   407  	}
   408  	_, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{
   409  		PublicKey:       MarshalablePublicKey{pk.Public()},
   410  		SubjectKeyId:    goodSKID,
   411  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   412  		DNSNames:        []string{"example.com"},
   413  		NotBefore:       fc.Now(),
   414  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   415  		IncludeCTPoison: true,
   416  	})
   417  	if err != nil {
   418  		t.Fatalf("signer.Prepare: %s", err)
   419  	}
   420  	certBytes, err := signer.Issue(issuanceToken)
   421  	if err != nil {
   422  		t.Fatalf("signer.Issue: %s", err)
   423  	}
   424  	cert, err := x509.ParseCertificate(certBytes)
   425  	if err != nil {
   426  		t.Fatalf("x509.ParseCertificate: %s", err)
   427  	}
   428  	if !reflect.DeepEqual(cert.DNSNames, []string{"example.com"}) {
   429  		t.Errorf("got DNSNames %s, wanted example.com", cert.DNSNames)
   430  	}
   431  	// BRs 7.1.2.7.12 requires iPAddress, if present, to contain an entry.
   432  	if cert.IPAddresses != nil {
   433  		t.Errorf("got IPAddresses %s, wanted nil", cert.IPAddresses)
   434  	}
   435  }
   436  
   437  func TestIssueIPAddressesOnly(t *testing.T) {
   438  	fc := clock.NewFake()
   439  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   440  	if err != nil {
   441  		t.Fatalf("newIssuer: %s", err)
   442  	}
   443  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   444  	if err != nil {
   445  		t.Fatalf("ecdsa.GenerateKey: %s", err)
   446  	}
   447  	_, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{
   448  		PublicKey:       MarshalablePublicKey{pk.Public()},
   449  		SubjectKeyId:    goodSKID,
   450  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   451  		IPAddresses:     []net.IP{net.ParseIP("128.101.101.101"), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")},
   452  		NotBefore:       fc.Now(),
   453  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   454  		IncludeCTPoison: true,
   455  	})
   456  	if err != nil {
   457  		t.Fatalf("signer.Prepare: %s", err)
   458  	}
   459  	certBytes, err := signer.Issue(issuanceToken)
   460  	if err != nil {
   461  		t.Fatalf("signer.Issue: %s", err)
   462  	}
   463  	cert, err := x509.ParseCertificate(certBytes)
   464  	if err != nil {
   465  		t.Fatalf("x509.ParseCertificate: %s", err)
   466  	}
   467  	// BRs 7.1.2.7.12 requires dNSName, if present, to contain an entry.
   468  	if cert.DNSNames != nil {
   469  		t.Errorf("got DNSNames %s, wanted nil", cert.DNSNames)
   470  	}
   471  	if !reflect.DeepEqual(cert.IPAddresses, []net.IP{net.ParseIP("128.101.101.101").To4(), net.ParseIP("3fff:aaa:a:c0ff:ee:a:bad:deed")}) {
   472  		t.Errorf("got IPAddresses %s, wanted 128.101.101.101 (4-byte) & 3fff:aaa:a:c0ff:ee:a:bad:deed (16-byte)", cert.IPAddresses)
   473  	}
   474  }
   475  
   476  func TestIssueWithCRLDP(t *testing.T) {
   477  	fc := clock.NewFake()
   478  	issuerConfig := defaultIssuerConfig()
   479  	issuerConfig.CRLURLBase = "http://crls.example.net/"
   480  	issuerConfig.CRLShards = 999
   481  	signer, err := newIssuer(issuerConfig, issuerCert, issuerSigner, fc)
   482  	if err != nil {
   483  		t.Fatalf("newIssuer: %s", err)
   484  	}
   485  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   486  	if err != nil {
   487  		t.Fatalf("ecdsa.GenerateKey: %s", err)
   488  	}
   489  	profile := defaultProfile()
   490  	_, issuanceToken, err := signer.Prepare(profile, &IssuanceRequest{
   491  		PublicKey:       MarshalablePublicKey{pk.Public()},
   492  		SubjectKeyId:    goodSKID,
   493  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   494  		DNSNames:        []string{"example.com"},
   495  		NotBefore:       fc.Now(),
   496  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   497  		IncludeCTPoison: true,
   498  	})
   499  	if err != nil {
   500  		t.Fatalf("signer.Prepare: %s", err)
   501  	}
   502  	certBytes, err := signer.Issue(issuanceToken)
   503  	if err != nil {
   504  		t.Fatalf("signer.Issue: %s", err)
   505  	}
   506  	cert, err := x509.ParseCertificate(certBytes)
   507  	if err != nil {
   508  		t.Fatalf("x509.ParseCertificate: %s", err)
   509  	}
   510  	// Because CRL shard is calculated deterministically from serial, we know which shard will be chosen.
   511  	expectedCRLDP := []string{"http://crls.example.net/919.crl"}
   512  	if !reflect.DeepEqual(cert.CRLDistributionPoints, expectedCRLDP) {
   513  		t.Errorf("CRLDP=%+v, want %+v", cert.CRLDistributionPoints, expectedCRLDP)
   514  	}
   515  }
   516  
   517  func TestIssueCommonName(t *testing.T) {
   518  	fc := clock.NewFake()
   519  	fc.Set(time.Now())
   520  
   521  	prof := defaultProfileConfig()
   522  	prof.IgnoredLints = append(prof.IgnoredLints, "w_subject_common_name_included")
   523  	cnProfile, err := NewProfile(prof)
   524  	test.AssertNotError(t, err, "NewProfile failed")
   525  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   526  	test.AssertNotError(t, err, "NewIssuer failed")
   527  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   528  	test.AssertNotError(t, err, "failed to generate test key")
   529  	ir := &IssuanceRequest{
   530  		PublicKey:       MarshalablePublicKey{pk.Public()},
   531  		SubjectKeyId:    goodSKID,
   532  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   533  		DNSNames:        []string{"example.com", "www.example.com"},
   534  		NotBefore:       fc.Now(),
   535  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   536  		IncludeCTPoison: true,
   537  	}
   538  
   539  	// In the default profile, the common name is allowed if requested.
   540  	ir.CommonName = "example.com"
   541  	_, issuanceToken, err := signer.Prepare(cnProfile, ir)
   542  	test.AssertNotError(t, err, "Prepare failed")
   543  	certBytes, err := signer.Issue(issuanceToken)
   544  	test.AssertNotError(t, err, "Issue failed")
   545  	cert, err := x509.ParseCertificate(certBytes)
   546  	test.AssertNotError(t, err, "failed to parse certificate")
   547  	test.AssertEquals(t, cert.Subject.CommonName, "example.com")
   548  
   549  	// But not including the common name should be acceptable as well.
   550  	ir.CommonName = ""
   551  	_, issuanceToken, err = signer.Prepare(cnProfile, ir)
   552  	test.AssertNotError(t, err, "Prepare failed")
   553  	certBytes, err = signer.Issue(issuanceToken)
   554  	test.AssertNotError(t, err, "Issue failed")
   555  	cert, err = x509.ParseCertificate(certBytes)
   556  	test.AssertNotError(t, err, "failed to parse certificate")
   557  	test.AssertEquals(t, cert.Subject.CommonName, "")
   558  
   559  	// And the common name should be omitted if the profile is so configured.
   560  	ir.CommonName = "example.com"
   561  	cnProfile.omitCommonName = true
   562  	_, issuanceToken, err = signer.Prepare(cnProfile, ir)
   563  	test.AssertNotError(t, err, "Prepare failed")
   564  	certBytes, err = signer.Issue(issuanceToken)
   565  	test.AssertNotError(t, err, "Issue failed")
   566  	cert, err = x509.ParseCertificate(certBytes)
   567  	test.AssertNotError(t, err, "failed to parse certificate")
   568  	test.AssertEquals(t, cert.Subject.CommonName, "")
   569  }
   570  
   571  func TestIssueOmissions(t *testing.T) {
   572  	fc := clock.NewFake()
   573  	fc.Set(time.Now())
   574  
   575  	pc := defaultProfileConfig()
   576  	pc.OmitCommonName = true
   577  	pc.OmitKeyEncipherment = true
   578  	pc.OmitClientAuth = true
   579  	pc.OmitSKID = true
   580  	pc.IgnoredLints = []string{
   581  		// Reduce the lint ignores to just the minimal (SCT-related) set.
   582  		"w_ct_sct_policy_count_unsatisfied",
   583  		"e_scts_from_same_operator",
   584  		// Ignore the warning about *not* including the SubjectKeyIdentifier extension:
   585  		// zlint has both lints (one enforcing RFC5280, the other the BRs).
   586  		"w_ext_subject_key_identifier_missing_sub_cert",
   587  	}
   588  	prof, err := NewProfile(pc)
   589  	test.AssertNotError(t, err, "building test profile")
   590  
   591  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   592  	test.AssertNotError(t, err, "NewIssuer failed")
   593  
   594  	pk, err := rsa.GenerateKey(rand.Reader, 2048)
   595  	test.AssertNotError(t, err, "failed to generate test key")
   596  	_, issuanceToken, err := signer.Prepare(prof, &IssuanceRequest{
   597  		PublicKey:       MarshalablePublicKey{pk.Public()},
   598  		SubjectKeyId:    goodSKID,
   599  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   600  		DNSNames:        []string{"example.com"},
   601  		CommonName:      "example.com",
   602  		IncludeCTPoison: true,
   603  		NotBefore:       fc.Now(),
   604  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   605  	})
   606  	test.AssertNotError(t, err, "Prepare failed")
   607  	certBytes, err := signer.Issue(issuanceToken)
   608  	test.AssertNotError(t, err, "Issue failed")
   609  	cert, err := x509.ParseCertificate(certBytes)
   610  	test.AssertNotError(t, err, "failed to parse certificate")
   611  
   612  	test.AssertEquals(t, cert.Subject.CommonName, "")
   613  	test.AssertEquals(t, cert.KeyUsage, x509.KeyUsageDigitalSignature)
   614  	test.AssertDeepEquals(t, cert.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth})
   615  	test.AssertEquals(t, len(cert.SubjectKeyId), 0)
   616  }
   617  
   618  func TestIssueCTPoison(t *testing.T) {
   619  	fc := clock.NewFake()
   620  	fc.Set(time.Now())
   621  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   622  	test.AssertNotError(t, err, "NewIssuer failed")
   623  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   624  	test.AssertNotError(t, err, "failed to generate test key")
   625  	_, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{
   626  		PublicKey:       MarshalablePublicKey{pk.Public()},
   627  		SubjectKeyId:    goodSKID,
   628  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   629  		DNSNames:        []string{"example.com"},
   630  		IncludeCTPoison: true,
   631  		NotBefore:       fc.Now(),
   632  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   633  	})
   634  	test.AssertNotError(t, err, "Prepare failed")
   635  	certBytes, err := signer.Issue(issuanceToken)
   636  	test.AssertNotError(t, err, "Issue failed")
   637  	cert, err := x509.ParseCertificate(certBytes)
   638  	test.AssertNotError(t, err, "failed to parse certificate")
   639  	err = cert.CheckSignatureFrom(issuerCert.Certificate)
   640  	test.AssertNotError(t, err, "signature validation failed")
   641  	test.AssertByteEquals(t, cert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
   642  	test.AssertDeepEquals(t, cert.PublicKey, pk.Public())
   643  	test.AssertEquals(t, len(cert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison
   644  	test.AssertDeepEquals(t, cert.Extensions[9], ctPoisonExt)
   645  }
   646  
   647  func mustDecodeB64(b string) []byte {
   648  	out, err := base64.StdEncoding.DecodeString(b)
   649  	if err != nil {
   650  		panic(err)
   651  	}
   652  	return out
   653  }
   654  
   655  func TestIssueSCTList(t *testing.T) {
   656  	fc := clock.NewFake()
   657  	fc.Set(time.Now())
   658  
   659  	err := loglist.InitLintList("../test/ct-test-srv/log_list.json")
   660  	test.AssertNotError(t, err, "failed to load log list")
   661  
   662  	pc := defaultProfileConfig()
   663  	pc.IgnoredLints = []string{
   664  		// Only ignore the SKID lint, i.e., don't ignore the "missing SCT" lints.
   665  		"w_ext_subject_key_identifier_not_recommended_subscriber",
   666  	}
   667  	enforceSCTsProfile, err := NewProfile(pc)
   668  	test.AssertNotError(t, err, "NewProfile failed")
   669  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   670  	test.AssertNotError(t, err, "NewIssuer failed")
   671  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   672  	test.AssertNotError(t, err, "failed to generate test key")
   673  	_, issuanceToken, err := signer.Prepare(enforceSCTsProfile, &IssuanceRequest{
   674  		PublicKey:       MarshalablePublicKey{pk.Public()},
   675  		SubjectKeyId:    goodSKID,
   676  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   677  		DNSNames:        []string{"example.com"},
   678  		NotBefore:       fc.Now(),
   679  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   680  		IncludeCTPoison: true,
   681  	})
   682  	test.AssertNotError(t, err, "Prepare failed")
   683  	precertBytes, err := signer.Issue(issuanceToken)
   684  	test.AssertNotError(t, err, "Issue failed")
   685  	precert, err := x509.ParseCertificate(precertBytes)
   686  	test.AssertNotError(t, err, "failed to parse certificate")
   687  
   688  	sctList := []ct.SignedCertificateTimestamp{
   689  		{
   690  			SCTVersion: ct.V1,
   691  			LogID:      ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))},
   692  		},
   693  		{
   694  			SCTVersion: ct.V1,
   695  			LogID:      ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("UtToynGEyMkkXDMQei8Ll54oMwWHI0IieDEKs12/Td4="))},
   696  		},
   697  	}
   698  
   699  	request2, err := RequestFromPrecert(precert, sctList)
   700  	test.AssertNotError(t, err, "generating request from precert")
   701  
   702  	_, issuanceToken2, err := signer.Prepare(enforceSCTsProfile, request2)
   703  	test.AssertNotError(t, err, "preparing final cert issuance")
   704  
   705  	finalCertBytes, err := signer.Issue(issuanceToken2)
   706  	test.AssertNotError(t, err, "Issue failed")
   707  
   708  	finalCert, err := x509.ParseCertificate(finalCertBytes)
   709  	test.AssertNotError(t, err, "failed to parse certificate")
   710  
   711  	err = finalCert.CheckSignatureFrom(issuerCert.Certificate)
   712  	test.AssertNotError(t, err, "signature validation failed")
   713  	test.AssertByteEquals(t, finalCert.SerialNumber.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9})
   714  	test.AssertDeepEquals(t, finalCert.PublicKey, pk.Public())
   715  	test.AssertEquals(t, len(finalCert.Extensions), 10) // Constraints, KU, EKU, SKID, AKID, AIA, CRLDP, SAN, Policies, Poison
   716  	test.AssertDeepEquals(t, finalCert.Extensions[9], pkix.Extension{
   717  		Id: sctListOID,
   718  		Value: []byte{
   719  			4, 100, 0, 98, 0, 47, 0, 56, 152, 140, 148, 208, 53, 152, 195, 147, 45,
   720  			223, 233, 35, 186, 186, 242, 122, 66, 14, 185, 108, 65, 225, 90, 168, 12,
   721  			26, 176, 252, 4, 189, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47,
   722  			0, 82, 212, 232, 202, 113, 132, 200, 201, 36, 92, 51, 16, 122, 47, 11,
   723  			151, 158, 40, 51, 5, 135, 35, 66, 34, 120, 49, 10, 179, 93, 191, 77, 222,
   724  			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   725  		},
   726  	})
   727  }
   728  
   729  func TestIssueBadLint(t *testing.T) {
   730  	fc := clock.NewFake()
   731  	fc.Set(time.Now())
   732  
   733  	pc := defaultProfileConfig()
   734  	pc.IgnoredLints = []string{}
   735  	noSkipLintsProfile, err := NewProfile(pc)
   736  	test.AssertNotError(t, err, "NewProfile failed")
   737  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   738  	test.AssertNotError(t, err, "NewIssuer failed")
   739  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   740  	test.AssertNotError(t, err, "failed to generate test key")
   741  	_, _, err = signer.Prepare(noSkipLintsProfile, &IssuanceRequest{
   742  		PublicKey:       MarshalablePublicKey{pk.Public()},
   743  		SubjectKeyId:    goodSKID,
   744  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   745  		DNSNames:        []string{"example-com"},
   746  		NotBefore:       fc.Now(),
   747  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   748  		IncludeCTPoison: true,
   749  	})
   750  	test.AssertError(t, err, "Prepare didn't fail")
   751  	test.AssertErrorIs(t, err, linter.ErrLinting)
   752  	test.AssertContains(t, err.Error(), "tbsCertificate linting failed: failed lint(s)")
   753  }
   754  
   755  func TestIssuanceToken(t *testing.T) {
   756  	fc := clock.NewFake()
   757  	fc.Set(time.Now())
   758  
   759  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   760  	test.AssertNotError(t, err, "NewIssuer failed")
   761  
   762  	_, err = signer.Issue(&issuanceToken{})
   763  	test.AssertError(t, err, "expected issuance with a zero token to fail")
   764  
   765  	_, err = signer.Issue(nil)
   766  	test.AssertError(t, err, "expected issuance with a nil token to fail")
   767  
   768  	pk, err := rsa.GenerateKey(rand.Reader, 2048)
   769  	test.AssertNotError(t, err, "failed to generate test key")
   770  	_, issuanceToken, err := signer.Prepare(defaultProfile(), &IssuanceRequest{
   771  		PublicKey:       MarshalablePublicKey{pk.Public()},
   772  		SubjectKeyId:    goodSKID,
   773  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   774  		DNSNames:        []string{"example.com"},
   775  		NotBefore:       fc.Now(),
   776  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   777  		IncludeCTPoison: true,
   778  	})
   779  	test.AssertNotError(t, err, "expected Prepare to succeed")
   780  	_, err = signer.Issue(issuanceToken)
   781  	test.AssertNotError(t, err, "expected first issuance to succeed")
   782  
   783  	_, err = signer.Issue(issuanceToken)
   784  	test.AssertError(t, err, "expected second issuance with the same issuance token to fail")
   785  	test.AssertContains(t, err.Error(), "issuance token already redeemed")
   786  
   787  	_, issuanceToken, err = signer.Prepare(defaultProfile(), &IssuanceRequest{
   788  		PublicKey:       MarshalablePublicKey{pk.Public()},
   789  		SubjectKeyId:    goodSKID,
   790  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   791  		DNSNames:        []string{"example.com"},
   792  		NotBefore:       fc.Now(),
   793  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   794  		IncludeCTPoison: true,
   795  	})
   796  	test.AssertNotError(t, err, "expected Prepare to succeed")
   797  
   798  	signer2, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   799  	test.AssertNotError(t, err, "NewIssuer failed")
   800  
   801  	_, err = signer2.Issue(issuanceToken)
   802  	test.AssertError(t, err, "expected redeeming an issuance token with the wrong issuer to fail")
   803  	test.AssertContains(t, err.Error(), "wrong issuer")
   804  }
   805  
   806  func TestInvalidProfile(t *testing.T) {
   807  	fc := clock.NewFake()
   808  	fc.Set(time.Now())
   809  
   810  	err := loglist.InitLintList("../test/ct-test-srv/log_list.json")
   811  	test.AssertNotError(t, err, "failed to load log list")
   812  
   813  	signer, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   814  	test.AssertNotError(t, err, "NewIssuer failed")
   815  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   816  	test.AssertNotError(t, err, "failed to generate test key")
   817  	_, _, err = signer.Prepare(defaultProfile(), &IssuanceRequest{
   818  		PublicKey:       MarshalablePublicKey{pk.Public()},
   819  		SubjectKeyId:    goodSKID,
   820  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   821  		DNSNames:        []string{"example.com"},
   822  		NotBefore:       fc.Now(),
   823  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   824  		IncludeCTPoison: true,
   825  		precertDER:      []byte{6, 6, 6},
   826  	})
   827  	test.AssertError(t, err, "Invalid IssuanceRequest")
   828  
   829  	_, _, err = signer.Prepare(defaultProfile(), &IssuanceRequest{
   830  		PublicKey:    MarshalablePublicKey{pk.Public()},
   831  		SubjectKeyId: goodSKID,
   832  		Serial:       []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   833  		DNSNames:     []string{"example.com"},
   834  		NotBefore:    fc.Now(),
   835  		NotAfter:     fc.Now().Add(time.Hour - time.Second),
   836  		sctList: []ct.SignedCertificateTimestamp{
   837  			{
   838  				SCTVersion: ct.V1,
   839  				LogID:      ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))},
   840  			},
   841  		},
   842  		precertDER: []byte{},
   843  	})
   844  	test.AssertError(t, err, "Invalid IssuanceRequest")
   845  }
   846  
   847  // Generate a precert from one profile and a final cert from another, and verify
   848  // that the final cert errors out when linted because the lint cert doesn't
   849  // corresponding with the precert.
   850  func TestMismatchedProfiles(t *testing.T) {
   851  	fc := clock.NewFake()
   852  	fc.Set(time.Now())
   853  	err := loglist.InitLintList("../test/ct-test-srv/log_list.json")
   854  	test.AssertNotError(t, err, "failed to load log list")
   855  
   856  	issuer1, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   857  	test.AssertNotError(t, err, "NewIssuer failed")
   858  
   859  	pc := defaultProfileConfig()
   860  	pc.IgnoredLints = append(pc.IgnoredLints, "w_subject_common_name_included")
   861  	cnProfile, err := NewProfile(pc)
   862  	test.AssertNotError(t, err, "NewProfile failed")
   863  
   864  	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   865  	test.AssertNotError(t, err, "failed to generate test key")
   866  	_, issuanceToken, err := issuer1.Prepare(cnProfile, &IssuanceRequest{
   867  		PublicKey:       MarshalablePublicKey{pk.Public()},
   868  		SubjectKeyId:    goodSKID,
   869  		Serial:          []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},
   870  		CommonName:      "example.com",
   871  		DNSNames:        []string{"example.com"},
   872  		NotBefore:       fc.Now(),
   873  		NotAfter:        fc.Now().Add(time.Hour - time.Second),
   874  		IncludeCTPoison: true,
   875  	})
   876  	test.AssertNotError(t, err, "making IssuanceRequest")
   877  
   878  	precertDER, err := issuer1.Issue(issuanceToken)
   879  	test.AssertNotError(t, err, "signing precert")
   880  
   881  	// Create a new profile that differs slightly (no common name)
   882  	pc = defaultProfileConfig()
   883  	pc.OmitCommonName = false
   884  	test.AssertNotError(t, err, "building test lint registry")
   885  	noCNProfile, err := NewProfile(pc)
   886  	test.AssertNotError(t, err, "NewProfile failed")
   887  
   888  	issuer2, err := newIssuer(defaultIssuerConfig(), issuerCert, issuerSigner, fc)
   889  	test.AssertNotError(t, err, "NewIssuer failed")
   890  
   891  	sctList := []ct.SignedCertificateTimestamp{
   892  		{
   893  			SCTVersion: ct.V1,
   894  			LogID:      ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("OJiMlNA1mMOTLd/pI7q68npCDrlsQeFaqAwasPwEvQM="))},
   895  		},
   896  		{
   897  			SCTVersion: ct.V1,
   898  			LogID:      ct.LogID{KeyID: *(*[32]byte)(mustDecodeB64("UtToynGEyMkkXDMQei8Ll54oMwWHI0IieDEKs12/Td4="))},
   899  		},
   900  	}
   901  
   902  	precert, err := x509.ParseCertificate(precertDER)
   903  	test.AssertNotError(t, err, "parsing precert")
   904  
   905  	request2, err := RequestFromPrecert(precert, sctList)
   906  	test.AssertNotError(t, err, "RequestFromPrecert")
   907  	request2.CommonName = ""
   908  
   909  	_, _, err = issuer2.Prepare(noCNProfile, request2)
   910  	test.AssertError(t, err, "preparing final cert issuance")
   911  	test.AssertContains(t, err.Error(), "precert does not correspond to linted final cert")
   912  }
   913  
   914  func TestNewProfile(t *testing.T) {
   915  	for _, tc := range []struct {
   916  		name    string
   917  		config  ProfileConfig
   918  		wantErr string
   919  	}{
   920  		{
   921  			name: "happy path",
   922  			config: ProfileConfig{
   923  				MaxValidityBackdate: config.Duration{Duration: 1 * time.Hour},
   924  				MaxValidityPeriod:   config.Duration{Duration: 90 * 24 * time.Hour},
   925  			},
   926  		},
   927  		{
   928  			name: "large backdate",
   929  			config: ProfileConfig{
   930  				MaxValidityBackdate: config.Duration{Duration: 24 * time.Hour},
   931  				MaxValidityPeriod:   config.Duration{Duration: 90 * 24 * time.Hour},
   932  			},
   933  			wantErr: "backdate \"24h0m0s\" is too large",
   934  		},
   935  		{
   936  			name: "large validity",
   937  			config: ProfileConfig{
   938  				MaxValidityBackdate: config.Duration{Duration: 1 * time.Hour},
   939  				MaxValidityPeriod:   config.Duration{Duration: 397 * 24 * time.Hour},
   940  			},
   941  			wantErr: "validity period \"9528h0m0s\" is too large",
   942  		},
   943  	} {
   944  		t.Run(tc.name, func(t *testing.T) {
   945  			gotProfile, gotErr := NewProfile(tc.config)
   946  			if tc.wantErr != "" {
   947  				if gotErr == nil {
   948  					t.Errorf("NewProfile(%#v) = %#v, but want err %q", tc.config, gotProfile, tc.wantErr)
   949  				}
   950  				if !strings.Contains(gotErr.Error(), tc.wantErr) {
   951  					t.Errorf("NewProfile(%#v) = %q, but want %q", tc.config, gotErr, tc.wantErr)
   952  				}
   953  			} else {
   954  				if gotErr != nil {
   955  					t.Errorf("NewProfile(%#v) = %q, but want no error", tc.config, gotErr)
   956  				}
   957  			}
   958  		})
   959  	}
   960  }