1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ctfe
16
17 import (
18 "encoding/base64"
19 "encoding/pem"
20 "strings"
21 "testing"
22 "time"
23
24 "github.com/google/certificate-transparency-go/asn1"
25 "github.com/google/certificate-transparency-go/trillian/ctfe/testonly"
26 "github.com/google/certificate-transparency-go/x509"
27 "github.com/google/certificate-transparency-go/x509/pkix"
28 "github.com/google/certificate-transparency-go/x509util"
29 )
30
31 func wipeExtensions(cert *x509.Certificate) *x509.Certificate {
32 cert.Extensions = cert.Extensions[:0]
33 return cert
34 }
35
36 func makePoisonNonCritical(cert *x509.Certificate) *x509.Certificate {
37
38 cert.Extensions = []pkix.Extension{{Id: x509.OIDExtensionCTPoison, Critical: false, Value: asn1.NullBytes}}
39 return cert
40 }
41
42 func makePoisonNonNull(cert *x509.Certificate) *x509.Certificate {
43
44 cert.Extensions = []pkix.Extension{{Id: x509.OIDExtensionCTPoison, Critical: false, Value: []byte{0x42, 0x42, 0x42}}}
45 return cert
46 }
47
48 func TestIsPrecertificate(t *testing.T) {
49 var tests = []struct {
50 desc string
51 cert *x509.Certificate
52 wantPrecert bool
53 wantErr bool
54 }{
55 {
56 desc: "valid-precert",
57 cert: pemToCert(t, testonly.PrecertPEMValid),
58 wantPrecert: true,
59 },
60 {
61 desc: "valid-cert",
62 cert: pemToCert(t, testonly.CACertPEM),
63 wantPrecert: false,
64 },
65 {
66 desc: "remove-exts-from-precert",
67 cert: wipeExtensions(pemToCert(t, testonly.PrecertPEMValid)),
68 wantPrecert: false,
69 },
70 {
71 desc: "poison-non-critical",
72 cert: makePoisonNonCritical(pemToCert(t, testonly.PrecertPEMValid)),
73 wantPrecert: false,
74 wantErr: true,
75 },
76 {
77 desc: "poison-non-null",
78 cert: makePoisonNonNull(pemToCert(t, testonly.PrecertPEMValid)),
79 wantPrecert: false,
80 wantErr: true,
81 },
82 }
83
84 for _, test := range tests {
85 gotPrecert, err := IsPrecertificate(test.cert)
86 t.Run(test.desc, func(t *testing.T) {
87 if err != nil {
88 if !test.wantErr {
89 t.Errorf("IsPrecertificate()=%v,%v; want %v,nil", gotPrecert, err, test.wantPrecert)
90 }
91 return
92 }
93 if test.wantErr {
94 t.Errorf("IsPrecertificate()=%v,%v; want _,%v", gotPrecert, err, test.wantErr)
95 }
96 if gotPrecert != test.wantPrecert {
97 t.Errorf("IsPrecertificate()=%v,%v; want %v,nil", gotPrecert, err, test.wantPrecert)
98 }
99 })
100 }
101 }
102
103 func TestValidateChain(t *testing.T) {
104 fakeCARoots := x509util.NewPEMCertPool()
105 if !fakeCARoots.AppendCertsFromPEM([]byte(testonly.FakeCACertPEM)) {
106 t.Fatal("failed to load fake root")
107 }
108 if !fakeCARoots.AppendCertsFromPEM([]byte(testonly.FakeRootCACertPEM)) {
109 t.Fatal("failed to load fake root")
110 }
111 if !fakeCARoots.AppendCertsFromPEM([]byte(testonly.CACertPEM)) {
112 t.Fatal("failed to load CA root")
113 }
114 if !fakeCARoots.AppendCertsFromPEM([]byte(testonly.RealPrecertIntermediatePEM)) {
115 t.Fatal("failed to load real intermediate")
116 }
117 validateOpts := CertValidationOpts{
118 trustedRoots: fakeCARoots,
119 }
120
121 var tests = []struct {
122 desc string
123 chain [][]byte
124 wantErr bool
125 wantPathLen int
126 modifyOpts func(v *CertValidationOpts)
127 }{
128 {
129 desc: "missing-intermediate-cert",
130 chain: pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM}),
131 wantErr: true,
132 },
133 {
134 desc: "wrong-cert-order",
135 chain: pemsToDERChain(t, []string{testonly.FakeIntermediateCertPEM, testonly.LeafSignedByFakeIntermediateCertPEM}),
136 wantErr: true,
137 },
138 {
139 desc: "unrelated-cert-in-chain",
140 chain: pemsToDERChain(t, []string{testonly.FakeIntermediateCertPEM, testonly.TestCertPEM}),
141 wantErr: true,
142 },
143 {
144 desc: "unrelated-cert-after-chain",
145 chain: pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM, testonly.TestCertPEM}),
146 wantErr: true,
147 },
148 {
149 desc: "valid-chain",
150 chain: pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM}),
151 wantPathLen: 3,
152 },
153 {
154 desc: "valid-chain-with-policyconstraints",
155 chain: pemsToDERChain(t, []string{testonly.LeafCertPEM, testonly.FakeIntermediateWithPolicyConstraintsCertPEM}),
156 wantPathLen: 3,
157 },
158 {
159 desc: "valid-chain-with-policyconstraints-inc-root",
160 chain: pemsToDERChain(t, []string{testonly.LeafCertPEM, testonly.FakeIntermediateWithPolicyConstraintsCertPEM, testonly.FakeRootCACertPEM}),
161 wantPathLen: 3,
162 },
163 {
164 desc: "valid-chain-with-nameconstraints",
165 chain: pemsToDERChain(t, []string{testonly.LeafCertPEM, testonly.FakeIntermediateWithNameConstraintsCertPEM}),
166 wantPathLen: 3,
167 },
168 {
169 desc: "chain-with-invalid-nameconstraints",
170 chain: pemsToDERChain(t, []string{testonly.LeafCertPEM, testonly.FakeIntermediateWithInvalidNameConstraintsCertPEM}),
171 wantPathLen: 3,
172 },
173 {
174 desc: "chain-of-len-4",
175 chain: pemFileToDERChain(t, "../testdata/subleaf.chain"),
176 wantPathLen: 4,
177 },
178 {
179 desc: "misordered-chain-of-len-4",
180 chain: pemFileToDERChain(t, "../testdata/subleaf.misordered.chain"),
181 wantErr: true,
182 },
183 {
184 desc: "reject-non-existent-ext-id",
185 chain: pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM}),
186 modifyOpts: func(v *CertValidationOpts) {
187
188 v.rejectExtIds = []asn1.ObjectIdentifier{[]int{99, 99, 99, 99}}
189 },
190 wantPathLen: 3,
191 },
192 {
193 desc: "reject-non-existent-ext-id-precert",
194 chain: pemsToDERChain(t, []string{testonly.PrecertPEMValid}),
195 modifyOpts: func(v *CertValidationOpts) {
196
197 v.rejectExtIds = []asn1.ObjectIdentifier{[]int{99, 99, 99, 99}}
198 },
199 wantPathLen: 2,
200 },
201 {
202 desc: "reject-ext-id",
203 chain: pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM}),
204 wantErr: true,
205 modifyOpts: func(v *CertValidationOpts) {
206
207 v.rejectExtIds = []asn1.ObjectIdentifier{[]int{2, 5, 29, 14}}
208 },
209 },
210 {
211 desc: "reject-ext-id-precert",
212 chain: pemsToDERChain(t, []string{testonly.PrecertPEMValid}),
213 wantErr: true,
214 modifyOpts: func(v *CertValidationOpts) {
215
216 v.rejectExtIds = []asn1.ObjectIdentifier{[]int{2, 5, 29, 14}}
217 },
218 },
219 {
220 desc: "reject-eku-not-present-in-cert",
221 chain: pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM}),
222 wantErr: true,
223 modifyOpts: func(v *CertValidationOpts) {
224
225 v.extKeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection}
226 },
227 },
228 {
229 desc: "allow-eku-present-in-cert",
230 chain: pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM}),
231 wantPathLen: 3,
232 modifyOpts: func(v *CertValidationOpts) {
233 v.extKeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
234 },
235 },
236 {
237 desc: "reject-eku-not-present-in-precert",
238 chain: pemsToDERChain(t, []string{testonly.RealPrecertWithEKUPEM}),
239 wantErr: true,
240 modifyOpts: func(v *CertValidationOpts) {
241
242 v.extKeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection}
243 },
244 },
245 {
246 desc: "allow-eku-present-in-precert",
247 chain: pemsToDERChain(t, []string{testonly.RealPrecertWithEKUPEM}),
248 wantPathLen: 2,
249 modifyOpts: func(v *CertValidationOpts) {
250 v.extKeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
251 },
252 },
253 }
254 for _, test := range tests {
255 t.Run(test.desc, func(t *testing.T) {
256 validateOpts := validateOpts
257 if test.modifyOpts != nil {
258 test.modifyOpts(&validateOpts)
259 }
260 gotPath, err := ValidateChain(test.chain, validateOpts)
261 if err != nil {
262 if !test.wantErr {
263 t.Errorf("ValidateChain()=%v,%v; want _,nil", gotPath, err)
264 }
265 return
266 }
267 if test.wantErr {
268 t.Errorf("ValidateChain()=%v,%v; want _,non-nil", gotPath, err)
269 return
270 }
271 if len(gotPath) != test.wantPathLen {
272 t.Errorf("|ValidateChain()|=%d; want %d", len(gotPath), test.wantPathLen)
273 for _, c := range gotPath {
274 t.Logf("Subject: %s Issuer: %s", x509util.NameToString(c.Subject), x509util.NameToString(c.Issuer))
275 }
276 }
277 })
278 }
279 }
280
281 func TestCA(t *testing.T) {
282 fakeCARoots := x509util.NewPEMCertPool()
283 if !fakeCARoots.AppendCertsFromPEM([]byte(testonly.FakeCACertPEM)) {
284 t.Fatal("failed to load fake root")
285 }
286 validateOpts := CertValidationOpts{
287 trustedRoots: fakeCARoots,
288 }
289 chain := pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM})
290 leaf, err := x509.ParseCertificate(chain[0])
291 if x509.IsFatal(err) {
292 t.Fatalf("Failed to parse golden certificate DER: %v", err)
293 }
294 t.Logf("Cert expiry date: %v", leaf.NotAfter)
295
296 var tests = []struct {
297 desc string
298 chain [][]byte
299 caOnly bool
300 wantErr bool
301 }{
302 {
303 desc: "end-entity, allow non-CA",
304 chain: chain,
305 },
306 {
307 desc: "end-entity, disallow non-CA",
308 chain: chain,
309 caOnly: true,
310 wantErr: true,
311 },
312 {
313 desc: "intermediate, allow non-CA",
314 chain: chain[1:],
315 },
316 {
317 desc: "intermediate, disallow non-CA",
318 chain: chain[1:],
319 caOnly: true,
320 },
321 }
322 for _, test := range tests {
323 t.Run(test.desc, func(t *testing.T) {
324 validateOpts.acceptOnlyCA = test.caOnly
325 gotPath, err := ValidateChain(test.chain, validateOpts)
326 if err != nil {
327 if !test.wantErr {
328 t.Errorf("ValidateChain()=%v,%v; want _,nil", gotPath, err)
329 }
330 return
331 }
332 if test.wantErr {
333 t.Errorf("ValidateChain()=%v,%v; want _,non-nil", gotPath, err)
334 }
335 })
336 }
337 }
338
339 func TestNotAfterRange(t *testing.T) {
340 fakeCARoots := x509util.NewPEMCertPool()
341 if !fakeCARoots.AppendCertsFromPEM([]byte(testonly.FakeCACertPEM)) {
342 t.Fatal("failed to load fake root")
343 }
344 validateOpts := CertValidationOpts{
345 trustedRoots: fakeCARoots,
346 rejectExpired: false,
347 }
348
349 chain := pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM})
350
351 var tests = []struct {
352 desc string
353 chain [][]byte
354 notAfterStart time.Time
355 notAfterLimit time.Time
356 wantErr bool
357 }{
358 {
359 desc: "valid-chain, no range",
360 chain: chain,
361 },
362 {
363 desc: "valid-chain, valid range",
364 chain: chain,
365 notAfterStart: time.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC),
366 notAfterLimit: time.Date(2020, 7, 1, 0, 0, 0, 0, time.UTC),
367 },
368 {
369 desc: "before valid range",
370 chain: chain,
371 notAfterStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
372 wantErr: true,
373 },
374 {
375 desc: "after valid range",
376 chain: chain,
377 notAfterLimit: time.Date(1999, 1, 1, 0, 0, 0, 0, time.UTC),
378 wantErr: true,
379 },
380 }
381 for _, test := range tests {
382 t.Run(test.desc, func(t *testing.T) {
383 if !test.notAfterStart.IsZero() {
384 validateOpts.notAfterStart = &test.notAfterStart
385 }
386 if !test.notAfterLimit.IsZero() {
387 validateOpts.notAfterLimit = &test.notAfterLimit
388 }
389 gotPath, err := ValidateChain(test.chain, validateOpts)
390 if err != nil {
391 if !test.wantErr {
392 t.Errorf("ValidateChain()=%v,%v; want _,nil", gotPath, err)
393 }
394 return
395 }
396 if test.wantErr {
397 t.Errorf("ValidateChain()=%v,%v; want _,non-nil", gotPath, err)
398 }
399 })
400 }
401 }
402
403 func TestRejectExpiredUnexpired(t *testing.T) {
404 fakeCARoots := x509util.NewPEMCertPool()
405
406 if !fakeCARoots.AppendCertsFromPEM([]byte(testonly.FakeCACertPEM)) {
407 t.Fatal("failed to load fake root")
408 }
409
410 chain := pemsToDERChain(t, []string{testonly.LeafSignedByFakeIntermediateCertPEM, testonly.FakeIntermediateCertPEM})
411 validateOpts := CertValidationOpts{
412 trustedRoots: fakeCARoots,
413 extKeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
414 }
415 beforeValidPeriod := time.Date(1999, 1, 1, 0, 0, 0, 0, time.UTC)
416 currentValidPeriod := time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC)
417 afterValidPeriod := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
418
419 for _, tc := range []struct {
420 desc string
421 rejectExpired bool
422 rejectUnexpired bool
423 now time.Time
424 wantErr string
425 }{
426
427 {
428 desc: "no-reject-current",
429 now: currentValidPeriod,
430 },
431 {
432 desc: "no-reject-after",
433 now: afterValidPeriod,
434 },
435 {
436 desc: "no-reject-before",
437 now: beforeValidPeriod,
438 },
439
440 {
441 desc: "reject-expired-current",
442 rejectExpired: true,
443 now: currentValidPeriod,
444 },
445 {
446 desc: "reject-expired-after",
447 rejectExpired: true,
448 now: afterValidPeriod,
449 wantErr: "rejecting expired certificate",
450 },
451 {
452 desc: "reject-expired-before",
453 rejectExpired: true,
454 now: beforeValidPeriod,
455 },
456
457 {
458 desc: "reject-non-expired-after",
459 rejectUnexpired: true,
460 now: afterValidPeriod,
461 },
462 {
463 desc: "reject-non-expired-before",
464 rejectUnexpired: true,
465 now: beforeValidPeriod,
466 wantErr: "rejecting unexpired certificate",
467 },
468 {
469 desc: "reject-non-expired-current",
470 rejectUnexpired: true,
471 now: currentValidPeriod,
472 wantErr: "rejecting unexpired certificate",
473 },
474
475 {
476 desc: "reject-all-after",
477 rejectExpired: true,
478 rejectUnexpired: true,
479 now: afterValidPeriod,
480 wantErr: "rejecting expired certificate",
481 },
482 {
483 desc: "reject-all-before",
484 rejectExpired: true,
485 rejectUnexpired: true,
486 now: beforeValidPeriod,
487 wantErr: "rejecting unexpired certificate",
488 },
489 {
490 desc: "reject-all-current",
491 rejectExpired: true,
492 rejectUnexpired: true,
493 now: currentValidPeriod,
494 wantErr: "rejecting unexpired certificate",
495 },
496 } {
497 t.Run(tc.desc, func(t *testing.T) {
498 validateOpts.currentTime = tc.now
499 validateOpts.rejectExpired = tc.rejectExpired
500 validateOpts.rejectUnexpired = tc.rejectUnexpired
501 _, err := ValidateChain(chain, validateOpts)
502 if err != nil {
503 if len(tc.wantErr) == 0 {
504 t.Errorf("ValidateChain()=_,%v; want _,nil", err)
505 } else if !strings.Contains(err.Error(), tc.wantErr) {
506 t.Errorf("ValidateChain()=_,%v; want err containing %q", err, tc.wantErr)
507 }
508 } else if len(tc.wantErr) != 0 {
509 t.Errorf("ValidateChain()=_,nil; want err containing %q", tc.wantErr)
510 }
511 })
512 }
513 }
514
515
516
517 func pemsToDERChain(t *testing.T, pemCerts []string) [][]byte {
518 t.Helper()
519 chain := make([][]byte, 0, len(pemCerts))
520 for _, pemCert := range pemCerts {
521 cert := pemToCert(t, pemCert)
522 chain = append(chain, cert.Raw)
523 }
524 return chain
525 }
526
527 func pemToCert(t *testing.T, pemData string) *x509.Certificate {
528 t.Helper()
529 bytes, rest := pem.Decode([]byte(pemData))
530 if len(rest) > 0 {
531 t.Fatalf("Extra data after PEM: %v", rest)
532 return nil
533 }
534
535 cert, err := x509.ParseCertificate(bytes.Bytes)
536 if x509.IsFatal(err) {
537 t.Fatal(err)
538 }
539
540 return cert
541 }
542
543 func pemFileToDERChain(t *testing.T, filename string) [][]byte {
544 t.Helper()
545 rawChain, err := x509util.ReadPossiblePEMFile(filename, "CERTIFICATE")
546 if err != nil {
547 t.Fatalf("failed to load testdata: %v", err)
548 }
549 return rawChain
550 }
551
552
553 func TestCMPreIssuedCert(t *testing.T) {
554 var b64Chain = []string{
555 "MIID+jCCAuKgAwIBAgIHBWW7shJizTANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJHQjEPMA0GA1UEBwwGTG9uZG9uMTowOAYDVQQKDDFHb29nbGUgQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IChQcmVjZXJ0IFNpZ25pbmcpMRkwFwYDVQQFExAxNTE5MjMxNzA0MTczNDg3MB4XDTE4MDIyMTE2NDgyNFoXDTE4MTIwMTIwMzMyN1owYzELMAkGA1UEBhMCR0IxDzANBgNVBAcMBkxvbmRvbjEoMCYGA1UECgwfR29vZ2xlIENlcnRpZmljYXRlIFRyYW5zcGFyZW5jeTEZMBcGA1UEBRMQMTUxOTIzMTcwNDM5MjM5NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKnKP9TP6hkEuD+d1rPeA8mxo5xFYffhCcEitP8PtTl7G2RqFrndPeAkzgvOxPB3Jrhx7LtMtg0IvS8y7Sy1qDqDou1/OrJgwCeWMc1/KSneuGP8GTX0Rqy4z8+LsiBN/tMDbt94RuiyCeltIAaHGmsNeYXV34ayD3vSIAQbtLUOD39KqrJWO0tQ//nshBuFlebiUrDP7rirPusYYW0stJKiCKeORhHvL3/I8mCYGNO0XIWMpASH2S9LGMwg+AQM13whC1KL65EGuVs4Ta0rO+Tl8Yi0is0RwdUmgdSGtl0evPTzyUXbA1n1BpkLcSQ5E3RxY3O6Ge9Whvtmg9vAJiMCAwEAAaOBoDCBnTATBgNVHSUEDDAKBggrBgEFBQcDATAjBgNVHREEHDAaghhmbG93ZXJzLXRvLXRoZS13b3JsZC5jb20wDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRKCM/Ajh0Fu6FFjJ9F4gVWK2oj/jAdBgNVHQ4EFgQUVjYl6wDey3DxvmTG2HL4vdiUt+MwEwYKKwYBBAHWeQIEAwEB/wQCBQAwDQYJKoZIhvcNAQELBQADggEBAAvyEFDIAWr0URsZzrJLZEL8p6FMTzVxY/MOvGP8QMXA6xNVElxYnDPF32JERAl+poR7syByhVFcEjrw7f2FTlMc04+hT/hsYzi8cMAmfX9KA36xUBVjyqvqwofxTwoWYdf+eGZW0EG8Yp1pM7iUy9bdlh3sgdOpmT9Z5XGCRwvdW1+mctv0JMKDdWzxBqYyNMnNjvjHBmkiuHeDDGFsV2zq+wV64RwJa2eVrnkMDMV1mscL6KzNRLPP2ZpNz/8H7SPock+fk4cZrdqj+0IzFt+6ixSoKyltyD+nkbWjRGY4iyboo/nPgTQ1IQCS2OPVHWw3NijFD8hqgAnYvz0Dn+k=",
556 "MIIE4jCCAsqgAwIBAgIHBWW7sg8LrzANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMRcwFQYDVQQKDA5Hb29nbGUgVUsgTHRkLjEhMB8GA1UECwwYQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5MSMwIQYDVQQDDBpNZXJnZSBEZWxheSBJbnRlcm1lZGlhdGUgMTAeFw0xODAyMjExNjQ4MjRaFw0xODEyMDEyMDM0MjdaMHUxCzAJBgNVBAYTAkdCMQ8wDQYDVQQHDAZMb25kb24xOjA4BgNVBAoMMUdvb2dsZSBDZXJ0aWZpY2F0ZSBUcmFuc3BhcmVuY3kgKFByZWNlcnQgU2lnbmluZykxGTAXBgNVBAUTEDE1MTkyMzE3MDQxNzM0ODcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCKWlc3A43kJ9IzmkCPXcsGwTxlIvtl9sNYBWlx9qqHa1i6tU6rZuH9uXAb3wsn39fqY22HzF/yrx9pd05doFfRq6dvvm4eHNFfFm4cJur1kmPe8vLKpSI/P2DPx4/mRzrHnPAI8Jo9QgKcj91AyYeB689ZFzH30ay32beo6PxQvtoJkzl+dzf9Hs1ezavS7nDCuqDnu1V1Og7J5xTHZeNyTKgD5Kx28ukmIp2wGOvg3omuInABg/ew0VxnG/txKV+69zfV9dhclU3m16L81e3RkJ8Kg4RLb0mh9X3EMn90SpJ9yw0j8FF0Esk6wxuYeUGLShUji8BPnnbactY9B6ORAgMBAAGjbTBrMBgGA1UdJQEB/wQOMAwGCisGAQQB1nkCBAQwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTpPAThgC/ChBMtJnCe8v0az6r+xjAdBgNVHQ4EFgQUSgjPwI4dBbuhRYyfReIFVitqI/4wDQYJKoZIhvcNAQEFBQADggIBAEep2uWAFsdq1nLtLWLGh7DfVPc/K+1lcqNx64ucjpVZbDnMnYKFagf2Z9rHEWqR7kwuLac5xW8woSlLa/NHmJmdg18HGUhlS+x8iMPv7dK6hfNsRFdjLZkZOFneuf9j1b0dV+rXoRvyY+Oq+lomC98bEr+g9zq+M7wJ4wS/KeaNHpPw1pBeTtCdw+1c4ZgRTOEa2OUUpkpueJ+9psD/hbp6HLF+WYijWQ0/iYSxJ4TbjTC+omKRsGhvxSLbP8cSMt3X1pJgrFK1BvH4lqqEXGDNEiVNoPCHraEa8JtMZIo47/Af13lDfp6sBdZ0lvLAVDduWgg/2RkWCbHefAe81h+cYdDS775TF2TCMTwsR6GsM9sVCbfPvHXI/pUzamRn0i0CrhyccBBdPrUhj+cXuc9kqSkLegun9D8EBDMM9va5wb1HM0ruSno+YuLtfhCdBRHr/RG2BKJi7uUDjJ8goHov/EUJmHjAIARKz74IPWRkxMrnOvGhnNa2Hz+da3hpusz0Mj4rsqv1EKTC2wbCs6Rk2MRPSxdRbywdWLSmGn249SMfXK4An+dqoRk1fwKqdXc4swoUvxnGUi5ajBaRtc6631zBTmvmSFQnvGmS42aF7q2PjfvWPIuO+d//m8KgN6o2YyjrdPDDslI2RZUE5ngOR+JynvhjYrrB7Bat1EY7",
557 "MIIFyDCCA7CgAwIBAgICEAEwDQYJKoZIhvcNAQEFBQAwfTELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEXMBUGA1UECgwOR29vZ2xlIFVLIEx0ZC4xITAfBgNVBAsMGENlcnRpZmljYXRlIFRyYW5zcGFyZW5jeTEhMB8GA1UEAwwYTWVyZ2UgRGVsYXkgTW9uaXRvciBSb290MB4XDTE0MDcxNzEyMjYzMFoXDTE5MDcxNjEyMjYzMFowfzELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEXMBUGA1UECgwOR29vZ2xlIFVLIEx0ZC4xITAfBgNVBAsMGENlcnRpZmljYXRlIFRyYW5zcGFyZW5jeTEjMCEGA1UEAwwaTWVyZ2UgRGVsYXkgSW50ZXJtZWRpYXRlIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDB6HT+/5ru8wO7+mNFOIH6r43BwiwJZB2vQwOB8zvBV79sTIqNV7Grx5KFnSDyGRUJxZfEN7FGc96lr0vqFDlt1DbcYgVV15U+Dt4B9/+0Tz/3zeZO0kVjTg3wqvzpw6xetj2N4dlpysiFQZVAOp+dHUw9zu3xNR7dlFdDvFSrdFsgT7Uln+Pt9pXCz5C4hsSP9oC3RP7CaRtDRSQrMcNvMRi3J8XeXCXsGqMKTCRhxRGe9ruQ2Bbm5ExbmVW/ou00Fr9uSlPJL6+sDR8Li/PTW+DU9hygXSj8Zi36WI+6PuA4BHDAEt7Z5Ru/Hnol76dFeExJ0F6vjc7gUnNh7JExJgBelyz0uGORT4NhWC7SRWP/ngPFLoqcoyZMVsGGtOxSt+aVzkKuF+x64CVxMeHb9I8t3iQubpHqMEmIE1oVSCsF/AkTVTKLOeWG6N06SjoUy5fu9o+faXKMKR8hldLM5z1K6QhFsb/F+uBAuU/DWaKVEZgbmWautW06fF5I+OyoFeW+hrPTbmon4OLE3ubjDxKnyTa4yYytWSisojjfw5z58sUkbLu7KAy2+Z60m/0deAiVOQcsFkxwgzcXRt7bxN7By5Q5Bzrz8uYPjFBfBnlhqMU5RU/FNBFY7Mx4Uy8+OcMYfJQ5/A/4julXEx1HjfBj3VCyrT/noHDpBeOGiwIDAQABo1AwTjAdBgNVHQ4EFgQU6TwE4YAvwoQTLSZwnvL9Gs+q/sYwHwYDVR0jBBgwFoAU8197dUnjeEE5aiC2fGtMXMk9WEEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEACFjL1UXy6S4JkGrDnz1VwTYHplFDY4bG6Q8Sh3Og6z9HJdivNft/iAQ2tIHyz0eAGCXeVPE/j1kgvz2RbnUxQd5eWdLeu/w/wiZyHxWhbTt6RhjqBVFjnx0st7n6rRt+Bw8jpugZfD11SbumVT/V20Gc45lHf2oEgbkPUcnTB9gssFz5Z4KKGs5lIHz4a20WeSJF3PJLTBefkRhHNufi/LhjpLXImwrC82g5ChBZS5XIVuJZx3VkMWiYz4emgX0YWF/JdtaB2dUQ7yrTforQ5J9b1JnJ7H/o9DsX3/ubfQ39gwDBxTicnqC+Q3Dcv3i9PvwjCNJQuGa7ygMcDEn/d6elQg2qHxtqRE02ZlOXTC0XnDAJhx7myJFA/Knv3yO9S4jG6665KG9Y88/CHkh08YLR7NYFiRmwOxjbe3lb6csl/FFmqUXvjhEzzWAxKjI09GSd9hZkB8u17Mg46eEYwF3ufIlqmYdlWufjSc2BZuaNNN6jtK6JKp8jhQUycehgtUK+NlBQOXTzu28miDdasoSH2mdR0PLDo1547+MLGdV4COvqLERTmQrYHrliicD5nFCA+CCSvGEjo0DGOmF/O8StwSmNiKJ4ppPvk2iGEdO07e0LbQI+2fbC6og2SDGXUlsbG85wqQw0A7CU1fQSqhFBuZZauDFMUvdy3v/BAIw=",
558 "MIIFzTCCA7WgAwIBAgIJAJ7TzLHRLKJyMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xFzAVBgNVBAoMDkdvb2dsZSBVSyBMdGQuMSEwHwYDVQQLDBhDZXJ0aWZpY2F0ZSBUcmFuc3BhcmVuY3kxITAfBgNVBAMMGE1lcmdlIERlbGF5IE1vbml0b3IgUm9vdDAeFw0xNDA3MTcxMjA1NDNaFw00MTEyMDIxMjA1NDNaMH0xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xFzAVBgNVBAoMDkdvb2dsZSBVSyBMdGQuMSEwHwYDVQQLDBhDZXJ0aWZpY2F0ZSBUcmFuc3BhcmVuY3kxITAfBgNVBAMMGE1lcmdlIERlbGF5IE1vbml0b3IgUm9vdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKoWHPIgXtgaxWVIPNpCaj2y5Yj9t1ixe5PqjWhJXVNKAbpPbNHA/AoSivecBm3FTD9DfgW6J17mHb+cvbKSgYNzgTk5e2GJrnOP7yubYJpt2OCw0OILJD25NsApzcIiCvLA4aXkqkGgBq9FiVfisReNJxVu8MtxfhbVQCXZf0PpkW+yQPuF99V5Ri+grHbHYlaEN1C/HM3+t2yMR4hkd2RNXsMjViit9qCchIi/pQNt5xeQgVGmtYXyc92ftTMrmvduj7+pHq9DEYFt3ifFxE8v0GzCIE1xR/d7prFqKl/KRwAjYUcpU4vuazywcmRxODKuwWFVDrUBkGgCIVIjrMJWStH5i7WTSSTrVtOD/HWYvkXInZlSgcDvsNIG0pptJaEKSP4jUzI3nFymnoNZn6pnfdIII/XISpYSVeyl1IcdVMod8HdKoRew9CzW6f2n6KSKU5I8X5QEM1NUTmRLWmVi5c75/CvS/PzOMyMzXPf+fE2Dwbf4OcR5AZLTupqp8yCTqo7ny+cIBZ1TjcZjzKG4JTMaqDZ1Sg0T3mO/ZbbiBE3N8EHxoMWpw8OP50z1dtRRwj6qUZ2zLvngOb2EihlMO15BpVZC3Cg929c9Hdl65pUd4YrYnQBQB/rn6IvHo8zot8zElgOg22fHbViijUt3qnRggB40N30MXkYGwuJbAgMBAAGjUDBOMB0GA1UdDgQWBBTzX3t1SeN4QTlqILZ8a0xcyT1YQTAfBgNVHSMEGDAWgBTzX3t1SeN4QTlqILZ8a0xcyT1YQTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQB3HP6jRXmpdSDYwkI9aOzQeJH4x/HDi/PNMOqdNje/xdNzUy7HZWVYvvSVBkZ1DG/ghcUtn/wJ5m6/orBn3ncnyzgdKyXbWLnCGX/V61PgIPQpuGo7HzegenYaZqWz7NeXxGaVo3/y1HxUEmvmvSiioQM1cifGtz9/aJsJtIkn5umlImenKKEV1Ly7R3Uz3Cjz/Ffac1o+xU+8NpkLF/67fkazJCCMH6dCWgy6SL3AOB6oKFIVJhw8SD8vptHaDbpJSRBxifMtcop/85XUNDCvO4zkvlB1vPZ9ZmYZQdyL43NA+PkoKy0qrdaQZZMq1Jdp+Lx/yeX255/zkkILp43jFyd44rZ+TfGEQN1WHlp4RMjvoGwOX1uGlfoGkRSgBRj7TBn514VYMbXu687RS4WY2v+kny3PUFv/ZBfYSyjoNZnU4Dce9kstgv+gaKMQRPcyL+4vZU7DV8nBIfNFilCXKMN/VnNBKtDV52qmtOsVghgai+QE09w15x7dg+44gIfWFHxNhvHKys+s4BBN8fSxAMLOsb5NGFHE8x58RAkmIYWHjyPM6zB5AUPw1b2A0sDtQmCqoxJZfZUKrzyLz8gS2aVujRYN13KklHQ3EKfkeKBG2KXVBe5rjMN/7Anf1MtXxsTY6O8qIuHZ5QlXhSYzE41yIlPlG6d7AGnTiBIgeg==",
559 }
560 rawChain := make([][]byte, len(b64Chain))
561 for i, b64Data := range b64Chain {
562 var err error
563 rawChain[i], err = base64.StdEncoding.DecodeString(b64Data)
564 if err != nil {
565 t.Fatalf("failed to base64.Decode(chain[%d]): %v", i, err)
566 }
567 }
568
569 root, err := x509.ParseCertificate(rawChain[len(rawChain)-1])
570 if err != nil {
571 t.Fatalf("failed to parse root cert: %v", err)
572 }
573 cmRoot := x509util.NewPEMCertPool()
574 cmRoot.AddCert(root)
575
576 for _, tc := range []struct {
577 desc string
578 eku []x509.ExtKeyUsage
579 }{
580 {
581 desc: "no EKU specified",
582 }, {
583 desc: "EKU ServerAuth",
584 eku: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
585 },
586 } {
587 t.Run(tc.desc, func(t *testing.T) {
588 opts := CertValidationOpts{
589 trustedRoots: cmRoot,
590 extKeyUsages: tc.eku,
591 }
592 chain, err := ValidateChain(rawChain, opts)
593 if err != nil {
594 t.Fatalf("failed to ValidateChain: %v", err)
595 }
596 for i, c := range chain {
597 t.Logf("chain[%d] = \n%s", i, x509util.CertificateToString(c))
598 }
599 })
600 }
601 }
602
View as plain text