1 package ca
2
3 import (
4 "context"
5 "crypto/x509"
6 "encoding/hex"
7 "testing"
8 "time"
9
10 capb "github.com/letsencrypt/boulder/ca/proto"
11 "github.com/letsencrypt/boulder/core"
12 blog "github.com/letsencrypt/boulder/log"
13 "github.com/letsencrypt/boulder/metrics"
14 "github.com/letsencrypt/boulder/test"
15 "golang.org/x/crypto/ocsp"
16 )
17
18 func TestImplementationOCSP(t *testing.T) {
19 test.AssertImplementsGRPCServer(t, &ocspImpl{}, capb.UnimplementedOCSPGeneratorServer{})
20 }
21
22 func serial(t *testing.T) []byte {
23 serial, err := hex.DecodeString("aabbccddeeffaabbccddeeff000102030405")
24 if err != nil {
25 t.Fatal(err)
26 }
27 return serial
28
29 }
30
31 func TestOCSP(t *testing.T) {
32 testCtx := setup(t)
33 ca, err := NewCertificateAuthorityImpl(
34 &mockSA{},
35 testCtx.pa,
36 testCtx.boulderIssuers,
37 nil,
38 testCtx.certExpiry,
39 testCtx.certBackdate,
40 testCtx.serialPrefix,
41 testCtx.maxNames,
42 testCtx.keyPolicy,
43 testCtx.logger,
44 testCtx.stats,
45 testCtx.signatureCount,
46 testCtx.signErrorCount,
47 testCtx.fc)
48 test.AssertNotError(t, err, "Failed to create CA")
49 ocspi := testCtx.ocsp
50
51
52 rsaIssuerID := ca.issuers.byAlg[x509.RSA].ID()
53 rsaCertPB, err := ca.IssuePrecertificate(ctx, &capb.IssueCertificateRequest{Csr: CNandSANCSR, RegistrationID: arbitraryRegID})
54 test.AssertNotError(t, err, "Failed to issue certificate")
55 rsaCert, err := x509.ParseCertificate(rsaCertPB.DER)
56 test.AssertNotError(t, err, "Failed to parse rsaCert")
57 rsaOCSPPB, err := ocspi.GenerateOCSP(ctx, &capb.GenerateOCSPRequest{
58 Serial: core.SerialToString(rsaCert.SerialNumber),
59 IssuerID: int64(rsaIssuerID),
60 Status: string(core.OCSPStatusGood),
61 })
62 test.AssertNotError(t, err, "Failed to generate OCSP")
63 rsaOCSP, err := ocsp.ParseResponse(rsaOCSPPB.Response, caCert.Certificate)
64 test.AssertNotError(t, err, "Failed to parse / validate OCSP for rsaCert")
65 test.AssertEquals(t, rsaOCSP.Status, 0)
66 test.AssertEquals(t, rsaOCSP.RevocationReason, 0)
67 test.AssertEquals(t, rsaOCSP.SerialNumber.Cmp(rsaCert.SerialNumber), 0)
68
69
70 ecdsaIssuerID := ca.issuers.byAlg[x509.ECDSA].ID()
71 ecdsaCertPB, err := ca.IssuePrecertificate(ctx, &capb.IssueCertificateRequest{Csr: ECDSACSR, RegistrationID: arbitraryRegID})
72 test.AssertNotError(t, err, "Failed to issue certificate")
73 ecdsaCert, err := x509.ParseCertificate(ecdsaCertPB.DER)
74 test.AssertNotError(t, err, "Failed to parse ecdsaCert")
75 ecdsaOCSPPB, err := ocspi.GenerateOCSP(ctx, &capb.GenerateOCSPRequest{
76 Serial: core.SerialToString(ecdsaCert.SerialNumber),
77 IssuerID: int64(ecdsaIssuerID),
78 Status: string(core.OCSPStatusGood),
79 })
80 test.AssertNotError(t, err, "Failed to generate OCSP")
81 ecdsaOCSP, err := ocsp.ParseResponse(ecdsaOCSPPB.Response, caCert2.Certificate)
82 test.AssertNotError(t, err, "Failed to parse / validate OCSP for ecdsaCert")
83 test.AssertEquals(t, ecdsaOCSP.Status, 0)
84 test.AssertEquals(t, ecdsaOCSP.RevocationReason, 0)
85 test.AssertEquals(t, ecdsaOCSP.SerialNumber.Cmp(ecdsaCert.SerialNumber), 0)
86
87
88 _, err = ocspi.GenerateOCSP(context.Background(), &capb.GenerateOCSPRequest{
89 Serial: core.SerialToString(rsaCert.SerialNumber),
90 IssuerID: int64(666),
91 Status: string(core.OCSPStatusGood),
92 })
93 test.AssertError(t, err, "GenerateOCSP didn't fail with invalid IssuerID")
94
95
96 _, err = ocspi.GenerateOCSP(context.Background(), &capb.GenerateOCSPRequest{
97 Serial: "BADDECAF",
98 IssuerID: int64(rsaIssuerID),
99 Status: string(core.OCSPStatusGood),
100 })
101 test.AssertError(t, err, "GenerateOCSP didn't fail with invalid Serial")
102
103
104 _, err = ocspi.GenerateOCSP(context.Background(), &capb.GenerateOCSPRequest{
105 Serial: "03DEADBEEFBADDECAFFADEFACECAFE30",
106 IssuerID: int64(rsaIssuerID),
107 Status: string(core.OCSPStatusGood),
108 })
109 test.AssertNotError(t, err, "GenerateOCSP failed with fake-but-valid Serial")
110 }
111
112
113
114 func TestOcspLogFlushOnExit(t *testing.T) {
115 t.Parallel()
116 log := blog.NewMock()
117 stats := metrics.NoopRegisterer
118 queue := newOCSPLogQueue(4000, 10000*time.Millisecond, stats, log)
119 go queue.loop()
120 queue.enqueue(serial(t), time.Now(), ocsp.Good, ocsp.Unspecified)
121 queue.stop()
122
123 expected := []string{
124 "INFO: [AUDIT] OCSP signed: aabbccddeeffaabbccddeeff000102030405:_,",
125 }
126 test.AssertDeepEquals(t, log.GetAll(), expected)
127 }
128
129
130 func TestOcspFlushOnLength(t *testing.T) {
131 t.Parallel()
132 log := blog.NewMock()
133 stats := metrics.NoopRegisterer
134 queue := newOCSPLogQueue(100, 100*time.Millisecond, stats, log)
135 go queue.loop()
136 for i := 0; i < 5; i++ {
137 queue.enqueue(serial(t), time.Now(), ocsp.Good, ocsp.Unspecified)
138 }
139 queue.stop()
140
141 expected := []string{
142 "INFO: [AUDIT] OCSP signed: aabbccddeeffaabbccddeeff000102030405:_,aabbccddeeffaabbccddeeff000102030405:_,",
143 "INFO: [AUDIT] OCSP signed: aabbccddeeffaabbccddeeff000102030405:_,aabbccddeeffaabbccddeeff000102030405:_,",
144 "INFO: [AUDIT] OCSP signed: aabbccddeeffaabbccddeeff000102030405:_,",
145 }
146 test.AssertDeepEquals(t, log.GetAll(), expected)
147 }
148
149
150 func TestOcspFlushOnTimeout(t *testing.T) {
151 t.Parallel()
152 log := blog.NewWaitingMock()
153 stats := metrics.NoopRegisterer
154 queue := newOCSPLogQueue(90000, 10*time.Millisecond, stats, log)
155
156 go queue.loop()
157 queue.enqueue(serial(t), time.Now(), ocsp.Good, ocsp.Unspecified)
158
159 expected := "INFO: [AUDIT] OCSP signed: aabbccddeeffaabbccddeeff000102030405:_,"
160 logLines, err := log.WaitForMatch("OCSP signed", 50*time.Millisecond)
161 test.AssertNotError(t, err, "error in mock log")
162 test.AssertDeepEquals(t, logLines, expected)
163 queue.stop()
164 }
165
166
167 func TestOcspNoEmptyLines(t *testing.T) {
168 t.Parallel()
169 log := blog.NewMock()
170 stats := metrics.NoopRegisterer
171 queue := newOCSPLogQueue(90000, 10*time.Millisecond, stats, log)
172
173 go queue.loop()
174 time.Sleep(50 * time.Millisecond)
175 queue.stop()
176
177 test.AssertDeepEquals(t, log.GetAll(), []string{})
178 }
179
180
181 func TestOcspLogWhenMaxLogLenIsShort(t *testing.T) {
182 t.Parallel()
183 log := blog.NewMock()
184 stats := metrics.NoopRegisterer
185 queue := newOCSPLogQueue(3, 10000*time.Millisecond, stats, log)
186 go queue.loop()
187 queue.enqueue(serial(t), time.Now(), ocsp.Good, ocsp.Unspecified)
188 queue.stop()
189
190 expected := []string{
191 "INFO: [AUDIT] OCSP signed: aabbccddeeffaabbccddeeff000102030405:_,",
192 }
193 test.AssertDeepEquals(t, log.GetAll(), expected)
194 }
195
196
197 func TestOcspLogPanicsOnEnqueueAfterStop(t *testing.T) {
198 t.Parallel()
199
200 log := blog.NewMock()
201 stats := metrics.NoopRegisterer
202 queue := newOCSPLogQueue(4000, 10000*time.Millisecond, stats, log)
203 go queue.loop()
204 queue.stop()
205
206 defer func() {
207 if r := recover(); r == nil {
208 t.Errorf("The code did not panic")
209 }
210 }()
211
212 queue.enqueue(serial(t), time.Now(), ocsp.Good, ocsp.Unspecified)
213 }
214
215
216 func TestOcspRevokeReasonIsSet(t *testing.T) {
217 t.Parallel()
218 log := blog.NewMock()
219 stats := metrics.NoopRegisterer
220 queue := newOCSPLogQueue(100, 100*time.Millisecond, stats, log)
221 go queue.loop()
222
223 queue.enqueue(serial(t), time.Now(), ocsp.Revoked, ocsp.KeyCompromise)
224 queue.enqueue(serial(t), time.Now(), ocsp.Revoked, ocsp.CACompromise)
225 queue.stop()
226
227 expected := []string{
228 "INFO: [AUDIT] OCSP signed: aabbccddeeffaabbccddeeff000102030405:1,aabbccddeeffaabbccddeeff000102030405:2,",
229 }
230 test.AssertDeepEquals(t, log.GetAll(), expected)
231 }
232
View as plain text