...

Source file src/github.com/letsencrypt/boulder/csr/csr_test.go

Documentation: github.com/letsencrypt/boulder/csr

     1  package csr
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"crypto/rsa"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"encoding/asn1"
    10  	"errors"
    11  	"net"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/letsencrypt/boulder/core"
    16  	berrors "github.com/letsencrypt/boulder/errors"
    17  	"github.com/letsencrypt/boulder/features"
    18  	"github.com/letsencrypt/boulder/goodkey"
    19  	"github.com/letsencrypt/boulder/identifier"
    20  	"github.com/letsencrypt/boulder/test"
    21  )
    22  
    23  var testingPolicy = &goodkey.KeyPolicy{
    24  	AllowRSA:           true,
    25  	AllowECDSANISTP256: true,
    26  	AllowECDSANISTP384: true,
    27  }
    28  
    29  type mockPA struct{}
    30  
    31  func (pa *mockPA) ChallengesFor(identifier identifier.ACMEIdentifier) (challenges []core.Challenge, err error) {
    32  	return
    33  }
    34  
    35  func (pa *mockPA) WillingToIssueWildcards(idents []identifier.ACMEIdentifier) error {
    36  	for _, ident := range idents {
    37  		if ident.Value == "bad-name.com" || ident.Value == "other-bad-name.com" {
    38  			return errors.New("policy forbids issuing for identifier")
    39  		}
    40  	}
    41  	return nil
    42  }
    43  
    44  func (pa *mockPA) ChallengeTypeEnabled(t core.AcmeChallenge) bool {
    45  	return true
    46  }
    47  
    48  func (pa *mockPA) CheckAuthz(a *core.Authorization) error {
    49  	return nil
    50  }
    51  
    52  func TestVerifyCSR(t *testing.T) {
    53  	private, err := rsa.GenerateKey(rand.Reader, 2048)
    54  	test.AssertNotError(t, err, "error generating test key")
    55  	signedReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{PublicKey: private.PublicKey, SignatureAlgorithm: x509.SHA256WithRSA}, private)
    56  	test.AssertNotError(t, err, "error generating test CSR")
    57  	signedReq, err := x509.ParseCertificateRequest(signedReqBytes)
    58  	test.AssertNotError(t, err, "error parsing test CSR")
    59  	brokenSignedReq := new(x509.CertificateRequest)
    60  	*brokenSignedReq = *signedReq
    61  	brokenSignedReq.Signature = []byte{1, 1, 1, 1}
    62  	signedReqWithHosts := new(x509.CertificateRequest)
    63  	*signedReqWithHosts = *signedReq
    64  	signedReqWithHosts.DNSNames = []string{"a.com", "b.com"}
    65  	signedReqWithLongCN := new(x509.CertificateRequest)
    66  	*signedReqWithLongCN = *signedReq
    67  	signedReqWithLongCN.Subject.CommonName = strings.Repeat("a", maxCNLength+1)
    68  	signedReqWithBadNames := new(x509.CertificateRequest)
    69  	*signedReqWithBadNames = *signedReq
    70  	signedReqWithBadNames.DNSNames = []string{"bad-name.com", "other-bad-name.com"}
    71  	signedReqWithEmailAddress := new(x509.CertificateRequest)
    72  	*signedReqWithEmailAddress = *signedReq
    73  	signedReqWithEmailAddress.EmailAddresses = []string{"foo@bar.com"}
    74  	signedReqWithIPAddress := new(x509.CertificateRequest)
    75  	*signedReqWithIPAddress = *signedReq
    76  	signedReqWithIPAddress.IPAddresses = []net.IP{net.IPv4(1, 2, 3, 4)}
    77  	signedReqWithAllLongSANs := new(x509.CertificateRequest)
    78  	*signedReqWithAllLongSANs = *signedReq
    79  	signedReqWithAllLongSANs.DNSNames = []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com"}
    80  
    81  	cases := []struct {
    82  		csr           *x509.CertificateRequest
    83  		maxNames      int
    84  		keyPolicy     *goodkey.KeyPolicy
    85  		pa            core.PolicyAuthority
    86  		expectedError error
    87  	}{
    88  		{
    89  			&x509.CertificateRequest{},
    90  			100,
    91  			testingPolicy,
    92  			&mockPA{},
    93  			invalidPubKey,
    94  		},
    95  		{
    96  			&x509.CertificateRequest{PublicKey: &private.PublicKey},
    97  			100,
    98  			testingPolicy,
    99  			&mockPA{},
   100  			unsupportedSigAlg,
   101  		},
   102  		{
   103  			brokenSignedReq,
   104  			100,
   105  			testingPolicy,
   106  			&mockPA{},
   107  			invalidSig,
   108  		},
   109  		{
   110  			signedReq,
   111  			100,
   112  			testingPolicy,
   113  			&mockPA{},
   114  			invalidNoDNS,
   115  		},
   116  		{
   117  			signedReqWithLongCN,
   118  			100,
   119  			testingPolicy,
   120  			&mockPA{},
   121  			berrors.BadCSRError("CN was longer than %d bytes", maxCNLength),
   122  		},
   123  		{
   124  			signedReqWithHosts,
   125  			1,
   126  			testingPolicy,
   127  			&mockPA{},
   128  			berrors.BadCSRError("CSR contains more than 1 DNS names"),
   129  		},
   130  		{
   131  			signedReqWithBadNames,
   132  			100,
   133  			testingPolicy,
   134  			&mockPA{},
   135  			errors.New("policy forbids issuing for identifier"),
   136  		},
   137  		{
   138  			signedReqWithEmailAddress,
   139  			100,
   140  			testingPolicy,
   141  			&mockPA{},
   142  			invalidEmailPresent,
   143  		},
   144  		{
   145  			signedReqWithIPAddress,
   146  			100,
   147  			testingPolicy,
   148  			&mockPA{},
   149  			invalidIPPresent,
   150  		},
   151  		{
   152  			signedReqWithAllLongSANs,
   153  			100,
   154  			testingPolicy,
   155  			&mockPA{},
   156  			invalidAllSANTooLong,
   157  		},
   158  	}
   159  
   160  	for _, c := range cases {
   161  		err := VerifyCSR(context.Background(), c.csr, c.maxNames, c.keyPolicy, c.pa)
   162  		test.AssertDeepEquals(t, c.expectedError, err)
   163  	}
   164  }
   165  
   166  func TestNamesFromCSR(t *testing.T) {
   167  	tooLongString := strings.Repeat("a", maxCNLength+1)
   168  
   169  	cases := []struct {
   170  		name          string
   171  		csr           *x509.CertificateRequest
   172  		expectedCN    string
   173  		expectedNames []string
   174  	}{
   175  		{
   176  			"no explicit CN",
   177  			&x509.CertificateRequest{DNSNames: []string{"a.com"}},
   178  			"a.com",
   179  			[]string{"a.com"},
   180  		},
   181  		{
   182  			"explicit uppercase CN",
   183  			&x509.CertificateRequest{Subject: pkix.Name{CommonName: "A.com"}, DNSNames: []string{"a.com"}},
   184  			"a.com",
   185  			[]string{"a.com"},
   186  		},
   187  		{
   188  			"no explicit CN, uppercase SAN",
   189  			&x509.CertificateRequest{DNSNames: []string{"A.com"}},
   190  			"a.com",
   191  			[]string{"a.com"},
   192  		},
   193  		{
   194  			"duplicate SANs",
   195  			&x509.CertificateRequest{DNSNames: []string{"b.com", "b.com", "a.com", "a.com"}},
   196  			"b.com",
   197  			[]string{"a.com", "b.com"},
   198  		},
   199  		{
   200  			"explicit CN not found in SANs",
   201  			&x509.CertificateRequest{Subject: pkix.Name{CommonName: "a.com"}, DNSNames: []string{"b.com"}},
   202  			"a.com",
   203  			[]string{"a.com", "b.com"},
   204  		},
   205  		{
   206  			"no explicit CN, too long leading SANs",
   207  			&x509.CertificateRequest{DNSNames: []string{
   208  				tooLongString + ".a.com",
   209  				tooLongString + ".b.com",
   210  				"a.com",
   211  				"b.com",
   212  			}},
   213  			"a.com",
   214  			[]string{"a.com", tooLongString + ".a.com", tooLongString + ".b.com", "b.com"},
   215  		},
   216  		{
   217  			"explicit CN, too long leading SANs",
   218  			&x509.CertificateRequest{
   219  				Subject: pkix.Name{CommonName: "A.com"},
   220  				DNSNames: []string{
   221  					tooLongString + ".a.com",
   222  					tooLongString + ".b.com",
   223  					"a.com",
   224  					"b.com",
   225  				}},
   226  			"a.com",
   227  			[]string{"a.com", tooLongString + ".a.com", tooLongString + ".b.com", "b.com"},
   228  		},
   229  	}
   230  	for _, tc := range cases {
   231  		t.Run(tc.name, func(t *testing.T) {
   232  			names := NamesFromCSR(tc.csr)
   233  			test.AssertEquals(t, names.CN, tc.expectedCN)
   234  			test.AssertDeepEquals(t, names.SANs, tc.expectedNames)
   235  		})
   236  	}
   237  }
   238  
   239  func TestSHA1Deprecation(t *testing.T) {
   240  	features.Reset()
   241  
   242  	private, err := rsa.GenerateKey(rand.Reader, 2048)
   243  	test.AssertNotError(t, err, "error generating test key")
   244  
   245  	makeAndVerifyCsr := func(alg x509.SignatureAlgorithm) error {
   246  		csrBytes, err := x509.CreateCertificateRequest(rand.Reader,
   247  			&x509.CertificateRequest{
   248  				DNSNames:           []string{"example.com"},
   249  				SignatureAlgorithm: alg,
   250  				PublicKey:          &private.PublicKey,
   251  			}, private)
   252  		test.AssertNotError(t, err, "creating test CSR")
   253  
   254  		csr, err := x509.ParseCertificateRequest(csrBytes)
   255  		test.AssertNotError(t, err, "parsing test CSR")
   256  
   257  		return VerifyCSR(context.Background(), csr, 100, testingPolicy, &mockPA{})
   258  	}
   259  
   260  	err = makeAndVerifyCsr(x509.SHA256WithRSA)
   261  	test.AssertNotError(t, err, "SHA256 CSR should verify")
   262  
   263  	err = makeAndVerifyCsr(x509.SHA1WithRSA)
   264  	test.AssertError(t, err, "SHA1 CSR should not verify")
   265  }
   266  
   267  func TestDuplicateExtensionRejection(t *testing.T) {
   268  	private, err := rsa.GenerateKey(rand.Reader, 2048)
   269  	test.AssertNotError(t, err, "error generating test key")
   270  
   271  	csrBytes, err := x509.CreateCertificateRequest(rand.Reader,
   272  		&x509.CertificateRequest{
   273  			DNSNames:           []string{"example.com"},
   274  			SignatureAlgorithm: x509.SHA256WithRSA,
   275  			PublicKey:          &private.PublicKey,
   276  			ExtraExtensions: []pkix.Extension{
   277  				{Id: asn1.ObjectIdentifier{2, 5, 29, 1}, Value: []byte("hello")},
   278  				{Id: asn1.ObjectIdentifier{2, 5, 29, 1}, Value: []byte("world")},
   279  			},
   280  		}, private)
   281  	test.AssertNotError(t, err, "creating test CSR")
   282  
   283  	_, err = x509.ParseCertificateRequest(csrBytes)
   284  	test.AssertError(t, err, "CSR with duplicate extension OID should fail to parse")
   285  }
   286  

View as plain text