// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package x509import ()typeInvalidReasonintconst (// NotAuthorizedToSign results when a certificate is signed by another // which isn't marked as a CA certificate.NotAuthorizedToSignInvalidReason = iota// Expired results when a certificate has expired, based on the time // given in the VerifyOptions.Expired// CANotAuthorizedForThisName results when an intermediate or root // certificate has a name constraint which doesn't permit a DNS or // other name (including IP address) in the leaf certificate.CANotAuthorizedForThisName// TooManyIntermediates results when a path length constraint is // violated.TooManyIntermediates// IncompatibleUsage results when the certificate's key usage indicates // that it may only be used for a different purpose.IncompatibleUsage// NameMismatch results when the subject name of a parent certificate // does not match the issuer name in the child.NameMismatch// NameConstraintsWithoutSANs is a legacy error and is no longer returned.NameConstraintsWithoutSANs// UnconstrainedName results when a CA certificate contains permitted // name constraints, but leaf certificate contains a name of an // unsupported or unconstrained type.UnconstrainedName// TooManyConstraints results when the number of comparison operations // needed to check a certificate exceeds the limit set by // VerifyOptions.MaxConstraintComparisions. This limit exists to // prevent pathological certificates can consuming excessive amounts of // CPU time to verify.TooManyConstraints// CANotAuthorizedForExtKeyUsage results when an intermediate or root // certificate does not permit a requested extended key usage.CANotAuthorizedForExtKeyUsage)// CertificateInvalidError results when an odd error occurs. Users of this// library probably want to handle all these errors uniformly.typeCertificateInvalidErrorstruct { Cert *Certificate Reason InvalidReason Detail string}func ( CertificateInvalidError) () string {switch .Reason {caseNotAuthorizedToSign:return"x509: certificate is not authorized to sign other certificates"caseExpired:return"x509: certificate has expired or is not yet valid: " + .DetailcaseCANotAuthorizedForThisName:return"x509: a root or intermediate certificate is not authorized to sign for this name: " + .DetailcaseCANotAuthorizedForExtKeyUsage:return"x509: a root or intermediate certificate is not authorized for an extended key usage: " + .DetailcaseTooManyIntermediates:return"x509: too many intermediates for path length constraint"caseIncompatibleUsage:return"x509: certificate specifies an incompatible key usage"caseNameMismatch:return"x509: issuer name does not match subject from issuing certificate"caseNameConstraintsWithoutSANs:return"x509: issuer has name constraints but leaf doesn't have a SAN extension"caseUnconstrainedName:return"x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + .Detail }return"x509: unknown error"}// HostnameError results when the set of authorized names doesn't match the// requested name.typeHostnameErrorstruct { Certificate *Certificate Host string}func ( HostnameError) () string { := .Certificateif !.hasSANExtension() && matchHostnames(.Subject.CommonName, .Host) {return"x509: certificate relies on legacy Common Name field, use SANs instead" }varstringif := net.ParseIP(.Host); != nil {// Trying to validate an IPiflen(.IPAddresses) == 0 {return"x509: cannot validate certificate for " + .Host + " because it doesn't contain any IP SANs" }for , := range .IPAddresses {iflen() > 0 { += ", " } += .String() } } else { = strings.Join(.DNSNames, ", ") }iflen() == 0 {return"x509: certificate is not valid for any names, but wanted to match " + .Host }return"x509: certificate is valid for " + + ", not " + .Host}// UnknownAuthorityError results when the certificate issuer is unknowntypeUnknownAuthorityErrorstruct { Cert *Certificate// hintErr contains an error that may be helpful in determining why an // authority wasn't found. hintErr error// hintCert contains a possible authority certificate that was rejected // because of the error in hintErr. hintCert *Certificate}func ( UnknownAuthorityError) () string { := "x509: certificate signed by unknown authority"if .hintErr != nil { := .hintCert.Subject.CommonNameiflen() == 0 {iflen(.hintCert.Subject.Organization) > 0 { = .hintCert.Subject.Organization[0] } else { = "serial:" + .hintCert.SerialNumber.String() } } += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", .hintErr, ) }return}// SystemRootsError results when we fail to load the system root certificates.typeSystemRootsErrorstruct { Err error}func ( SystemRootsError) () string { := "x509: failed to load system roots and no roots provided"if .Err != nil {return + "; " + .Err.Error() }return}func ( SystemRootsError) () error { return .Err }// errNotParsed is returned when a certificate without ASN.1 contents is// verified. Platform-specific verification needs the ASN.1 contents.var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")// VerifyOptions contains parameters for Certificate.Verify.typeVerifyOptionsstruct {// DNSName, if set, is checked against the leaf certificate with // Certificate.VerifyHostname or the platform verifier. DNSName string// Intermediates is an optional pool of certificates that are not trust // anchors, but can be used to form a chain from the leaf certificate to a // root certificate. Intermediates *CertPool// Roots is the set of trusted root certificates the leaf certificate needs // to chain up to. If nil, the system roots or the platform verifier are used. Roots *CertPool// CurrentTime is used to check the validity of all certificates in the // chain. If zero, the current time is used. CurrentTime time.Time// KeyUsages specifies which Extended Key Usage values are acceptable. A // chain is accepted if it allows any of the listed values. An empty list // means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny. KeyUsages []ExtKeyUsage// MaxConstraintComparisions is the maximum number of comparisons to // perform when checking a given certificate's name constraints. If // zero, a sensible default is used. This limit prevents pathological // certificates from consuming excessive amounts of CPU time when // validating. It does not apply to the platform verifier. MaxConstraintComparisions int}const ( leafCertificate = iota intermediateCertificate rootCertificate)// rfc2821Mailbox represents a “mailbox” (which is an email address to most// people) by breaking it into the “local” (i.e. before the '@') and “domain”// parts.type rfc2821Mailbox struct { local, domain string}// parseRFC2821Mailbox parses an email address into local and domain parts,// based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280,// Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The// format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”.func parseRFC2821Mailbox( string) ( rfc2821Mailbox, bool) {iflen() == 0 {return , false } := make([]byte, 0, len()/2)if [0] == '"' {// Quoted-string = DQUOTE *qcontent DQUOTE // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 // qcontent = qtext / quoted-pair // qtext = non-whitespace-control / // %d33 / %d35-91 / %d93-126 // quoted-pair = ("\" text) / obs-qp // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text // // (Names beginning with “obs-” are the obsolete syntax from RFC 2822, // Section 4. Since it has been 16 years, we no longer accept that.) = [1:] :for {iflen() == 0 {return , false } := [0] = [1:]switch {case == '"':breakcase == '\\':// quoted-pairiflen() == 0 {return , false }if [0] == 11 || [0] == 12 || (1 <= [0] && [0] <= 9) || (14 <= [0] && [0] <= 127) { = append(, [0]) = [1:] } else {return , false }case == 11 || == 12 ||// Space (char 32) is not allowed based on the // BNF, but RFC 3696 gives an example that // assumes that it is. Several “verified” // errata continue to argue about this point. // We choose to accept it. == 32 || == 33 || == 127 || (1 <= && <= 8) || (14 <= && <= 31) || (35 <= && <= 91) || (93 <= && <= 126):// qtext = append(, )default:return , false } } } else {// Atom ("." Atom)* :forlen() > 0 {// atext from RFC 2822, Section 3.2.4 := [0]switch {case == '\\':// Examples given in RFC 3696 suggest that // escaped characters can appear outside of a // quoted string. Several “verified” errata // continue to argue the point. We choose to // accept it. = [1:]iflen() == 0 {return , false }fallthroughcase ('0' <= && <= '9') || ('a' <= && <= 'z') || ('A' <= && <= 'Z') || == '!' || == '#' || == '$' || == '%' || == '&' || == '\'' || == '*' || == '+' || == '-' || == '/' || == '=' || == '?' || == '^' || == '_' || == '`' || == '{' || == '|' || == '}' || == '~' || == '.': = append(, [0]) = [1:]default:break } }iflen() == 0 {return , false }// From RFC 3696, Section 3: // “period (".") may also appear, but may not be used to start // or end the local part, nor may two or more consecutive // periods appear.” := []byte{'.', '.'}if [0] == '.' || [len()-1] == '.' ||bytes.Contains(, ) {return , false } }iflen() == 0 || [0] != '@' {return , false } = [1:]// The RFC species a format for domains, but that's known to be // violated in practice so we accept that anything after an '@' is the // domain part.if , := domainToReverseLabels(); ! {return , false } .local = string() .domain = return , true}// domainToReverseLabels converts a textual domain name like foo.example.com to// the list of labels in reverse order, e.g. ["com", "example", "foo"].func domainToReverseLabels( string) ( []string, bool) {forlen() > 0 {if := strings.LastIndexByte(, '.'); == -1 { = append(, ) = "" } else { = append(, [+1:]) = [:]if == 0 { // domain == ""// domain is prefixed with an empty label, append an empty // string to reverseLabels to indicate this. = append(, "") } } }iflen() > 0 && len([0]) == 0 {// An empty label at the end indicates an absolute value.returnnil, false }for , := range {iflen() == 0 {// Empty labels are otherwise invalid.returnnil, false }for , := range {if < 33 || > 126 {// Invalid character.returnnil, false } } }return , true}func matchEmailConstraint( rfc2821Mailbox, string) (bool, error) {// If the constraint contains an @, then it specifies an exact mailbox // name.ifstrings.Contains(, "@") { , := parseRFC2821Mailbox()if ! {returnfalse, fmt.Errorf("x509: internal error: cannot parse constraint %q", ) }return .local == .local && strings.EqualFold(.domain, .domain), nil }// Otherwise the constraint is like a DNS constraint of the domain part // of the mailbox.returnmatchDomainConstraint(.domain, )}func matchURIConstraint( *url.URL, string) (bool, error) {// From RFC 5280, Section 4.2.1.10: // “a uniformResourceIdentifier that does not include an authority // component with a host name specified as a fully qualified domain // name (e.g., if the URI either does not include an authority // component or includes an authority component in which the host name // is specified as an IP address), then the application MUST reject the // certificate.” := .Hostiflen() == 0 {returnfalse, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", .String()) }ifstrings.Contains(, ":") && !strings.HasSuffix(, "]") {varerror , _, = net.SplitHostPort(.Host)if != nil {returnfalse, } }ifstrings.HasPrefix(, "[") && strings.HasSuffix(, "]") ||net.ParseIP() != nil {returnfalse, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", .String()) }returnmatchDomainConstraint(, )}func matchIPConstraint( net.IP, *net.IPNet) (bool, error) {iflen() != len(.IP) {returnfalse, nil }for := range {if := .Mask[]; []& != .IP[]& {returnfalse, nil } }returntrue, nil}func matchDomainConstraint(, string) (bool, error) {// The meaning of zero length constraints is not specified, but this // code follows NSS and accepts them as matching everything.iflen() == 0 {returntrue, nil } , := domainToReverseLabels()if ! {returnfalse, fmt.Errorf("x509: internal error: cannot parse domain %q", ) }// RFC 5280 says that a leading period in a domain name means that at // least one label must be prepended, but only for URI and email // constraints, not DNS constraints. The code also supports that // behaviour for DNS constraints. := falseif [0] == '.' { = true = [1:] } , := domainToReverseLabels()if ! {returnfalse, fmt.Errorf("x509: internal error: cannot parse domain %q", ) }iflen() < len() || ( && len() == len()) {returnfalse, nil }for , := range {if !strings.EqualFold(, []) {returnfalse, nil } }returntrue, nil}// checkNameConstraints checks that c permits a child certificate to claim the// given name, of type nameType. The argument parsedName contains the parsed// form of name, suitable for passing to the match function. The total number// of comparisons is tracked in the given count and should not exceed the given// limit.func ( *Certificate) ( *int,int,string,string,any,func(, any) ( bool, error), , any) error { := reflect.ValueOf() * += .Len()if * > {returnCertificateInvalidError{, TooManyConstraints, ""} }for := 0; < .Len(); ++ { := .Index().Interface() , := (, )if != nil {returnCertificateInvalidError{, CANotAuthorizedForThisName, .Error()} }if {returnCertificateInvalidError{, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", , , )} } } := reflect.ValueOf() * += .Len()if * > {returnCertificateInvalidError{, TooManyConstraints, ""} } := truefor := 0; < .Len(); ++ { := .Index().Interface()varerrorif , = (, ); != nil {returnCertificateInvalidError{, CANotAuthorizedForThisName, .Error()} }if {break } }if ! {returnCertificateInvalidError{, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", , )} }returnnil}// isValid performs validity checks on c given that it is a candidate to append// to the chain in currentChain.func ( *Certificate) ( int, []*Certificate, *VerifyOptions) error {iflen(.UnhandledCriticalExtensions) > 0 {returnUnhandledCriticalExtension{} }iflen() > 0 { := [len()-1]if !bytes.Equal(.RawIssuer, .RawSubject) {returnCertificateInvalidError{, NameMismatch, ""} } } := .CurrentTimeif .IsZero() { = time.Now() }if .Before(.NotBefore) {returnCertificateInvalidError{Cert: ,Reason: Expired,Detail: fmt.Sprintf("current time %s is before %s", .Format(time.RFC3339), .NotBefore.Format(time.RFC3339)), } } elseif .After(.NotAfter) {returnCertificateInvalidError{Cert: ,Reason: Expired,Detail: fmt.Sprintf("current time %s is after %s", .Format(time.RFC3339), .NotAfter.Format(time.RFC3339)), } } := .MaxConstraintComparisionsif == 0 { = 250000 } := 0if == intermediateCertificate || == rootCertificate {iflen() == 0 {returnerrors.New("x509: internal error: empty chain when appending CA cert") } }if ( == intermediateCertificate || == rootCertificate) && .hasNameConstraints() { := []*Certificate{}for , := range {if .hasSANExtension() { = append(, ) } }for , := range { := forEachSAN(.getSANExtension(), func( int, []byte) error {switch {casenameTypeEmail: := string() , := parseRFC2821Mailbox()if ! {returnfmt.Errorf("x509: cannot parse rfc822Name %q", ) }if := .checkNameConstraints(&, , "email address", , ,func(, any) (bool, error) {returnmatchEmailConstraint(.(rfc2821Mailbox), .(string)) }, .PermittedEmailAddresses, .ExcludedEmailAddresses); != nil {return }casenameTypeDNS: := string()if , := domainToReverseLabels(); ! {returnfmt.Errorf("x509: cannot parse dnsName %q", ) }if := .checkNameConstraints(&, , "DNS name", , ,func(, any) (bool, error) {returnmatchDomainConstraint(.(string), .(string)) }, .PermittedDNSDomains, .ExcludedDNSDomains); != nil {return }casenameTypeURI: := string() , := url.Parse()if != nil {returnfmt.Errorf("x509: internal error: URI SAN %q failed to parse", ) }if := .checkNameConstraints(&, , "URI", , ,func(, any) (bool, error) {returnmatchURIConstraint(.(*url.URL), .(string)) }, .PermittedURIDomains, .ExcludedURIDomains); != nil {return }casenameTypeIP: := net.IP()if := len(); != net.IPv4len && != net.IPv6len {returnfmt.Errorf("x509: internal error: IP SAN %x failed to parse", ) }if := .checkNameConstraints(&, , "IP address", .String(), ,func(, any) (bool, error) {returnmatchIPConstraint(.(net.IP), .(*net.IPNet)) }, .PermittedIPRanges, .ExcludedIPRanges); != nil {return }default:// Unknown SAN types are ignored. }returnnil })if != nil {return } } }// KeyUsage status flags are ignored. From Engineering Security, Peter // Gutmann: A European government CA marked its signing certificates as // being valid for encryption only, but no-one noticed. Another // European CA marked its signature keys as not being valid for // signatures. A different CA marked its own trusted root certificate // as being invalid for certificate signing. Another national CA // distributed a certificate to be used to encrypt data for the // country’s tax authority that was marked as only being usable for // digital signatures but not for encryption. Yet another CA reversed // the order of the bit flags in the keyUsage due to confusion over // encoding endianness, essentially setting a random keyUsage in // certificates that it issued. Another CA created a self-invalidating // certificate by adding a certificate policy statement stipulating // that the certificate had to be used strictly as specified in the // keyUsage, and a keyUsage containing a flag indicating that the RSA // encryption key could only be used for Diffie-Hellman key agreement.if == intermediateCertificate && (!.BasicConstraintsValid || !.IsCA) {returnCertificateInvalidError{, NotAuthorizedToSign, ""} }if .BasicConstraintsValid && .MaxPathLen >= 0 { := len() - 1if > .MaxPathLen {returnCertificateInvalidError{, TooManyIntermediates, ""} } }if !boringAllowCert() {// IncompatibleUsage is not quite right here, // but it's also the "no chains found" error // and is close enough.returnCertificateInvalidError{, IncompatibleUsage, ""} }returnnil}// Verify attempts to verify c by building one or more chains from c to a// certificate in opts.Roots, using certificates in opts.Intermediates if// needed. If successful, it returns one or more chains where the first// element of the chain is c and the last element is from opts.Roots.//// If opts.Roots is nil, the platform verifier might be used, and// verification details might differ from what is described below. If system// roots are unavailable the returned error will be of type SystemRootsError.//// Name constraints in the intermediates will be applied to all names claimed// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim// example.com if an intermediate doesn't permit it, even if example.com is not// the name being validated. Note that DirectoryName constraints are not// supported.//// Name constraint validation follows the rules from RFC 5280, with the// addition that DNS name constraints may use the leading period format// defined for emails and URIs. When a constraint has a leading period// it indicates that at least one additional label must be prepended to// the constrained name to be considered valid.//// Extended Key Usage values are enforced nested down a chain, so an intermediate// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that// list. (While this is not specified, it is common practice in order to limit// the types of certificates a CA can issue.)//// Certificates that use SHA1WithRSA and ECDSAWithSHA1 signatures are not supported,// and will not be used to build chains.//// Certificates other than c in the returned chains should not be modified.//// WARNING: this function doesn't do any revocation checking.func ( *Certificate) ( VerifyOptions) ( [][]*Certificate, error) {// Platform-specific verification needs the ASN.1 contents so // this makes the behavior consistent across platforms.iflen(.Raw) == 0 {returnnil, errNotParsed }for := 0; < .Intermediates.len(); ++ { , , := .Intermediates.cert()if != nil {returnnil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", ) }iflen(.Raw) == 0 {returnnil, errNotParsed } }// Use platform verifiers, where available, if Roots is from SystemCertPool.ifruntime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {// Don't use the system verifier if the system pool was replaced with a non-system pool, // i.e. if SetFallbackRoots was called with x509usefallbackroots=1. := systemRootsPool()if .Roots == nil && ( == nil || .systemPool) {return .systemVerify(&) }if .Roots != nil && .Roots.systemPool { , := .systemVerify(&)// If the platform verifier succeeded, or there are no additional // roots, return the platform verifier result. Otherwise, continue // with the Go verifier.if == nil || .Roots.len() == 0 {return , } } }if .Roots == nil { .Roots = systemRootsPool()if .Roots == nil {returnnil, SystemRootsError{systemRootsErr} } } = .isValid(leafCertificate, nil, &)if != nil {return }iflen(.DNSName) > 0 { = .VerifyHostname(.DNSName)if != nil {return } }var [][]*Certificateif .Roots.contains() { = [][]*Certificate{{}} } else { , = .buildChains([]*Certificate{}, nil, &)if != nil {returnnil, } }iflen(.KeyUsages) == 0 { .KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} }for , := range .KeyUsages {if == ExtKeyUsageAny {// If any key usage is acceptable, no need to check the chain for // key usages.return , nil } } = make([][]*Certificate, 0, len())for , := range {ifcheckChainForKeyUsage(, .KeyUsages) { = append(, ) } }iflen() == 0 {returnnil, CertificateInvalidError{, IncompatibleUsage, ""} }return , nil}func appendToFreshChain( []*Certificate, *Certificate) []*Certificate { := make([]*Certificate, len()+1)copy(, ) [len()] = return}// alreadyInChain checks whether a candidate certificate is present in a chain.// Rather than doing a direct byte for byte equivalency check, we check if the// subject, public key, and SAN, if present, are equal. This prevents loops that// are created by mutual cross-signatures, or other cross-signature bridge// oddities.func alreadyInChain( *Certificate, []*Certificate) bool {typeinterface { (crypto.PublicKey) bool }var *pkix.Extensionfor , := range .Extensions {if .Id.Equal(oidExtensionSubjectAltName) { = &break } }for , := range {if !bytes.Equal(.RawSubject, .RawSubject) {continue }if !.PublicKey.().(.PublicKey) {continue }var *pkix.Extensionfor , := range .Extensions {if .Id.Equal(oidExtensionSubjectAltName) { = &break } }if == nil && == nil {returntrue } elseif == nil || == nil {returnfalse }ifbytes.Equal(.Value, .Value) {returntrue } }returnfalse}// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls// that an invocation of buildChains will (transitively) make. Most chains are// less than 15 certificates long, so this leaves space for multiple chains and// for failed checks due to different intermediates having the same Subject.const maxChainSignatureChecks = 100func ( *Certificate) ( []*Certificate, *int, *VerifyOptions) ( [][]*Certificate, error) {var (error *Certificate ) := func( int, potentialParent) {if .cert.PublicKey == nil || alreadyInChain(.cert, ) {return }if == nil { = new(int) } *++if * > maxChainSignatureChecks { = errors.New("x509: signature check attempts limit reached while verifying certificate chain")return }if := .CheckSignatureFrom(.cert); != nil {if == nil { = = .cert }return } = .cert.isValid(, , )if != nil {if == nil { = = .cert }return }if .constraint != nil {if := .constraint(); != nil {if == nil { = = .cert }return } }switch {caserootCertificate: = append(, appendToFreshChain(, .cert))caseintermediateCertificate:var [][]*Certificate , = .cert.(appendToFreshChain(, .cert), , ) = append(, ...) } }for , := range .Roots.findPotentialParents() { (rootCertificate, ) }for , := range .Intermediates.findPotentialParents() { (intermediateCertificate, ) }iflen() > 0 { = nil }iflen() == 0 && == nil { = UnknownAuthorityError{, , } }return}func validHostnamePattern( string) bool { returnvalidHostname(, true) }func validHostnameInput( string) bool { returnvalidHostname(, false) }// validHostname reports whether host is a valid hostname that can be matched or// matched against according to RFC 6125 2.2, with some leniency to accommodate// legacy values.func validHostname( string, bool) bool {if ! { = strings.TrimSuffix(, ".") }iflen() == 0 {returnfalse }if == "*" {// Bare wildcards are not allowed, they are not valid DNS names, // nor are they allowed per RFC 6125.returnfalse }for , := rangestrings.Split(, ".") {if == "" {// Empty label.returnfalse }if && == 0 && == "*" {// Only allow full left-most wildcards, as those are the only ones // we match, and matching literal '*' characters is probably never // the expected behavior.continue }for , := range {if'a' <= && <= 'z' {continue }if'0' <= && <= '9' {continue }if'A' <= && <= 'Z' {continue }if == '-' && != 0 {continue }if == '_' {// Not a valid character in hostnames, but commonly // found in deployments outside the WebPKI.continue }returnfalse } }returntrue}func matchExactly(, string) bool {if == "" || == "." || == "" || == "." {returnfalse }returntoLowerCaseASCII() == toLowerCaseASCII()}func matchHostnames(, string) bool { = toLowerCaseASCII() = toLowerCaseASCII(strings.TrimSuffix(, "."))iflen() == 0 || len() == 0 {returnfalse } := strings.Split(, ".") := strings.Split(, ".")iflen() != len() {returnfalse }for , := range {if == 0 && == "*" {continue }if != [] {returnfalse } }returntrue}// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use// an explicitly ASCII function to avoid any sharp corners resulting from// performing Unicode operations on DNS labels.func toLowerCaseASCII( string) string {// If the string is already lower-case then there's nothing to do. := truefor , := range {if == utf8.RuneError {// If we get a UTF-8 error then there might be // upper-case ASCII bytes in the invalid sequence. = falsebreak }if'A' <= && <= 'Z' { = falsebreak } }if {return } := []byte()for , := range {if'A' <= && <= 'Z' { [] += 'a' - 'A' } }returnstring()}// VerifyHostname returns nil if c is a valid certificate for the named host.// Otherwise it returns an error describing the mismatch.//// IP addresses can be optionally enclosed in square brackets and are checked// against the IPAddresses field. Other names are checked case insensitively// against the DNSNames field. If the names are valid hostnames, the certificate// fields can have a wildcard as the complete left-most label (e.g. *.example.com).//// Note that the legacy Common Name field is ignored.func ( *Certificate) ( string) error {// IP addresses may be written in [ ]. := iflen() >= 3 && [0] == '[' && [len()-1] == ']' { = [1 : len()-1] }if := net.ParseIP(); != nil {// We only match IP addresses against IP SANs. // See RFC 6125, Appendix B.2.for , := range .IPAddresses {if .Equal() {returnnil } }returnHostnameError{, } } := toLowerCaseASCII() // Save allocations inside the loop. := validHostnameInput()for , := range .DNSNames {// Ideally, we'd only match valid hostnames according to RFC 6125 like // browsers (more or less) do, but in practice Go is used in a wider // array of contexts and can't even assume DNS resolution. Instead, // always allow perfect matches, and only apply wildcard and trailing // dot processing to valid hostnames.if && validHostnamePattern() {ifmatchHostnames(, ) {returnnil } } else {ifmatchExactly(, ) {returnnil } } }returnHostnameError{, }}func checkChainForKeyUsage( []*Certificate, []ExtKeyUsage) bool { := make([]ExtKeyUsage, len())copy(, )iflen() == 0 {returnfalse } := len()// We walk down the list and cross out any usages that aren't supported // by each certificate. If we cross out all the usages, then the chain // is unacceptable.:for := len() - 1; >= 0; -- { := []iflen(.ExtKeyUsage) == 0 && len(.UnknownExtKeyUsage) == 0 {// The certificate doesn't have any extended key usage specified.continue }for , := range .ExtKeyUsage {if == ExtKeyUsageAny {// The certificate is explicitly good for any usage.continue } }constExtKeyUsage = -1 :for , := range {if == {continue }for , := range .ExtKeyUsage {if == {continue } } [] = --if == 0 {returnfalse } } }returntrue}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.