github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/x509/verify.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package x509 6 7 /* 8 x509/verify.go 实现证书信任链的验证: 9 c.Verify : 尝试构建证书c的有效信任链 10 */ 11 12 import ( 13 "bytes" 14 "errors" 15 "fmt" 16 "net" 17 "net/url" 18 "reflect" 19 "runtime" 20 "strings" 21 "time" 22 "unicode/utf8" 23 24 log "gitee.com/zhaochuninhefei/zcgolog/zclog" 25 ) 26 27 type InvalidReason int 28 29 const ( 30 // NotAuthorizedToSign results when a certificate is signed by another 31 // which isn't marked as a CA certificate. 32 NotAuthorizedToSign InvalidReason = iota 33 // Expired results when a certificate has expired, based on the time 34 // given in the VerifyOptions. 35 Expired 36 // CANotAuthorizedForThisName results when an intermediate or root 37 // certificate has a name constraint which doesn't permit a DNS or 38 // other name (including IP address) in the leaf certificate. 39 CANotAuthorizedForThisName 40 // TooManyIntermediates results when a path length constraint is 41 // violated. 42 TooManyIntermediates 43 // IncompatibleUsage results when the certificate's key usage indicates 44 // that it may only be used for a different purpose. 45 IncompatibleUsage 46 // NameMismatch results when the subject name of a parent certificate 47 // does not match the issuer name in the child. 48 NameMismatch 49 // NameConstraintsWithoutSANs is a legacy error and is no longer returned. 50 NameConstraintsWithoutSANs 51 // UnconstrainedName results when a CA certificate contains permitted 52 // name constraints, but leaf certificate contains a name of an 53 // unsupported or unconstrained type. 54 UnconstrainedName 55 // TooManyConstraints results when the number of comparison operations 56 // needed to check a certificate exceeds the limit set by 57 // VerifyOptions.MaxConstraintComparisions. This limit exists to 58 // prevent pathological certificates can consuming excessive amounts of 59 // CPU time to verify. 60 TooManyConstraints 61 // CANotAuthorizedForExtKeyUsage results when an intermediate or root 62 // certificate does not permit a requested extended key usage. 63 CANotAuthorizedForExtKeyUsage 64 ) 65 66 // CertificateInvalidError results when an odd error occurs. Users of this 67 // library probably want to handle all these errors uniformly. 68 type CertificateInvalidError struct { 69 Cert *Certificate 70 Reason InvalidReason 71 Detail string 72 } 73 74 func (e CertificateInvalidError) Error() string { 75 switch e.Reason { 76 case NotAuthorizedToSign: 77 return "x509: certificate is not authorized to sign other certificates" 78 case Expired: 79 return "x509: certificate has expired or is not yet valid: " + e.Detail 80 case CANotAuthorizedForThisName: 81 return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail 82 case CANotAuthorizedForExtKeyUsage: 83 return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail 84 case TooManyIntermediates: 85 return "x509: too many intermediates for path length constraint" 86 case IncompatibleUsage: 87 return "x509: certificate specifies an incompatible key usage" 88 case NameMismatch: 89 return "x509: issuer name does not match subject from issuing certificate" 90 case NameConstraintsWithoutSANs: 91 return "x509: issuer has name constraints but leaf doesn't have a SAN extension" 92 case UnconstrainedName: 93 return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail 94 } 95 return "x509: unknown error" 96 } 97 98 // HostnameError results when the set of authorized names doesn't match the 99 // requested name. 100 type HostnameError struct { 101 Certificate *Certificate 102 Host string 103 } 104 105 func (h HostnameError) Error() string { 106 c := h.Certificate 107 108 if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) { 109 return "x509: certificate relies on legacy Common Name field, use SANs instead" 110 } 111 112 var valid string 113 if ip := net.ParseIP(h.Host); ip != nil { 114 // Trying to validate an IP 115 if len(c.IPAddresses) == 0 { 116 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" 117 } 118 for _, san := range c.IPAddresses { 119 if len(valid) > 0 { 120 valid += ", " 121 } 122 valid += san.String() 123 } 124 } else { 125 valid = strings.Join(c.DNSNames, ", ") 126 } 127 128 if len(valid) == 0 { 129 return "x509: certificate is not valid for any names, but wanted to match " + h.Host 130 } 131 return "x509: certificate is valid for " + valid + ", not " + h.Host 132 } 133 134 // UnknownAuthorityError results when the certificate issuer is unknown 135 type UnknownAuthorityError struct { 136 Cert *Certificate 137 // hintErr contains an error that may be helpful in determining why an 138 // authority wasn't found. 139 hintErr error 140 // hintCert contains a possible authority certificate that was rejected 141 // because of the error in hintErr. 142 hintCert *Certificate 143 } 144 145 func (e UnknownAuthorityError) Error() string { 146 s := "x509: certificate signed by unknown authority" 147 if e.hintErr != nil { 148 certName := e.hintCert.Subject.CommonName 149 if len(certName) == 0 { 150 if len(e.hintCert.Subject.Organization) > 0 { 151 certName = e.hintCert.Subject.Organization[0] 152 } else { 153 certName = "serial:" + e.hintCert.SerialNumber.String() 154 } 155 } 156 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName) 157 } 158 return s 159 } 160 161 // SystemRootsError results when we fail to load the system root certificates. 162 type SystemRootsError struct { 163 Err error 164 } 165 166 func (se SystemRootsError) Error() string { 167 msg := "x509: failed to load system roots and no roots provided" 168 if se.Err != nil { 169 return msg + "; " + se.Err.Error() 170 } 171 return msg 172 } 173 174 func (se SystemRootsError) Unwrap() error { return se.Err } 175 176 // errNotParsed is returned when a certificate without ASN.1 contents is 177 // verified. Platform-specific verification needs the ASN.1 contents. 178 var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate") 179 180 // VerifyOptions contains parameters for Certificate.Verify. 181 type VerifyOptions struct { 182 // 如果设置了 DNSName,则使用 Certificate.VerifyHostname 或平台验证程序检查叶证书。 183 // DNSName, if set, is checked against the leaf certificate with 184 // Certificate.VerifyHostname or the platform verifier. 185 DNSName string 186 187 // 可选的中间证书池,它们不是信任锚,但可用于形成从叶证书到根证书的链。 188 // Intermediates is an optional pool of certificates that are not trust 189 // anchors, but can be used to form a chain from the leaf certificate to a 190 // root certificate. 191 Intermediates *CertPool 192 193 // 根是叶证书需要链接到的一组受信任的根证书。 如果为零,则使用系统根或平台验证程序。 194 // Roots is the set of trusted root certificates the leaf certificate needs 195 // to chain up to. If nil, the system roots or the platform verifier are used. 196 Roots *CertPool 197 198 // CurrentTime 用于检查链中所有证书的有效性。 如果为零,则使用当前时间。 199 // CurrentTime is used to check the validity of all certificates in the 200 // chain. If zero, the current time is used. 201 CurrentTime time.Time 202 203 // KeyUsages 指定允许的扩展公钥用途。 204 // 目标证书只要匹配上任意一个指定的用途即可通过该项检查。 205 // 该字段默认值为 ExtKeyUsageServerAuth。 206 // 如果允许任意一种扩展公钥用途,请在该字段列表中加入 ExtKeyUsageAny。 207 // KeyUsages specifies which Extended Key Usage values are acceptable. A 208 // chain is accepted if it allows any of the listed values. An empty list 209 // means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny. 210 KeyUsages []ExtKeyUsage 211 212 // MaxConstraintComparisions 是检查给定证书的名称约束时要执行的最大比较次数。 213 // 如果为零,则使用合理的默认值。 214 // 此限制可防止病态证书在验证时消耗过多的 CPU 时间。 它不适用于平台验证者。 215 // MaxConstraintComparisions is the maximum number of comparisons to 216 // perform when checking a given certificate's name constraints. If 217 // zero, a sensible default is used. This limit prevents pathological 218 // certificates from consuming excessive amounts of CPU time when 219 // validating. It does not apply to the platform verifier. 220 MaxConstraintComparisions int 221 } 222 223 const ( 224 // 子证书 225 leafCertificate = iota 226 // 中间证书 227 intermediateCertificate 228 // 根证书 229 rootCertificate 230 ) 231 232 // rfc2821Mailbox represents a “mailbox” (which is an email address to most 233 // people) by breaking it into the “local” (i.e. before the '@') and “domain” 234 // parts. 235 type rfc2821Mailbox struct { 236 local, domain string 237 } 238 239 // parseRFC2821Mailbox parses an email address into local and domain parts, 240 // based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280, 241 // Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The 242 // format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”. 243 func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) { 244 if len(in) == 0 { 245 return mailbox, false 246 } 247 248 localPartBytes := make([]byte, 0, len(in)/2) 249 250 if in[0] == '"' { 251 // Quoted-string = DQUOTE *qcontent DQUOTE 252 // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 253 // qcontent = qtext / quoted-pair 254 // qtext = non-whitespace-control / 255 // %d33 / %d35-91 / %d93-126 256 // quoted-pair = ("\" text) / obs-qp 257 // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text 258 // 259 // (Names beginning with “obs-” are the obsolete syntax from RFC 2822, 260 // Section 4. Since it has been 16 years, we no longer accept that.) 261 in = in[1:] 262 QuotedString: 263 for { 264 if len(in) == 0 { 265 return mailbox, false 266 } 267 c := in[0] 268 in = in[1:] 269 270 switch { 271 case c == '"': 272 break QuotedString 273 274 case c == '\\': 275 // quoted-pair 276 if len(in) == 0 { 277 return mailbox, false 278 } 279 if in[0] == 11 || 280 in[0] == 12 || 281 (1 <= in[0] && in[0] <= 9) || 282 (14 <= in[0] && in[0] <= 127) { 283 localPartBytes = append(localPartBytes, in[0]) 284 in = in[1:] 285 } else { 286 return mailbox, false 287 } 288 289 case c == 11 || 290 c == 12 || 291 // Space (char 32) is not allowed based on the 292 // BNF, but RFC 3696 gives an example that 293 // assumes that it is. Several “verified” 294 // errata continue to argue about this point. 295 // We choose to accept it. 296 c == 32 || 297 c == 33 || 298 c == 127 || 299 (1 <= c && c <= 8) || 300 (14 <= c && c <= 31) || 301 (35 <= c && c <= 91) || 302 (93 <= c && c <= 126): 303 // qtext 304 localPartBytes = append(localPartBytes, c) 305 306 default: 307 return mailbox, false 308 } 309 } 310 } else { 311 // Atom ("." Atom)* 312 NextChar: 313 for len(in) > 0 { 314 // atext from RFC 2822, Section 3.2.4 315 c := in[0] 316 317 switch { 318 case c == '\\': 319 // Examples given in RFC 3696 suggest that 320 // escaped characters can appear outside of a 321 // quoted string. Several “verified” errata 322 // continue to argue the point. We choose to 323 // accept it. 324 in = in[1:] 325 if len(in) == 0 { 326 return mailbox, false 327 } 328 fallthrough 329 330 case ('0' <= c && c <= '9') || 331 ('a' <= c && c <= 'z') || 332 ('A' <= c && c <= 'Z') || 333 c == '!' || c == '#' || c == '$' || c == '%' || 334 c == '&' || c == '\'' || c == '*' || c == '+' || 335 c == '-' || c == '/' || c == '=' || c == '?' || 336 c == '^' || c == '_' || c == '`' || c == '{' || 337 c == '|' || c == '}' || c == '~' || c == '.': 338 localPartBytes = append(localPartBytes, in[0]) 339 in = in[1:] 340 341 default: 342 break NextChar 343 } 344 } 345 346 if len(localPartBytes) == 0 { 347 return mailbox, false 348 } 349 350 // From RFC 3696, Section 3: 351 // “period (".") may also appear, but may not be used to start 352 // or end the local part, nor may two or more consecutive 353 // periods appear.” 354 twoDots := []byte{'.', '.'} 355 if localPartBytes[0] == '.' || 356 localPartBytes[len(localPartBytes)-1] == '.' || 357 bytes.Contains(localPartBytes, twoDots) { 358 return mailbox, false 359 } 360 } 361 362 if len(in) == 0 || in[0] != '@' { 363 return mailbox, false 364 } 365 in = in[1:] 366 367 // The RFC species a format for domains, but that's known to be 368 // violated in practice so we accept that anything after an '@' is the 369 // domain part. 370 if _, ok := domainToReverseLabels(in); !ok { 371 return mailbox, false 372 } 373 374 mailbox.local = string(localPartBytes) 375 mailbox.domain = in 376 return mailbox, true 377 } 378 379 // domainToReverseLabels converts a textual domain name like foo.example.com to 380 // the list of labels in reverse order, e.g. ["com", "example", "foo"]. 381 func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { 382 for len(domain) > 0 { 383 if i := strings.LastIndexByte(domain, '.'); i == -1 { 384 reverseLabels = append(reverseLabels, domain) 385 domain = "" 386 } else { 387 reverseLabels = append(reverseLabels, domain[i+1:]) 388 domain = domain[:i] 389 } 390 } 391 392 if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 { 393 // An empty label at the end indicates an absolute value. 394 return nil, false 395 } 396 397 for _, label := range reverseLabels { 398 if len(label) == 0 { 399 // Empty labels are otherwise invalid. 400 return nil, false 401 } 402 403 for _, c := range label { 404 if c < 33 || c > 126 { 405 // Invalid character. 406 return nil, false 407 } 408 } 409 } 410 411 return reverseLabels, true 412 } 413 414 func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) { 415 // If the constraint contains an @, then it specifies an exact mailbox 416 // name. 417 if strings.Contains(constraint, "@") { 418 constraintMailbox, ok := parseRFC2821Mailbox(constraint) 419 if !ok { 420 return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint) 421 } 422 return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil 423 } 424 425 // Otherwise the constraint is like a DNS constraint of the domain part 426 // of the mailbox. 427 return matchDomainConstraint(mailbox.domain, constraint) 428 } 429 430 func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { 431 // From RFC 5280, Section 4.2.1.10: 432 // “a uniformResourceIdentifier that does not include an authority 433 // component with a host name specified as a fully qualified domain 434 // name (e.g., if the URI either does not include an authority 435 // component or includes an authority component in which the host name 436 // is specified as an IP address), then the application MUST reject the 437 // certificate.” 438 439 host := uri.Host 440 if len(host) == 0 { 441 return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String()) 442 } 443 444 if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") { 445 var err error 446 host, _, err = net.SplitHostPort(uri.Host) 447 if err != nil { 448 return false, err 449 } 450 } 451 452 if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") || 453 net.ParseIP(host) != nil { 454 return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) 455 } 456 457 return matchDomainConstraint(host, constraint) 458 } 459 460 func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { 461 if len(ip) != len(constraint.IP) { 462 return false, nil 463 } 464 465 for i := range ip { 466 if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask { 467 return false, nil 468 } 469 } 470 471 return true, nil 472 } 473 474 func matchDomainConstraint(domain, constraint string) (bool, error) { 475 // The meaning of zero length constraints is not specified, but this 476 // code follows NSS and accepts them as matching everything. 477 if len(constraint) == 0 { 478 return true, nil 479 } 480 481 domainLabels, ok := domainToReverseLabels(domain) 482 if !ok { 483 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) 484 } 485 486 // RFC 5280 says that a leading period in a domain name means that at 487 // least one label must be prepended, but only for URI and email 488 // constraints, not DNS constraints. The code also supports that 489 // behaviour for DNS constraints. 490 491 mustHaveSubdomains := false 492 if constraint[0] == '.' { 493 mustHaveSubdomains = true 494 constraint = constraint[1:] 495 } 496 497 constraintLabels, ok := domainToReverseLabels(constraint) 498 if !ok { 499 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) 500 } 501 502 if len(domainLabels) < len(constraintLabels) || 503 (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) { 504 return false, nil 505 } 506 507 for i, constraintLabel := range constraintLabels { 508 if !strings.EqualFold(constraintLabel, domainLabels[i]) { 509 return false, nil 510 } 511 } 512 513 return true, nil 514 } 515 516 // checkNameConstraints checks that c permits a child certificate to claim the 517 // given name, of type nameType. The argument parsedName contains the parsed 518 // form of name, suitable for passing to the match function. The total number 519 // of comparisons is tracked in the given count and should not exceed the given 520 // limit. 521 func (c *Certificate) checkNameConstraints(count *int, 522 maxConstraintComparisons int, 523 nameType string, 524 name string, 525 parsedName interface{}, 526 match func(parsedName, constraint interface{}) (match bool, err error), 527 permitted, excluded interface{}) error { 528 529 excludedValue := reflect.ValueOf(excluded) 530 531 *count += excludedValue.Len() 532 if *count > maxConstraintComparisons { 533 return CertificateInvalidError{c, TooManyConstraints, ""} 534 } 535 536 for i := 0; i < excludedValue.Len(); i++ { 537 constraint := excludedValue.Index(i).Interface() 538 match, err := match(parsedName, constraint) 539 if err != nil { 540 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} 541 } 542 543 if match { 544 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)} 545 } 546 } 547 548 permittedValue := reflect.ValueOf(permitted) 549 550 *count += permittedValue.Len() 551 if *count > maxConstraintComparisons { 552 return CertificateInvalidError{c, TooManyConstraints, ""} 553 } 554 555 ok := true 556 for i := 0; i < permittedValue.Len(); i++ { 557 constraint := permittedValue.Index(i).Interface() 558 559 var err error 560 if ok, err = match(parsedName, constraint); err != nil { 561 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} 562 } 563 564 if ok { 565 break 566 } 567 } 568 569 if !ok { 570 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)} 571 } 572 573 return nil 574 } 575 576 // isValid 对 证书c 执行有效性检查,证书c是当前证书莲currentChain的候选者。 577 // 578 // certType 证书c在证书链中的位置(0:子证书, 1:中间证书, 2:根证书) 579 // currentChain 当前证书链 580 // opts 校验参数 581 // 582 // isValid performs validity checks on c given that it is a candidate to append to the chain in currentChain. 583 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { 584 // log.Debugf("===== x509/verify.go isValid c.NotAfter 3: %s", c.NotAfter.Format(time.RFC3339)) 585 if len(c.UnhandledCriticalExtensions) > 0 { 586 log.Debugf("===== x509/verify.go isValid 证书解析时有未完全处理的扩展ID: %#v", c.UnhandledCriticalExtensions) 587 return UnhandledCriticalExtension{} 588 } 589 if len(currentChain) > 0 { 590 // 检查当前证书链最后一个证书的签署者是否是证书c的拥有者 591 child := currentChain[len(currentChain)-1] 592 if !bytes.Equal(child.RawIssuer, c.RawSubject) { 593 return CertificateInvalidError{c, NameMismatch, "===== x509/verify.go isValid 当前证书链最后一个证书的签署者不是证书c的拥有者"} 594 } 595 } 596 // 获取当前时间并检查证书c是否已过期 597 now := opts.CurrentTime 598 if now.IsZero() { 599 now = time.Now() 600 } 601 // log.Debugf("===== x509/verify.go isValid c.NotAfter 4: %s , now: %s", c.NotAfter.Format(time.RFC3339), now.Format(time.RFC3339)) 602 if now.Before(c.NotBefore) { 603 return CertificateInvalidError{ 604 Cert: c, 605 Reason: Expired, 606 Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)), 607 } 608 } else if now.After(c.NotAfter) { 609 // log.Debugf("===== x509/verify.go isValid c.NotAfter 5: %s , now: %s", c.NotAfter.Format(time.RFC3339), now.Format(time.RFC3339)) 610 return CertificateInvalidError{ 611 Cert: c, 612 Reason: Expired, 613 Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)), 614 } 615 } 616 617 maxConstraintComparisons := opts.MaxConstraintComparisions 618 if maxConstraintComparisons == 0 { 619 maxConstraintComparisons = 250000 620 } 621 comparisonCount := 0 622 623 var leaf *Certificate 624 if certType == intermediateCertificate || certType == rootCertificate { 625 // 如果证书c位置为中间证书或根证书,则当前证书链长度不可为0 626 if len(currentChain) == 0 { 627 return errors.New("===== x509/verify.go isValid 证书c位置为中间证书或根证书时当前证书链长度不可为0") 628 } 629 // 获取子证书:证书链的首个证书即子证书 630 leaf = currentChain[0] 631 } 632 // 证书c是中间证书或根证书,且证书c有名称约束,且子证书有SAN扩展字段时,进行对SAN扩展字段检查 633 if (certType == intermediateCertificate || certType == rootCertificate) && 634 c.hasNameConstraints() && leaf.hasSANExtension() { 635 err := forEachSAN(leaf.getSANExtension(), func(tag int, data []byte) error { 636 switch tag { 637 case nameTypeEmail: 638 name := string(data) 639 mailbox, ok := parseRFC2821Mailbox(name) 640 if !ok { 641 return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox) 642 } 643 644 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, 645 func(parsedName, constraint interface{}) (bool, error) { 646 return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string)) 647 }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { 648 return err 649 } 650 651 case nameTypeDNS: 652 name := string(data) 653 if _, ok := domainToReverseLabels(name); !ok { 654 return fmt.Errorf("x509: cannot parse dnsName %q", name) 655 } 656 657 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, 658 func(parsedName, constraint interface{}) (bool, error) { 659 return matchDomainConstraint(parsedName.(string), constraint.(string)) 660 }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { 661 return err 662 } 663 664 case nameTypeURI: 665 name := string(data) 666 uri, err := url.Parse(name) 667 if err != nil { 668 return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name) 669 } 670 671 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, 672 func(parsedName, constraint interface{}) (bool, error) { 673 return matchURIConstraint(parsedName.(*url.URL), constraint.(string)) 674 }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { 675 return err 676 } 677 678 case nameTypeIP: 679 ip := net.IP(data) 680 if l := len(ip); l != net.IPv4len && l != net.IPv6len { 681 return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data) 682 } 683 684 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip, 685 func(parsedName, constraint interface{}) (bool, error) { 686 return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet)) 687 }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil { 688 return err 689 } 690 691 default: 692 // Unknown SAN types are ignored. 693 } 694 695 return nil 696 }) 697 698 if err != nil { 699 return err 700 } 701 } 702 703 // KeyUsage status flags are ignored. From Engineering Security, Peter 704 // Gutmann: A European government CA marked its signing certificates as 705 // being valid for encryption only, but no-one noticed. Another 706 // European CA marked its signature keys as not being valid for 707 // signatures. A different CA marked its own trusted root certificate 708 // as being invalid for certificate signing. Another national CA 709 // distributed a certificate to be used to encrypt data for the 710 // country’s tax authority that was marked as only being usable for 711 // digital signatures but not for encryption. Yet another CA reversed 712 // the order of the bit flags in the keyUsage due to confusion over 713 // encoding endianness, essentially setting a random keyUsage in 714 // certificates that it issued. Another CA created a self-invalidating 715 // certificate by adding a certificate policy statement stipulating 716 // that the certificate had to be used strictly as specified in the 717 // keyUsage, and a keyUsage containing a flag indicating that the RSA 718 // encryption key could only be used for Diffie-Hellman key agreement. 719 720 // 证书c是中间证书时,其BasicConstraintsValid与IsCA必须为true 721 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) { 722 return CertificateInvalidError{c, NotAuthorizedToSign, ""} 723 } 724 // BasicConstraintsValid有效且设置了有效的MaxPathLen(大于0)时,做证书链长度检查。 725 // 证书链长度不能超过ca证书设置的有效MaxPathLen。 726 if c.BasicConstraintsValid && c.MaxPathLen >= 0 { 727 numIntermediates := len(currentChain) - 1 728 if numIntermediates > c.MaxPathLen { 729 return CertificateInvalidError{c, TooManyIntermediates, ""} 730 } 731 } 732 733 return nil 734 } 735 736 // Verify 尝试构建证书c的有效信任链。 737 // 成功时将返回验证成功的证书链,其中第一个证书即c自身,最后一个是opts.Roots中的某个根证书。 738 // Verify attempts to verify c by building one or more chains from c to a 739 // certificate in opts.Roots, using certificates in opts.Intermediates if 740 // needed. If successful, it returns one or more chains where the first 741 // element of the chain is c and the last element is from opts.Roots. 742 // 743 // opts.Roots为空时,将使用系统平台的根证书验证。此时验证的详细信息与本方法的实现会有不同。 744 // 如果系统根证书不可用将返回SystemRootsError。 745 // If opts.Roots is nil, the platform verifier might be used, and 746 // verification details might differ from what is described below. If system 747 // roots are unavailable the returned error will be of type SystemRootsError. 748 // 749 // 信任链的中间证书的名称约束对整个信任链有效,不能只看传入的opts.DNSName。 750 // Name constraints in the intermediates will be applied to all names claimed 751 // in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim 752 // example.com if an intermediate doesn't permit it, even if example.com is not 753 // the name being validated. Note that DirectoryName constraints are not 754 // supported. 755 // 756 // 名称约束遵循RFC 5280标准,因此可以使用前导句点匹配。 757 // Name constraint validation follows the rules from RFC 5280, with the 758 // addition that DNS name constraints may use the leading period format 759 // defined for emails and URIs. When a constraint has a leading period 760 // it indicates that at least one additional label must be prepended to 761 // the constrained name to be considered valid. 762 // 763 // Extended Key Usage values are enforced nested down a chain, so an intermediate 764 // or root that enumerates EKUs prevents a leaf from asserting an EKU not in that 765 // list. (While this is not specified, it is common practice in order to limit 766 // the types of certificates a CA can issue.) 767 // 768 // WARNING: this function doesn't do any revocation checking. 769 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { 770 // Platform-specific verification needs the ASN.1 contents so 771 // this makes the behavior consistent across platforms. 772 // log.Debugf("===== x509/verify.go Verify c.NotAfter 1: %s", c.NotAfter.Format(time.RFC3339)) 773 if len(c.Raw) == 0 { 774 return nil, errNotParsed 775 } 776 for i := 0; i < opts.Intermediates.len(); i++ { 777 // 如果检查参数中包含可选的中间证书池,则先检查这些中间证书是否能够正常读取 778 intermediatesCert, err := opts.Intermediates.cert(i) 779 if err != nil { 780 return nil, fmt.Errorf("gitee.com/zhaochuninhefei/gmgo/x509: error fetching intermediate: %w", err) 781 } 782 if len(intermediatesCert.Raw) == 0 { 783 return nil, errNotParsed 784 } 785 } 786 // 检查参数的根证书池为空,且平台为windows时,调用目标证书的系统校验,使用windows自己的校验与证书链构建。 787 // Use Windows's own verification and chain building. 788 if opts.Roots == nil && runtime.GOOS == "windows" { 789 return c.systemVerify(&opts) 790 } 791 // 检查参数的根证书池为空,且平台不是windows时,获取系统的跟证书池 792 if opts.Roots == nil { 793 opts.Roots = systemRootsPool() 794 if opts.Roots == nil { 795 return nil, SystemRootsError{systemRootsErr} 796 } 797 } 798 // log.Debugf("===== x509/verify.go Verify c.NotAfter 2: %s", c.NotAfter.Format(time.RFC3339)) 799 // 将目标证书作为叶证书进行有效性检查 800 err = c.isValid(leafCertificate, nil, &opts) 801 if err != nil { 802 return 803 } 804 // 检查参数设置了DNSName时,对目标证书c做域名(或IP)检查 805 if len(opts.DNSName) > 0 { 806 err = c.VerifyHostname(opts.DNSName) 807 if err != nil { 808 return 809 } 810 } 811 // 创建证书信任链 812 var candidateChains [][]*Certificate 813 if opts.Roots.contains(c) { 814 // 如果检查参数的根证书池中包含目标证书c,则直接将其加入证书信任链,此时信任链只有这一个证书(叶证书) 815 candidateChains = append(candidateChains, []*Certificate{c}) 816 } else { 817 // 目标证书c不是检查参数的根证书池中的某一个,则将其作为第一个证书(叶证书)加入证书信任链 818 if candidateChains, err = c.buildChains(nil, []*Certificate{c}, nil, &opts); err != nil { 819 return nil, err 820 } 821 } 822 // 获取检查参数的扩展公钥用途字段,未设置时默认值为 ExtKeyUsageServerAuth 823 keyUsages := opts.KeyUsages 824 if len(keyUsages) == 0 { 825 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} 826 } 827 // 如果扩展公钥用途包含 ExtKeyUsageAny , 则无需检查,直接返回证书信任链 828 for _, usage := range keyUsages { 829 if usage == ExtKeyUsageAny { 830 return candidateChains, nil 831 } 832 } 833 // 检查证书信任链中每个证书的扩展公钥用途是否能够匹配检查参数的扩展公钥用途。 834 // 只保留匹配用途的证书留在证书链中。 835 for _, candidate := range candidateChains { 836 if checkChainForKeyUsage(candidate, keyUsages) { 837 chains = append(chains, candidate) 838 } 839 } 840 if len(chains) == 0 { 841 return nil, CertificateInvalidError{c, IncompatibleUsage, ""} 842 } 843 return chains, nil 844 } 845 846 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { 847 n := make([]*Certificate, len(chain)+1) 848 copy(n, chain) 849 n[len(chain)] = cert 850 return n 851 } 852 853 // maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls 854 // that an invocation of buildChains will (transitively) make. Most chains are 855 // less than 15 certificates long, so this leaves space for multiple chains and 856 // for failed checks due to different intermediates having the same Subject. 857 const maxChainSignatureChecks = 100 858 859 // 为证书c创建信任链 860 func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) { 861 var ( 862 hintErr error 863 hintCert *Certificate 864 ) 865 // 定义considerCandidate用于验证c并添加信任链 866 considerCandidate := func(certType int, candidate *Certificate) { 867 for _, cert := range currentChain { 868 if cert.Equal(candidate) { 869 return 870 } 871 } 872 873 if sigChecks == nil { 874 sigChecks = new(int) 875 } 876 *sigChecks++ 877 if *sigChecks > maxChainSignatureChecks { 878 // 验签次数有限制,防止过多的验签 879 err = errors.New("x509: signature check attempts limit reached while verifying certificate chain") 880 return 881 } 882 // 使用当前证书candidate对c进行验签,即检查证书c是否由candidate拥有者签署。 883 // 该步骤会最终调用到对应公钥的验签方法。 884 if err := c.CheckSignatureFrom(candidate); err != nil { 885 if hintErr == nil { 886 hintErr = err 887 hintCert = candidate 888 } 889 return 890 } 891 // 检查candidate的有效性 892 err = candidate.isValid(certType, currentChain, opts) 893 if err != nil { 894 return 895 } 896 897 switch certType { 898 case rootCertificate: 899 // 如果candidate是根证书,则直接加入c的信任链 900 chains = append(chains, appendToFreshChain(currentChain, candidate)) 901 case intermediateCertificate: 902 if cache == nil { 903 cache = make(map[*Certificate][][]*Certificate) 904 } 905 // 尝试从之前的遍历中缓存的信任链里找到candidate的信任链 906 childChains, ok := cache[candidate] 907 if !ok { 908 // 如果candidate是中间证书且并未建立信任链,则为其建立信任链,此处是递归 909 childChains, err = candidate.buildChains(cache, appendToFreshChain(currentChain, candidate), sigChecks, opts) 910 cache[candidate] = childChains 911 } 912 // 将candidate的信任链加入c的信任链 913 chains = append(chains, childChains...) 914 } 915 } 916 // 遍历根证书,尝试验证c 917 for _, root := range opts.Roots.findPotentialParents(c) { 918 considerCandidate(rootCertificate, root) 919 } 920 // 遍历中间证书,尝试验证c 921 for _, intermediate := range opts.Intermediates.findPotentialParents(c) { 922 considerCandidate(intermediateCertificate, intermediate) 923 } 924 925 if len(chains) > 0 { 926 err = nil 927 } 928 if len(chains) == 0 && err == nil { 929 err = UnknownAuthorityError{c, hintErr, hintCert} 930 } 931 932 return 933 } 934 935 func validHostnamePattern(host string) bool { return validHostname(host, true) } 936 func validHostnameInput(host string) bool { return validHostname(host, false) } 937 938 // validHostname reports whether host is a valid hostname that can be matched or 939 // matched against according to RFC 6125 2.2, with some leniency to accommodate 940 // legacy values. 941 func validHostname(host string, isPattern bool) bool { 942 if !isPattern { 943 host = strings.TrimSuffix(host, ".") 944 } 945 if len(host) == 0 { 946 return false 947 } 948 949 for i, part := range strings.Split(host, ".") { 950 if part == "" { 951 // Empty label. 952 return false 953 } 954 if isPattern && i == 0 && part == "*" { 955 // Only allow full left-most wildcards, as those are the only ones 956 // we match, and matching literal '*' characters is probably never 957 // the expected behavior. 958 continue 959 } 960 for j, c := range part { 961 if 'a' <= c && c <= 'z' { 962 continue 963 } 964 if '0' <= c && c <= '9' { 965 continue 966 } 967 if 'A' <= c && c <= 'Z' { 968 continue 969 } 970 if c == '-' && j != 0 { 971 continue 972 } 973 if c == '_' { 974 // Not a valid character in hostnames, but commonly 975 // found in deployments outside the WebPKI. 976 continue 977 } 978 return false 979 } 980 } 981 982 return true 983 } 984 985 func matchExactly(hostA, hostB string) bool { 986 if hostA == "" || hostA == "." || hostB == "" || hostB == "." { 987 return false 988 } 989 return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB) 990 } 991 992 func matchHostnames(pattern, host string) bool { 993 pattern = toLowerCaseASCII(pattern) 994 host = toLowerCaseASCII(strings.TrimSuffix(host, ".")) 995 996 if len(pattern) == 0 || len(host) == 0 { 997 return false 998 } 999 1000 patternParts := strings.Split(pattern, ".") 1001 hostParts := strings.Split(host, ".") 1002 1003 if len(patternParts) != len(hostParts) { 1004 return false 1005 } 1006 1007 for i, patternPart := range patternParts { 1008 if i == 0 && patternPart == "*" { 1009 continue 1010 } 1011 if patternPart != hostParts[i] { 1012 return false 1013 } 1014 } 1015 1016 return true 1017 } 1018 1019 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use 1020 // an explicitly ASCII function to avoid any sharp corners resulting from 1021 // performing Unicode operations on DNS labels. 1022 func toLowerCaseASCII(in string) string { 1023 // If the string is already lower-case then there's nothing to do. 1024 isAlreadyLowerCase := true 1025 for _, c := range in { 1026 if c == utf8.RuneError { 1027 // If we get a UTF-8 error then there might be 1028 // upper-case ASCII bytes in the invalid sequence. 1029 isAlreadyLowerCase = false 1030 break 1031 } 1032 if 'A' <= c && c <= 'Z' { 1033 isAlreadyLowerCase = false 1034 break 1035 } 1036 } 1037 1038 if isAlreadyLowerCase { 1039 return in 1040 } 1041 1042 out := []byte(in) 1043 for i, c := range out { 1044 if 'A' <= c && c <= 'Z' { 1045 out[i] += 'a' - 'A' 1046 } 1047 } 1048 return string(out) 1049 } 1050 1051 // VerifyHostname 检查证书域名(或IP) 1052 // VerifyHostname returns nil if c is a valid certificate for the named host. 1053 // Otherwise it returns an error describing the mismatch. 1054 // 1055 // IP addresses can be optionally enclosed in square brackets and are checked 1056 // against the IPAddresses field. Other names are checked case insensitively 1057 // against the DNSNames field. If the names are valid hostnames, the certificate 1058 // fields can have a wildcard as the left-most label. 1059 // 1060 // Note that the legacy Common Name field is ignored. 1061 func (c *Certificate) VerifyHostname(h string) error { 1062 // IP addresses may be written in [ ]. 1063 candidateIP := h 1064 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { 1065 candidateIP = h[1 : len(h)-1] 1066 } 1067 if ip := net.ParseIP(candidateIP); ip != nil { 1068 // We only match IP addresses against IP SANs. 1069 // See RFC 6125, Appendix B.2. 1070 for _, candidate := range c.IPAddresses { 1071 if ip.Equal(candidate) { 1072 return nil 1073 } 1074 } 1075 return HostnameError{c, candidateIP} 1076 } 1077 1078 candidateName := toLowerCaseASCII(h) // Save allocations inside the loop. 1079 validCandidateName := validHostnameInput(candidateName) 1080 1081 for _, match := range c.DNSNames { 1082 // Ideally, we'd only match valid hostnames according to RFC 6125 like 1083 // browsers (more or less) do, but in practice Go is used in a wider 1084 // array of contexts and can't even assume DNS resolution. Instead, 1085 // always allow perfect matches, and only apply wildcard and trailing 1086 // dot processing to valid hostnames. 1087 if validCandidateName && validHostnamePattern(match) { 1088 if matchHostnames(match, candidateName) { 1089 return nil 1090 } 1091 } else { 1092 if matchExactly(match, candidateName) { 1093 return nil 1094 } 1095 } 1096 } 1097 1098 return HostnameError{c, h} 1099 } 1100 1101 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { 1102 usages := make([]ExtKeyUsage, len(keyUsages)) 1103 copy(usages, keyUsages) 1104 1105 if len(chain) == 0 { 1106 return false 1107 } 1108 1109 usagesRemaining := len(usages) 1110 1111 // We walk down the list and cross out any usages that aren't supported 1112 // by each certificate. If we cross out all the usages, then the chain 1113 // is unacceptable. 1114 1115 NextCert: 1116 for i := len(chain) - 1; i >= 0; i-- { 1117 cert := chain[i] 1118 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { 1119 // The certificate doesn't have any extended key usage specified. 1120 continue 1121 } 1122 1123 for _, usage := range cert.ExtKeyUsage { 1124 if usage == ExtKeyUsageAny { 1125 // The certificate is explicitly good for any usage. 1126 continue NextCert 1127 } 1128 } 1129 1130 const invalidUsage ExtKeyUsage = -1 1131 1132 NextRequestedUsage: 1133 for i, requestedUsage := range usages { 1134 if requestedUsage == invalidUsage { 1135 continue 1136 } 1137 1138 for _, usage := range cert.ExtKeyUsage { 1139 if requestedUsage == usage { 1140 continue NextRequestedUsage 1141 } else if requestedUsage == ExtKeyUsageServerAuth && 1142 (usage == ExtKeyUsageNetscapeServerGatedCrypto || 1143 usage == ExtKeyUsageMicrosoftServerGatedCrypto) { 1144 // In order to support COMODO 1145 // certificate chains, we have to 1146 // accept Netscape or Microsoft SGC 1147 // usages as equal to ServerAuth. 1148 continue NextRequestedUsage 1149 } 1150 } 1151 1152 usages[i] = invalidUsage 1153 usagesRemaining-- 1154 if usagesRemaining == 0 { 1155 return false 1156 } 1157 } 1158 } 1159 1160 return true 1161 }