1 package main
2
3 import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rand"
8 "crypto/x509"
9 "crypto/x509/pkix"
10 "encoding/asn1"
11 "encoding/pem"
12 "io"
13 "math/big"
14 "testing"
15 "time"
16
17 "github.com/letsencrypt/boulder/test"
18 )
19
20 func TestGenerateCRLTimeBounds(t *testing.T) {
21 _, err := generateCRL(nil, nil, time.Now().Add(time.Hour), time.Now(), 1, nil)
22 test.AssertError(t, err, "generateCRL did not fail")
23 test.AssertEquals(t, err.Error(), "thisUpdate must be before nextUpdate")
24
25 _, err = generateCRL(nil, &x509.Certificate{
26 NotBefore: time.Now().Add(time.Hour),
27 NotAfter: time.Now(),
28 }, time.Now(), time.Now(), 1, nil)
29 test.AssertError(t, err, "generateCRL did not fail")
30 test.AssertEquals(t, err.Error(), "thisUpdate is before issuing certificate's notBefore")
31
32 _, err = generateCRL(nil, &x509.Certificate{
33 NotBefore: time.Now(),
34 NotAfter: time.Now().Add(time.Hour * 2),
35 }, time.Now().Add(time.Hour), time.Now().Add(time.Hour*3), 1, nil)
36 test.AssertError(t, err, "generateCRL did not fail")
37 test.AssertEquals(t, err.Error(), "nextUpdate is after issuing certificate's notAfter")
38
39 _, err = generateCRL(nil, &x509.Certificate{
40 NotBefore: time.Now(),
41 NotAfter: time.Now().Add(time.Hour * 24 * 370),
42 }, time.Now(), time.Now().Add(time.Hour*24*366), 1, nil)
43 test.AssertError(t, err, "generateCRL did not fail")
44 test.AssertEquals(t, err.Error(), "nextUpdate must be less than 12 months after thisUpdate")
45 }
46
47
48
49
50
51
52
53 type wrappedSigner struct{ k crypto.Signer }
54
55 func (p wrappedSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
56 return p.k.Sign(rand.Reader, digest, opts)
57 }
58
59 func (p wrappedSigner) Public() crypto.PublicKey {
60 return p.k.Public()
61 }
62
63 func TestGenerateCRLLints(t *testing.T) {
64 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
65 test.AssertNotError(t, err, "failed to generate test key")
66
67 cert := &x509.Certificate{
68 Subject: pkix.Name{CommonName: "asd"},
69 SerialNumber: big.NewInt(7),
70 NotBefore: time.Now(),
71 NotAfter: time.Now().Add(365 * 24 * time.Hour),
72 IsCA: true,
73 KeyUsage: x509.KeyUsageCRLSign,
74 SubjectKeyId: []byte{1, 2, 3},
75 }
76
77 certBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, k.Public(), k)
78 test.AssertNotError(t, err, "failed to generate test cert")
79 cert, err = x509.ParseCertificate(certBytes)
80 test.AssertNotError(t, err, "failed to parse test cert")
81
82
83
84 _, err = generateCRL(&wrappedSigner{k}, cert, time.Now().Add(time.Hour), time.Now().Add(100*24*time.Hour), 1, []x509.RevocationListEntry{
85 {
86 SerialNumber: big.NewInt(12345),
87 RevocationTime: time.Now().Add(time.Hour),
88 ReasonCode: 6,
89 },
90 })
91 test.AssertError(t, err, "generateCRL did not fail")
92 test.AssertContains(t, err.Error(), "e_crl_acceptable_reason_codes")
93 }
94
95 func TestGenerateCRL(t *testing.T) {
96 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
97 test.AssertNotError(t, err, "failed to generate test key")
98
99 template := &x509.Certificate{
100 Subject: pkix.Name{CommonName: "asd"},
101 SerialNumber: big.NewInt(7),
102 NotBefore: time.Now(),
103 NotAfter: time.Now().Add(365 * 24 * time.Hour),
104 IsCA: true,
105 BasicConstraintsValid: true,
106 KeyUsage: x509.KeyUsageCRLSign,
107 SubjectKeyId: []byte{1, 2, 3},
108 }
109
110 certBytes, err := x509.CreateCertificate(rand.Reader, template, template, k.Public(), k)
111 test.AssertNotError(t, err, "failed to generate test cert")
112 cert, err := x509.ParseCertificate(certBytes)
113 test.AssertNotError(t, err, "failed to parse test cert")
114
115 crlPEM, err := generateCRL(&wrappedSigner{k}, cert, time.Now().Add(time.Hour), time.Now().Add(time.Hour*2), 1, nil)
116 test.AssertNotError(t, err, "generateCRL failed with valid profile")
117
118 pemBlock, _ := pem.Decode(crlPEM)
119 crlDER := pemBlock.Bytes
120
121
122 goCRL, err := x509.ParseRevocationList(crlDER)
123 test.AssertNotError(t, err, "failed to parse CRL")
124 err = goCRL.CheckSignatureFrom(cert)
125 test.AssertNotError(t, err, "CRL signature check failed")
126 test.AssertEquals(t, len(goCRL.RevokedCertificateEntries), 0)
127
128
129
130 var crl asn1CRL
131 _, err = asn1.Unmarshal(crlDER, &crl)
132 test.AssertNotError(t, err, "failed to parse CRL")
133 test.AssertEquals(t, crl.TBS.Version, 1)
134 test.AssertEquals(t, len(crl.TBS.Extensions), 3)
135 test.Assert(t, crl.TBS.Extensions[1].Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 20}), "unexpected OID in extension")
136 test.Assert(t, crl.TBS.Extensions[2].Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 28}), "unexpected OID in extension")
137 var number int
138 _, err = asn1.Unmarshal(crl.TBS.Extensions[1].Value, &number)
139 test.AssertNotError(t, err, "failed to parse CRL number extension")
140 test.AssertEquals(t, number, 1)
141 }
142
143 type asn1CRL struct {
144 TBS struct {
145 Version int `asn1:"optional"`
146 SigAlg pkix.AlgorithmIdentifier
147 Issuer struct {
148 Raw asn1.RawContent
149 }
150 ThisUpdate time.Time
151 NextUpdate time.Time `asn1:"optional"`
152 RevokedCertificates []struct {
153 Serial *big.Int
154 RevokedAt time.Time
155 Extensions []pkix.Extension `asn1:"optional"`
156 } `asn1:"optional"`
157 Extensions []pkix.Extension `asn1:"optional,explicit,tag:0"`
158 }
159 SigAlg pkix.AlgorithmIdentifier
160 Sig asn1.BitString
161 }
162
View as plain text