github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/verifier/verifier_test.go (about) 1 /* 2 * ZCrypto Copyright 2017 Regents of the University of Michigan 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * of the License at http://www.apache.org/licenses/LICENSE-2.0 7 * 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 11 * implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package verifier 16 17 import ( 18 "bytes" 19 "crypto/sha256" 20 "encoding/hex" 21 "encoding/pem" 22 "fmt" 23 "io/ioutil" 24 "os" 25 "strings" 26 "testing" 27 "time" 28 29 "github.com/zmap/zcrypto/x509" 30 "github.com/zmap/zcrypto/x509/revocation/google" 31 "github.com/zmap/zcrypto/x509/revocation/mozilla" 32 33 data "github.com/zmap/zcrypto/data/test/certificates" 34 ) 35 36 func loadPEMs(pems []string) (out []*x509.Certificate) { 37 for _, s := range pems { 38 c := loadPEM(s) 39 out = append(out, c) 40 } 41 return 42 } 43 44 func loadPEM(pemBytes string) *x509.Certificate { 45 block, _ := pem.Decode([]byte(pemBytes)) 46 if block == nil { 47 return nil 48 } 49 c, _ := x509.ParseCertificate(block.Bytes) 50 return c 51 } 52 53 func getChainID(chain x509.CertificateChain) string { 54 parts := make([]string, 0, len(chain)) 55 for _, c := range chain { 56 hexHash := hex.EncodeToString(c.FingerprintSHA256) 57 parts = append(parts, hexHash) 58 } 59 return strings.Join(parts, "|") 60 } 61 62 type chainError struct { 63 Extra, Missing []string 64 } 65 66 func (e *chainError) Error() string { 67 out := fmt.Sprintf("missing chains: %v, extra chains: %v", e.Missing, e.Extra) 68 return out 69 } 70 71 type parentError struct { 72 Extra, Missing []string 73 } 74 75 func (e *parentError) Error() string { 76 out := fmt.Sprintf("missing parents: %v, extra parents: %v", e.Missing, e.Extra) 77 return out 78 } 79 80 type crlSetLoader func() (*google.CRLSet, error) 81 type oneCRLLoader func() (*mozilla.OneCRL, error) 82 83 type verifyTest struct { 84 Name string 85 86 Leaf string 87 Presented []string 88 Intermediates []string 89 Roots []string 90 91 CurrentTime int64 92 DNSName string 93 94 ExpectedChains [][]int 95 ExpiredChains [][]int 96 NeverChains [][]int 97 ExpectedParents []int 98 99 ExpectHostnameError bool 100 101 InRevocationSet bool 102 CRLSetFn crlSetLoader 103 OneCRLFn oneCRLLoader 104 105 certificates []*x509.Certificate 106 leaf *x509.Certificate 107 presented, intermediates, roots []*x509.Certificate 108 } 109 110 func (vt *verifyTest) parseSelf() { 111 vt.leaf = loadPEM(vt.Leaf) 112 vt.presented = loadPEMs(vt.Presented) 113 vt.intermediates = loadPEMs(vt.Intermediates) 114 vt.roots = loadPEMs(vt.Roots) 115 116 vt.certificates = append(vt.certificates, vt.leaf) 117 vt.certificates = append(vt.certificates, vt.presented...) 118 vt.certificates = append(vt.certificates, vt.intermediates...) 119 vt.certificates = append(vt.certificates, vt.roots...) 120 } 121 122 func (vt *verifyTest) parsedLeaf() *x509.Certificate { 123 return vt.leaf 124 } 125 126 func (vt *verifyTest) parsedIntermediates() []*x509.Certificate { 127 out := make([]*x509.Certificate, len(vt.intermediates)) 128 copy(out, vt.intermediates) 129 return out 130 } 131 132 func (vt *verifyTest) parsedRoots() []*x509.Certificate { 133 out := make([]*x509.Certificate, len(vt.roots)) 134 copy(out, vt.roots) 135 return out 136 } 137 138 func (vt *verifyTest) unionAllExpected() [][]int { 139 out := make([][]int, 0, 3) 140 current := make([][]int, len(vt.ExpectedChains)) 141 copy(current, vt.ExpectedChains) 142 expired := make([][]int, len(vt.ExpiredChains)) 143 copy(expired, vt.ExpiredChains) 144 never := make([][]int, len(vt.NeverChains)) 145 copy(never, vt.NeverChains) 146 out = append(out, current...) 147 out = append(out, expired...) 148 out = append(out, never...) 149 return out 150 } 151 152 func (vt *verifyTest) compareChains(expected [][]int, actual []x509.CertificateChain) *chainError { 153 type empty struct{} 154 155 expectedChainMap := make(map[string]empty) 156 for _, expectedChainIndices := range expected { 157 expectedCerts := make([]*x509.Certificate, 0, len(expectedChainIndices)) 158 for _, certIdx := range expectedChainIndices { 159 expectedCerts = append(expectedCerts, vt.certificates[certIdx]) 160 } 161 chainID := getChainID(expectedCerts) 162 expectedChainMap[chainID] = empty{} 163 } 164 actualChainMap := make(map[string]empty) 165 for _, chain := range actual { 166 chainID := getChainID(chain) 167 actualChainMap[chainID] = empty{} 168 } 169 170 var missing, extra []string 171 for expectedID := range expectedChainMap { 172 _, ok := actualChainMap[expectedID] 173 if !ok { 174 missing = append(missing, expectedID) 175 } 176 } 177 for actualID := range actualChainMap { 178 _, ok := expectedChainMap[actualID] 179 if !ok { 180 extra = append(extra, actualID) 181 } 182 } 183 184 if len(missing) > 0 || len(extra) > 0 { 185 err := chainError{ 186 Missing: missing, 187 Extra: extra, 188 } 189 return &err 190 } 191 return nil 192 } 193 194 func (vt *verifyTest) compareParents(expected []int, actual []*x509.Certificate) *parentError { 195 type empty struct{} 196 expectedHashMap := make(map[string]empty) 197 for _, certIdx := range expected { 198 c := vt.certificates[certIdx] 199 hexHash := hex.EncodeToString(c.FingerprintSHA256) 200 expectedHashMap[hexHash] = empty{} 201 } 202 actualHashMap := make(map[string]empty) 203 for _, c := range actual { 204 hexHash := hex.EncodeToString(c.FingerprintSHA256) 205 actualHashMap[hexHash] = empty{} 206 } 207 208 var missing, extra []string 209 for expectedHash := range expectedHashMap { 210 _, ok := actualHashMap[expectedHash] 211 if !ok { 212 missing = append(missing, expectedHash) 213 } 214 } 215 for actualHash := range actualHashMap { 216 _, ok := expectedHashMap[actualHash] 217 if !ok { 218 extra = append(extra, actualHash) 219 } 220 } 221 222 if len(missing) > 0 || len(extra) > 0 { 223 err := parentError{ 224 Missing: missing, 225 Extra: extra, 226 } 227 return &err 228 } 229 return nil 230 } 231 232 func (vt *verifyTest) compareParentSPKISubjectToParents(verifyResult *VerificationResult) error { 233 if len(verifyResult.ParentSPKISubjectFingerprint) == 0 && len(verifyResult.Parents) > 0 { 234 return fmt.Errorf("got empty ParentSPKISubjectFingerprint, but have %d parents", len(verifyResult.Parents)) 235 } 236 if len(verifyResult.Parents) == 0 && len(verifyResult.ParentSPKISubjectFingerprint) != 0 { 237 return fmt.Errorf("got ParentSPKISubjectFingeprint %s, but no parents", verifyResult.ParentSPKISubjectFingerprint.Hex()) 238 } 239 expected := verifyResult.ParentSPKISubjectFingerprint 240 for i, parent := range verifyResult.Parents { 241 actualParentFp := parent.SPKISubjectFingerprint 242 if !bytes.Equal(expected, actualParentFp) { 243 return fmt.Errorf("got ParentSPKISubjectFingerprint %s, but parent index %d and hash %s had SPKISubjectFingerprint %s", expected.Hex(), i, parent.FingerprintSHA256.Hex(), actualParentFp.Hex()) 244 } 245 } 246 return nil 247 } 248 249 func (vt *verifyTest) makeVerifier() *Verifier { 250 pki := NewGraph() 251 252 joinedIntermediates := strings.Join(vt.Intermediates, "\n") 253 intermediateReader := strings.NewReader(joinedIntermediates) 254 pki.AppendFromPEM(intermediateReader, false) 255 256 joinedRoots := strings.Join(vt.Roots, "\n") 257 rootReader := strings.NewReader(joinedRoots) 258 pki.AppendFromPEM(rootReader, true) 259 v := NewNSS(pki) 260 return v 261 } 262 263 func (vt *verifyTest) makeVerifyOptions() (opts *VerificationOptions) { 264 opts = new(VerificationOptions) 265 opts.Name = vt.DNSName 266 opts.VerifyTime = time.Unix(vt.CurrentTime, 0) 267 268 if vt.CRLSetFn != nil { 269 crl, err := vt.CRLSetFn() 270 if err != nil { 271 panic(err) 272 } 273 opts.CRLSet = crl 274 } 275 if vt.OneCRLFn != nil { 276 crl, err := vt.OneCRLFn() 277 if err != nil { 278 panic(err) 279 } 280 281 opts.OneCRL = crl 282 } 283 284 return opts 285 } 286 287 func (vt *verifyTest) checkVerifyResult(res *VerificationResult) error { 288 if err := vt.compareChains(vt.ExpectedChains, res.CurrentChains); err != nil { 289 return fmt.Errorf("bad expected chains: %s", err) 290 } 291 if err := vt.compareChains(vt.ExpiredChains, res.ExpiredChains); err != nil { 292 return fmt.Errorf("bad expired chains: %s", err) 293 } 294 if err := vt.compareChains(vt.NeverChains, res.NeverValidChains); err != nil { 295 return fmt.Errorf("bad never chains: %s", err) 296 } 297 if err := vt.compareParents(vt.ExpectedParents, res.Parents); err != nil { 298 return fmt.Errorf("bad parents: %s", err) 299 } 300 if vt.ExpectHostnameError && res.NameError == nil { 301 return fmt.Errorf("expected hostname error, got nil") 302 } 303 if res.NameError != nil && !vt.ExpectHostnameError { 304 return fmt.Errorf("unexpected name error: %s", res.NameError) 305 } 306 if err := vt.compareParentSPKISubjectToParents(res); err != nil { 307 return err 308 } 309 310 if vt.InRevocationSet != res.InRevocationSet { 311 return fmt.Errorf("unexpected InRevocationSet: %t", res.InRevocationSet) 312 } 313 return nil 314 } 315 316 var verifyTests = []verifyTest{ 317 { 318 Name: "PEMLEX3SignedByISRGRootX1-in-CRLSet", 319 Leaf: data.PEMDAdrianIOSignedByLEX3, // idx=0 320 Presented: nil, 321 Intermediates: []string{ 322 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 323 data.PEMLEX3SignedByISRGRootX1, 324 }, 325 Roots: []string{ 326 data.PEMDSTRootCAX3SignedBySelf, // idx=3 327 }, 328 CurrentTime: 1501804800, // 2017-08-04T00:00:00 329 ExpectedChains: [][]int{ 330 {0, 1, 3}, 331 }, 332 ExpectedParents: []int{1}, 333 CRLSetFn: func() (*google.CRLSet, error) { 334 return crlSetIntermediate(data.PEMDAdrianIOSignedByLEX3, []string{ 335 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 336 data.PEMLEX3SignedByISRGRootX1, 337 }) 338 }, 339 InRevocationSet: true, 340 }, 341 { 342 Name: "PEMLEX3SignedByISRGRootX1-in-CRLSet-clocked", 343 Leaf: data.PEMDAdrianIOSignedByLEX3, // idx=0 344 Presented: nil, 345 Intermediates: []string{ 346 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 347 data.PEMLEX3SignedByISRGRootX1, 348 }, 349 Roots: []string{ 350 data.PEMDSTRootCAX3SignedBySelf, // idx=3 351 }, 352 CurrentTime: 1501804800, // 2017-08-04T00:00:00 353 ExpectedChains: [][]int{ 354 {0, 1, 3}, 355 }, 356 ExpectedParents: []int{1}, 357 CRLSetFn: func() (*google.CRLSet, error) { 358 return crlSetBlocked([]string{data.PEMLEX3SignedByDSTRootCAX3}) 359 }, 360 InRevocationSet: true, 361 }, 362 { 363 Name: "PEMLEX3SignedByISRGRootX1-in-OneCRL", 364 Leaf: data.PEMDAdrianIOSignedByLEX3, // idx=0 365 Presented: nil, 366 Intermediates: []string{ 367 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 368 data.PEMLEX3SignedByISRGRootX1, 369 }, 370 Roots: []string{ 371 data.PEMDSTRootCAX3SignedBySelf, // idx=3 372 }, 373 CurrentTime: 1501804800, // 2017-08-04T00:00:00 374 ExpectedChains: [][]int{ 375 {0, 1, 3}, 376 }, 377 ExpectedParents: []int{1}, 378 OneCRLFn: func() (*mozilla.OneCRL, error) { 379 return oneCrlIntermediate(data.PEMDAdrianIOSignedByLEX3, []string{ 380 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 381 data.PEMLEX3SignedByISRGRootX1, 382 }) 383 }, 384 InRevocationSet: true, 385 }, 386 { 387 Name: "PEMLEX3SignedByISRGRootX1-in-OneCRL-blocked", 388 Leaf: data.PEMDAdrianIOSignedByLEX3, // idx=0 389 Presented: nil, 390 Intermediates: []string{ 391 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 392 data.PEMLEX3SignedByISRGRootX1, 393 }, 394 Roots: []string{ 395 data.PEMDSTRootCAX3SignedBySelf, // idx=3 396 }, 397 CurrentTime: 1501804800, // 2017-08-04T00:00:00 398 ExpectedChains: [][]int{ 399 {0, 1, 3}, 400 }, 401 ExpectedParents: []int{1}, 402 OneCRLFn: func() (*mozilla.OneCRL, error) { 403 return oneCrlBlocked(data.PEMDAdrianIOSignedByLEX3) 404 }, 405 InRevocationSet: true, 406 }, 407 { 408 Name: "le-two-intermediate-dst-root", 409 Leaf: data.PEMDAdrianIOSignedByLEX3, // idx=0 410 Presented: nil, 411 Intermediates: []string{ 412 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 413 data.PEMLEX3SignedByISRGRootX1, 414 }, 415 Roots: []string{ 416 data.PEMDSTRootCAX3SignedBySelf, // idx=3 417 }, 418 CurrentTime: 1501804800, // 2017-08-04T00:00:00 419 ExpectedChains: [][]int{ 420 {0, 1, 3}, 421 }, 422 ExpectedParents: []int{1}, 423 }, 424 { 425 Name: "dadrian-missing-intermediate", 426 Leaf: data.PEMDAdrianIOSignedByLEX3, 427 Intermediates: nil, 428 Roots: []string{ 429 data.PEMDSTRootCAX3SignedBySelf, 430 }, 431 CurrentTime: 1501804800, // 2017-08-04T00:00:00 432 ExpectedChains: nil, 433 ExpectedParents: nil, 434 }, 435 { 436 Name: "root-only", 437 Leaf: data.PEMDSTRootCAX3SignedBySelf, 438 Presented: nil, 439 Intermediates: []string{ 440 data.PEMLEX3SignedByDSTRootCAX3, 441 }, 442 Roots: []string{ 443 data.PEMDSTRootCAX3SignedBySelf, 444 }, 445 CurrentTime: 1501804800, // 2017-08-04T00:00:00 446 ExpectedChains: [][]int{ 447 {0}, 448 }, 449 ExpiredChains: nil, 450 NeverChains: nil, 451 ExpectedParents: nil, 452 }, 453 { 454 Name: "two-dadrian-le-in-intermediates", 455 Leaf: data.PEMDAdrianIOSignedByLEX3, // idx=0 456 Presented: nil, 457 Intermediates: []string{ 458 data.PEMDAdrianIOSignedByLEX3, // idx=1 459 data.PEMLEX3SignedByDSTRootCAX3, 460 data.PEMLEX3SignedByISRGRootX1, 461 data.PEMISRGRootX1SignedBySelf, 462 }, 463 Roots: []string{ 464 data.PEMISRGRootX1SignedBySelf, // idx=5 465 data.PEMDSTRootCAX3SignedBySelf, 466 }, 467 CurrentTime: 1501804800, // 2017-08-04T00:00:00 468 ExpectedChains: [][]int{ 469 {0, 2, 6}, {0, 3, 5}, 470 }, 471 ExpiredChains: nil, 472 NeverChains: nil, 473 ExpectedParents: []int{2, 3}, 474 }, 475 { 476 Name: "two-dadrian-le-no-presented", 477 Leaf: data.PEMDAdrianIOSignedByLEX3, // idx=0 478 Presented: nil, 479 Intermediates: []string{ 480 data.PEMLEX3SignedByDSTRootCAX3, // idx=1 481 data.PEMLEX3SignedByISRGRootX1, 482 data.PEMISRGRootX1SignedBySelf, 483 }, 484 Roots: []string{ 485 data.PEMISRGRootX1SignedBySelf, // idx=4 486 data.PEMDSTRootCAX3SignedBySelf, 487 }, 488 CurrentTime: 1501804800, // 2017-08-04T00:00:00 489 ExpectedChains: [][]int{ 490 {0, 1, 5}, {0, 2, 4}, 491 }, 492 ExpiredChains: nil, 493 NeverChains: nil, 494 ExpectedParents: []int{1, 2}, 495 }, 496 { 497 Name: "dod-root-ca-3-in-intermediates", 498 Leaf: data.PEMDoDRootCA3SignedByDoDInteropCA2Serial748, 499 Presented: nil, 500 Intermediates: []string{ 501 data.PEMDoDRootCA3SignedByCCEBInteropRootCA2, // idx=1 502 data.PEMDoDRootCA3SignedBySelf, 503 data.PEMDoDRootCA3SignedByDoDInteropCA2Serial655, 504 data.PEMDoDRootCA3SignedByDoDInteropCA2Serial748, 505 data.PEMFederalCommonPolicyCASignedByFederalBridgeCA, // idx=5 506 data.PEMFederalCommonPolicyCASignedByFederalBridgeCA2013, 507 data.PEMFederalCommonPolicyCASignedByFederalBridgeCA2016, 508 data.PEMDoDInteropCA2SignedByFederalBridgeCA, // idx=8 509 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial906, 510 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial8225, 511 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial8844, 512 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial9644, 513 data.PEMDoDInteropCA2SignedByFederalBridgeCA2016, 514 data.PEMFederalBridgeCASignedByDoDInteropCA2, // idx=14 515 data.PEMFederalBridgeCASignedByFederalBridgeCA2013, 516 data.PEMFederalBridgeCASignedByFederalCommonPolicyCA, 517 data.PEMFederalBridgeCA2013SignedByCommonPolicyCASerial5524, // idx=17 518 data.PEMFederalBridgeCA2013SignedByCommonPolicyCASerial11424, 519 data.PEMFederalBridgeCA2013SignedByDoDInteropCA2, 520 data.PEMFederalBridgeCA2013SignedByIdenTrust, 521 data.PEMFederalBridgeCA2016SignedByDodInteropCA2, // idx=21 522 data.PEMFederalBridgeCA2016SignedByFederalCommonPolicyCA, 523 }, 524 Roots: []string{ 525 data.PEMFederalCommonPolicyCASignedBySelf, // idx=23 526 }, 527 CurrentTime: 1501545600, // 2017-08-01T00:00:00 528 ExpectedChains: [][]int{ 529 {0, 12, 18, 23}, 530 {0, 13, 22, 23}, 531 }, 532 ExpiredChains: [][]int{ 533 {0, 8, 15, 17, 23}, 534 {0, 8, 15, 18, 23}, 535 {0, 9, 17, 23}, 536 {0, 9, 18, 23}, 537 {0, 10, 17, 23}, 538 {0, 10, 18, 23}, 539 {0, 11, 17, 23}, 540 {0, 11, 18, 23}, 541 {0, 12, 17, 23}, 542 }, 543 NeverChains: [][]int{ 544 {0, 8, 16, 23}, 545 }, 546 ExpectedParents: []int{12, 13}, 547 }, 548 { 549 Name: "dod-root-ca-3-leaf-no-presented", 550 Leaf: data.PEMDoDRootCA3SignedByDoDInteropCA2Serial748, 551 Presented: nil, 552 Intermediates: []string{ 553 data.PEMDoDRootCA3SignedByCCEBInteropRootCA2, // idx=1 554 data.PEMDoDRootCA3SignedBySelf, 555 data.PEMDoDRootCA3SignedByDoDInteropCA2Serial655, 556 data.PEMDAdrianIOSignedByLEX3, 557 data.PEMFederalCommonPolicyCASignedByFederalBridgeCA, // idx=5 558 data.PEMFederalCommonPolicyCASignedByFederalBridgeCA2013, 559 data.PEMFederalCommonPolicyCASignedByFederalBridgeCA2016, 560 data.PEMDoDInteropCA2SignedByFederalBridgeCA, // idx=8 561 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial906, 562 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial8225, 563 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial8844, 564 data.PEMDoDInteropCA2SignedByFederalBridgeCA2013Serial9644, 565 data.PEMDoDInteropCA2SignedByFederalBridgeCA2016, 566 data.PEMFederalBridgeCASignedByDoDInteropCA2, // idx=14 567 data.PEMFederalBridgeCASignedByFederalBridgeCA2013, 568 data.PEMFederalBridgeCASignedByFederalCommonPolicyCA, 569 data.PEMFederalBridgeCA2013SignedByCommonPolicyCASerial5524, // idx=17 570 data.PEMFederalBridgeCA2013SignedByCommonPolicyCASerial11424, 571 data.PEMFederalBridgeCA2013SignedByDoDInteropCA2, 572 data.PEMFederalBridgeCA2013SignedByIdenTrust, 573 data.PEMFederalBridgeCA2016SignedByDodInteropCA2, // idx=21 574 data.PEMFederalBridgeCA2016SignedByFederalCommonPolicyCA, 575 }, 576 Roots: []string{ 577 data.PEMFederalCommonPolicyCASignedBySelf, // idx=23 578 }, 579 CurrentTime: 1501545600, // 2017-08-01T00:00:00 580 ExpectedChains: [][]int{ 581 {0, 12, 18, 23}, 582 {0, 13, 22, 23}, 583 }, 584 ExpiredChains: [][]int{ 585 {0, 8, 15, 17, 23}, 586 {0, 8, 15, 18, 23}, 587 {0, 9, 17, 23}, 588 {0, 9, 18, 23}, 589 {0, 10, 17, 23}, 590 {0, 10, 18, 23}, 591 {0, 11, 17, 23}, 592 {0, 11, 18, 23}, 593 {0, 12, 17, 23}, 594 }, 595 NeverChains: [][]int{ 596 {0, 8, 16, 23}, 597 }, 598 ExpectedParents: []int{12, 13}, 599 }, 600 { 601 Name: "google-no-presented-chain", 602 Leaf: data.PEMGoogleSignedByGIAG2, 603 Intermediates: []string{ 604 data.PEMGIAG2SignedByGeoTrust, 605 }, 606 Roots: []string{ 607 data.PEMGeoTrustSignedBySelf, 608 }, 609 CurrentTime: 1395785200, 610 DNSName: "www.google.com", 611 ExpectedChains: [][]int{ 612 {0, 1, 2}, 613 }, 614 ExpectedParents: []int{1}, 615 CRLSetFn: loadCrlSet6375, 616 OneCRLFn: loadTestOneCRL, 617 }, 618 { 619 Name: "google-mixed-case", 620 Leaf: data.PEMGoogleSignedByGIAG2, 621 Intermediates: []string{ 622 data.PEMGIAG2SignedByGeoTrust, 623 }, 624 Roots: []string{ 625 data.PEMGeoTrustSignedBySelf, 626 }, 627 CurrentTime: 1395785200, 628 DNSName: "www.google.com", 629 ExpectedChains: [][]int{ 630 {0, 1, 2}, 631 }, 632 ExpectedParents: []int{1}, 633 CRLSetFn: loadCrlSet6375, 634 OneCRLFn: loadTestOneCRL, 635 }, 636 { 637 Name: "google-not-yet-valid", 638 Leaf: data.PEMGoogleSignedByGIAG2, 639 Intermediates: []string{ 640 data.PEMGIAG2SignedByGeoTrust, 641 }, 642 Roots: []string{ 643 data.PEMGeoTrustSignedBySelf, 644 }, 645 CurrentTime: 1, 646 DNSName: "www.google.com", 647 ExpectedChains: nil, 648 ExpiredChains: [][]int{ 649 {0, 1, 2}, 650 }, 651 ExpectedParents: []int{1}, 652 }, 653 { 654 Name: "google-expired", 655 Leaf: data.PEMGoogleSignedByGIAG2, 656 Intermediates: []string{ 657 data.PEMGIAG2SignedByGeoTrust, 658 }, 659 Roots: []string{ 660 data.PEMGeoTrustSignedBySelf, 661 }, 662 CurrentTime: 2000000000, 663 DNSName: "www.google.com", 664 ExpectedChains: nil, 665 ExpiredChains: [][]int{ 666 {0, 1, 2}, 667 }, 668 ExpectedParents: []int{1}, 669 CRLSetFn: loadCrlSet6375, 670 OneCRLFn: loadTestOneCRL, 671 }, 672 { 673 Name: "google-name-mismatch", 674 Leaf: data.PEMGoogleSignedByGIAG2, 675 Intermediates: []string{ 676 data.PEMGIAG2SignedByGeoTrust, 677 }, 678 Roots: []string{ 679 data.PEMGeoTrustSignedBySelf, 680 }, 681 CurrentTime: 1395785200, 682 DNSName: "www.example.com", 683 ExpectedChains: [][]int{ 684 {0, 1, 2}, 685 }, 686 ExpectedParents: []int{1}, 687 ExpectHostnameError: true, 688 }, 689 { 690 Name: "google-missing-intermediate", 691 Leaf: data.PEMGoogleSignedByGIAG2, 692 Intermediates: nil, 693 Roots: []string{ 694 data.PEMGeoTrustSignedBySelf, 695 }, 696 CurrentTime: 1395785200, 697 ExpectedChains: nil, 698 ExpectedParents: nil, 699 }, 700 { 701 Name: "google-with-unrelated-intermediate", 702 Leaf: data.PEMGoogleSignedByGIAG2, 703 Intermediates: []string{ 704 data.PEMGIAG2SignedByGeoTrust, 705 data.PEMDAdrianIOSignedByLEX3, 706 }, 707 Roots: []string{ 708 data.PEMGeoTrustSignedBySelf, 709 }, 710 CurrentTime: 1395785200, 711 DNSName: "www.google.com", 712 ExpectedChains: [][]int{ 713 {0, 1, 3}, 714 }, 715 ExpectedParents: []int{1}, 716 }, 717 } 718 719 func TestVerify(t *testing.T) { 720 for _, test := range verifyTests { 721 test.parseSelf() 722 v := test.makeVerifier() 723 opts := test.makeVerifyOptions() 724 verifyResult := v.Verify(test.parsedLeaf(), *opts) 725 if err := test.checkVerifyResult(verifyResult); err != nil { 726 t.Errorf("%s: %s", test.Name, err) 727 } 728 } 729 } 730 731 func loadCRLSet(data string) (*google.CRLSet, error) { 732 crlSetFile, err := os.Open(data) 733 if err != nil { 734 return nil, err 735 } 736 defer crlSetFile.Close() 737 738 crlSetBytes, err := ioutil.ReadAll(crlSetFile) 739 if err != nil { 740 return nil, err 741 } 742 743 crlset, err := google.Parse(crlSetBytes, "6375") 744 if err != nil { 745 return nil, err 746 } 747 return crlset, nil 748 } 749 750 func loadOneCRL(data string) (*mozilla.OneCRL, error) { 751 oneCRLFile, err := os.Open(data) 752 if err != nil { 753 return nil, err 754 } 755 defer oneCRLFile.Close() 756 oneCRLBytes, err := ioutil.ReadAll(oneCRLFile) 757 if err != nil { 758 return nil, err 759 } 760 761 onecrl, err := mozilla.Parse(oneCRLBytes) 762 if err != nil { 763 return nil, err 764 } 765 return onecrl, nil 766 } 767 768 func loadCrlSet6375() (*google.CRLSet, error) { 769 return loadCRLSet("testdata/crl-set-6375") 770 } 771 772 func loadTestOneCRL() (*mozilla.OneCRL, error) { 773 return loadOneCRL("testdata/test_onecrl.json") 774 } 775 776 func crlSetIntermediate(leafPEM string, intermediatesPEM []string) (*google.CRLSet, error) { 777 crl := &google.CRLSet{ 778 IssuerLists: make(map[string]*google.IssuerList), 779 } 780 781 leaf := loadPEM(leafPEM) 782 for _, ca := range loadPEMs(intermediatesPEM) { 783 if ca.Subject.CommonName == leaf.Issuer.CommonName { 784 spki := hex.EncodeToString(ca.SPKIFingerprint) 785 786 entries := &google.IssuerList{ 787 SPKIHash: spki, 788 Entries: []*google.Entry{ 789 {SerialNumber: leaf.SerialNumber}, 790 }, 791 } 792 793 crl.IssuerLists[spki] = entries 794 } 795 } 796 return crl, nil 797 } 798 799 func crlSetBlocked(intermediatesPEM []string) (*google.CRLSet, error) { 800 crl := &google.CRLSet{ 801 IssuerLists: make(map[string]*google.IssuerList), 802 BlockedSPKIs: make([]string, 0), 803 } 804 805 for _, ca := range loadPEMs(intermediatesPEM) { 806 spki := hex.EncodeToString(ca.SPKIFingerprint) 807 crl.BlockedSPKIs = append(crl.BlockedSPKIs, spki) 808 809 } 810 return crl, nil 811 } 812 813 func oneCrlIntermediate(leafPEM string, intermediatesPEM []string) (*mozilla.OneCRL, error) { 814 crl := &mozilla.OneCRL{ 815 IssuerLists: make(map[string]*mozilla.IssuerList), 816 } 817 818 leaf := loadPEM(leafPEM) 819 for _, ca := range loadPEMs(intermediatesPEM) { 820 if ca.Subject.CommonName == leaf.Issuer.CommonName { 821 entries := &mozilla.IssuerList{ 822 Issuer: &ca.Subject, 823 Entries: []*mozilla.Entry{ 824 { 825 Issuer: &ca.Subject, 826 SerialNumber: leaf.SerialNumber, 827 }, 828 }, 829 } 830 831 crl.IssuerLists[leaf.Issuer.String()] = entries 832 } 833 } 834 return crl, nil 835 } 836 837 func oneCrlBlocked(leafPEM string) (*mozilla.OneCRL, error) { 838 crl := &mozilla.OneCRL{ 839 IssuerLists: make(map[string]*mozilla.IssuerList), 840 Blocked: make([]*mozilla.SubjectAndPublicKey, 0), 841 } 842 843 leaf := loadPEM(leafPEM) 844 845 pubKeyData, _ := x509.MarshalPKIXPublicKey(leaf.PublicKey) 846 hash := sha256.Sum256(pubKeyData) 847 848 spk := &mozilla.SubjectAndPublicKey{ 849 RawSubject: leaf.RawSubject, 850 Subject: &leaf.Subject, 851 PubKeyHash: hash[:], 852 } 853 854 crl.Blocked = append(crl.Blocked, spk) 855 return crl, nil 856 }