github.com/emmansun/gmsm@v0.29.1/smx509/verify.go (about)

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