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