github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/crypto/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  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"net"
    12  	"runtime"
    13  	"strings"
    14  	"time"
    15  	"unicode/utf8"
    16  )
    17  
    18  type InvalidReason int
    19  
    20  const (
    21  	// NotAuthorizedToSign results when a certificate is signed by another
    22  	// which isn't marked as a CA certificate.
    23  	NotAuthorizedToSign InvalidReason = iota
    24  	// Expired results when a certificate has expired, based on the time
    25  	// given in the VerifyOptions.
    26  	Expired
    27  	// CANotAuthorizedForThisName results when an intermediate or root
    28  	// certificate has a name constraint which doesn't include the name
    29  	// being checked.
    30  	CANotAuthorizedForThisName
    31  	// TooManyIntermediates results when a path length constraint is
    32  	// violated.
    33  	TooManyIntermediates
    34  	// IncompatibleUsage results when the certificate's key usage indicates
    35  	// that it may only be used for a different purpose.
    36  	IncompatibleUsage
    37  	// NameMismatch results when the subject name of a parent certificate
    38  	// does not match the issuer name in the child.
    39  	NameMismatch
    40  )
    41  
    42  // CertificateInvalidError results when an odd error occurs. Users of this
    43  // library probably want to handle all these errors uniformly.
    44  type CertificateInvalidError struct {
    45  	Cert   *Certificate
    46  	Reason InvalidReason
    47  }
    48  
    49  func (e CertificateInvalidError) Error() string {
    50  	switch e.Reason {
    51  	case NotAuthorizedToSign:
    52  		return "x509: certificate is not authorized to sign other certificates"
    53  	case Expired:
    54  		return "x509: certificate has expired or is not yet valid"
    55  	case CANotAuthorizedForThisName:
    56  		return "x509: a root or intermediate certificate is not authorized to sign in this domain"
    57  	case TooManyIntermediates:
    58  		return "x509: too many intermediates for path length constraint"
    59  	case IncompatibleUsage:
    60  		return "x509: certificate specifies an incompatible key usage"
    61  	case NameMismatch:
    62  		return "x509: issuer name does not match subject from issuing certificate"
    63  	}
    64  	return "x509: unknown error"
    65  }
    66  
    67  // HostnameError results when the set of authorized names doesn't match the
    68  // requested name.
    69  type HostnameError struct {
    70  	Certificate *Certificate
    71  	Host        string
    72  }
    73  
    74  func (h HostnameError) Error() string {
    75  	c := h.Certificate
    76  
    77  	var valid string
    78  	if ip := net.ParseIP(h.Host); ip != nil {
    79  		// Trying to validate an IP
    80  		if len(c.IPAddresses) == 0 {
    81  			return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
    82  		}
    83  		for _, san := range c.IPAddresses {
    84  			if len(valid) > 0 {
    85  				valid += ", "
    86  			}
    87  			valid += san.String()
    88  		}
    89  	} else {
    90  		if c.hasSANExtension() {
    91  			valid = strings.Join(c.DNSNames, ", ")
    92  		} else {
    93  			valid = c.Subject.CommonName
    94  		}
    95  	}
    96  
    97  	if len(valid) == 0 {
    98  		return "x509: certificate is not valid for any names, but wanted to match " + h.Host
    99  	}
   100  	return "x509: certificate is valid for " + valid + ", not " + h.Host
   101  }
   102  
   103  // UnknownAuthorityError results when the certificate issuer is unknown
   104  type UnknownAuthorityError struct {
   105  	Cert *Certificate
   106  	// hintErr contains an error that may be helpful in determining why an
   107  	// authority wasn't found.
   108  	hintErr error
   109  	// hintCert contains a possible authority certificate that was rejected
   110  	// because of the error in hintErr.
   111  	hintCert *Certificate
   112  }
   113  
   114  func (e UnknownAuthorityError) Error() string {
   115  	s := "x509: certificate signed by unknown authority"
   116  	if e.hintErr != nil {
   117  		certName := e.hintCert.Subject.CommonName
   118  		if len(certName) == 0 {
   119  			if len(e.hintCert.Subject.Organization) > 0 {
   120  				certName = e.hintCert.Subject.Organization[0]
   121  			} else {
   122  				certName = "serial:" + e.hintCert.SerialNumber.String()
   123  			}
   124  		}
   125  		s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
   126  	}
   127  	return s
   128  }
   129  
   130  // SystemRootsError results when we fail to load the system root certificates.
   131  type SystemRootsError struct {
   132  	Err error
   133  }
   134  
   135  func (se SystemRootsError) Error() string {
   136  	msg := "x509: failed to load system roots and no roots provided"
   137  	if se.Err != nil {
   138  		return msg + "; " + se.Err.Error()
   139  	}
   140  	return msg
   141  }
   142  
   143  // errNotParsed is returned when a certificate without ASN.1 contents is
   144  // verified. Platform-specific verification needs the ASN.1 contents.
   145  var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
   146  
   147  // VerifyOptions contains parameters for Certificate.Verify. It's a structure
   148  // because other PKIX verification APIs have ended up needing many options.
   149  type VerifyOptions struct {
   150  	DNSName       string
   151  	Intermediates *CertPool
   152  	Roots         *CertPool // if nil, the system roots are used
   153  	CurrentTime   time.Time // if zero, the current time is used
   154  	// KeyUsage specifies which Extended Key Usage values are acceptable.
   155  	// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
   156  	// constraint down the chain which mirrors Windows CryptoAPI behavior,
   157  	// but not the spec. To accept any key usage, include ExtKeyUsageAny.
   158  	KeyUsages []ExtKeyUsage
   159  }
   160  
   161  const (
   162  	leafCertificate = iota
   163  	intermediateCertificate
   164  	rootCertificate
   165  )
   166  
   167  func matchNameConstraint(domain, constraint string) bool {
   168  	// The meaning of zero length constraints is not specified, but this
   169  	// code follows NSS and accepts them as matching everything.
   170  	if len(constraint) == 0 {
   171  		return true
   172  	}
   173  
   174  	if len(domain) < len(constraint) {
   175  		return false
   176  	}
   177  
   178  	prefixLen := len(domain) - len(constraint)
   179  	if !strings.EqualFold(domain[prefixLen:], constraint) {
   180  		return false
   181  	}
   182  
   183  	if prefixLen == 0 {
   184  		return true
   185  	}
   186  
   187  	isSubdomain := domain[prefixLen-1] == '.'
   188  	constraintHasLeadingDot := constraint[0] == '.'
   189  	return isSubdomain != constraintHasLeadingDot
   190  }
   191  
   192  // isValid performs validity checks on the c.
   193  func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
   194  	if len(c.UnhandledCriticalExtensions) > 0 {
   195  		return UnhandledCriticalExtension{}
   196  	}
   197  
   198  	if len(currentChain) > 0 {
   199  		child := currentChain[len(currentChain)-1]
   200  		if !bytes.Equal(child.RawIssuer, c.RawSubject) {
   201  			return CertificateInvalidError{c, NameMismatch}
   202  		}
   203  	}
   204  
   205  	now := opts.CurrentTime
   206  	if now.IsZero() {
   207  		now = time.Now()
   208  	}
   209  	if now.Before(c.NotBefore) || now.After(c.NotAfter) {
   210  		return CertificateInvalidError{c, Expired}
   211  	}
   212  
   213  	if len(c.PermittedDNSDomains) > 0 {
   214  		ok := false
   215  		for _, constraint := range c.PermittedDNSDomains {
   216  			ok = matchNameConstraint(opts.DNSName, constraint)
   217  			if ok {
   218  				break
   219  			}
   220  		}
   221  
   222  		if !ok {
   223  			return CertificateInvalidError{c, CANotAuthorizedForThisName}
   224  		}
   225  	}
   226  
   227  	for _, constraint := range c.ExcludedDNSDomains {
   228  		if matchNameConstraint(opts.DNSName, constraint) {
   229  			return CertificateInvalidError{c, CANotAuthorizedForThisName}
   230  		}
   231  	}
   232  
   233  	// KeyUsage status flags are ignored. From Engineering Security, Peter
   234  	// Gutmann: A European government CA marked its signing certificates as
   235  	// being valid for encryption only, but no-one noticed. Another
   236  	// European CA marked its signature keys as not being valid for
   237  	// signatures. A different CA marked its own trusted root certificate
   238  	// as being invalid for certificate signing. Another national CA
   239  	// distributed a certificate to be used to encrypt data for the
   240  	// country’s tax authority that was marked as only being usable for
   241  	// digital signatures but not for encryption. Yet another CA reversed
   242  	// the order of the bit flags in the keyUsage due to confusion over
   243  	// encoding endianness, essentially setting a random keyUsage in
   244  	// certificates that it issued. Another CA created a self-invalidating
   245  	// certificate by adding a certificate policy statement stipulating
   246  	// that the certificate had to be used strictly as specified in the
   247  	// keyUsage, and a keyUsage containing a flag indicating that the RSA
   248  	// encryption key could only be used for Diffie-Hellman key agreement.
   249  
   250  	if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
   251  		return CertificateInvalidError{c, NotAuthorizedToSign}
   252  	}
   253  
   254  	if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
   255  		numIntermediates := len(currentChain) - 1
   256  		if numIntermediates > c.MaxPathLen {
   257  			return CertificateInvalidError{c, TooManyIntermediates}
   258  		}
   259  	}
   260  
   261  	return nil
   262  }
   263  
   264  // Verify attempts to verify c by building one or more chains from c to a
   265  // certificate in opts.Roots, using certificates in opts.Intermediates if
   266  // needed. If successful, it returns one or more chains where the first
   267  // element of the chain is c and the last element is from opts.Roots.
   268  //
   269  // If opts.Roots is nil and system roots are unavailable the returned error
   270  // will be of type SystemRootsError.
   271  //
   272  // WARNING: this doesn't do any revocation checking.
   273  func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
   274  	// Platform-specific verification needs the ASN.1 contents so
   275  	// this makes the behavior consistent across platforms.
   276  	if len(c.Raw) == 0 {
   277  		return nil, errNotParsed
   278  	}
   279  	if opts.Intermediates != nil {
   280  		for _, intermediate := range opts.Intermediates.certs {
   281  			if len(intermediate.Raw) == 0 {
   282  				return nil, errNotParsed
   283  			}
   284  		}
   285  	}
   286  
   287  	// Use Windows's own verification and chain building.
   288  	if opts.Roots == nil && runtime.GOOS == "windows" {
   289  		return c.systemVerify(&opts)
   290  	}
   291  
   292  	if opts.Roots == nil {
   293  		opts.Roots = systemRootsPool()
   294  		if opts.Roots == nil {
   295  			return nil, SystemRootsError{systemRootsErr}
   296  		}
   297  	}
   298  
   299  	err = c.isValid(leafCertificate, nil, &opts)
   300  	if err != nil {
   301  		return
   302  	}
   303  
   304  	if len(opts.DNSName) > 0 {
   305  		err = c.VerifyHostname(opts.DNSName)
   306  		if err != nil {
   307  			return
   308  		}
   309  	}
   310  
   311  	var candidateChains [][]*Certificate
   312  	if opts.Roots.contains(c) {
   313  		candidateChains = append(candidateChains, []*Certificate{c})
   314  	} else {
   315  		if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
   316  			return nil, err
   317  		}
   318  	}
   319  
   320  	keyUsages := opts.KeyUsages
   321  	if len(keyUsages) == 0 {
   322  		keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
   323  	}
   324  
   325  	// If any key usage is acceptable then we're done.
   326  	for _, usage := range keyUsages {
   327  		if usage == ExtKeyUsageAny {
   328  			chains = candidateChains
   329  			return
   330  		}
   331  	}
   332  
   333  	for _, candidate := range candidateChains {
   334  		if checkChainForKeyUsage(candidate, keyUsages) {
   335  			chains = append(chains, candidate)
   336  		}
   337  	}
   338  
   339  	if len(chains) == 0 {
   340  		err = CertificateInvalidError{c, IncompatibleUsage}
   341  	}
   342  
   343  	return
   344  }
   345  
   346  func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
   347  	n := make([]*Certificate, len(chain)+1)
   348  	copy(n, chain)
   349  	n[len(chain)] = cert
   350  	return n
   351  }
   352  
   353  func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
   354  	possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
   355  nextRoot:
   356  	for _, rootNum := range possibleRoots {
   357  		root := opts.Roots.certs[rootNum]
   358  
   359  		for _, cert := range currentChain {
   360  			if cert.Equal(root) {
   361  				continue nextRoot
   362  			}
   363  		}
   364  
   365  		err = root.isValid(rootCertificate, currentChain, opts)
   366  		if err != nil {
   367  			continue
   368  		}
   369  		chains = append(chains, appendToFreshChain(currentChain, root))
   370  	}
   371  
   372  	possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
   373  nextIntermediate:
   374  	for _, intermediateNum := range possibleIntermediates {
   375  		intermediate := opts.Intermediates.certs[intermediateNum]
   376  		for _, cert := range currentChain {
   377  			if cert.Equal(intermediate) {
   378  				continue nextIntermediate
   379  			}
   380  		}
   381  		err = intermediate.isValid(intermediateCertificate, currentChain, opts)
   382  		if err != nil {
   383  			continue
   384  		}
   385  		var childChains [][]*Certificate
   386  		childChains, ok := cache[intermediateNum]
   387  		if !ok {
   388  			childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
   389  			cache[intermediateNum] = childChains
   390  		}
   391  		chains = append(chains, childChains...)
   392  	}
   393  
   394  	if len(chains) > 0 {
   395  		err = nil
   396  	}
   397  
   398  	if len(chains) == 0 && err == nil {
   399  		hintErr := rootErr
   400  		hintCert := failedRoot
   401  		if hintErr == nil {
   402  			hintErr = intermediateErr
   403  			hintCert = failedIntermediate
   404  		}
   405  		err = UnknownAuthorityError{c, hintErr, hintCert}
   406  	}
   407  
   408  	return
   409  }
   410  
   411  func matchHostnames(pattern, host string) bool {
   412  	host = strings.TrimSuffix(host, ".")
   413  	pattern = strings.TrimSuffix(pattern, ".")
   414  
   415  	if len(pattern) == 0 || len(host) == 0 {
   416  		return false
   417  	}
   418  
   419  	patternParts := strings.Split(pattern, ".")
   420  	hostParts := strings.Split(host, ".")
   421  
   422  	if len(patternParts) != len(hostParts) {
   423  		return false
   424  	}
   425  
   426  	for i, patternPart := range patternParts {
   427  		if i == 0 && patternPart == "*" {
   428  			continue
   429  		}
   430  		if patternPart != hostParts[i] {
   431  			return false
   432  		}
   433  	}
   434  
   435  	return true
   436  }
   437  
   438  // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
   439  // an explicitly ASCII function to avoid any sharp corners resulting from
   440  // performing Unicode operations on DNS labels.
   441  func toLowerCaseASCII(in string) string {
   442  	// If the string is already lower-case then there's nothing to do.
   443  	isAlreadyLowerCase := true
   444  	for _, c := range in {
   445  		if c == utf8.RuneError {
   446  			// If we get a UTF-8 error then there might be
   447  			// upper-case ASCII bytes in the invalid sequence.
   448  			isAlreadyLowerCase = false
   449  			break
   450  		}
   451  		if 'A' <= c && c <= 'Z' {
   452  			isAlreadyLowerCase = false
   453  			break
   454  		}
   455  	}
   456  
   457  	if isAlreadyLowerCase {
   458  		return in
   459  	}
   460  
   461  	out := []byte(in)
   462  	for i, c := range out {
   463  		if 'A' <= c && c <= 'Z' {
   464  			out[i] += 'a' - 'A'
   465  		}
   466  	}
   467  	return string(out)
   468  }
   469  
   470  // VerifyHostname returns nil if c is a valid certificate for the named host.
   471  // Otherwise it returns an error describing the mismatch.
   472  func (c *Certificate) VerifyHostname(h string) error {
   473  	// IP addresses may be written in [ ].
   474  	candidateIP := h
   475  	if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
   476  		candidateIP = h[1 : len(h)-1]
   477  	}
   478  	if ip := net.ParseIP(candidateIP); ip != nil {
   479  		// We only match IP addresses against IP SANs.
   480  		// https://tools.ietf.org/html/rfc6125#appendix-B.2
   481  		for _, candidate := range c.IPAddresses {
   482  			if ip.Equal(candidate) {
   483  				return nil
   484  			}
   485  		}
   486  		return HostnameError{c, candidateIP}
   487  	}
   488  
   489  	lowered := toLowerCaseASCII(h)
   490  
   491  	if c.hasSANExtension() {
   492  		for _, match := range c.DNSNames {
   493  			if matchHostnames(toLowerCaseASCII(match), lowered) {
   494  				return nil
   495  			}
   496  		}
   497  		// If Subject Alt Name is given, we ignore the common name.
   498  	} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
   499  		return nil
   500  	}
   501  
   502  	return HostnameError{c, h}
   503  }
   504  
   505  func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
   506  	usages := make([]ExtKeyUsage, len(keyUsages))
   507  	copy(usages, keyUsages)
   508  
   509  	if len(chain) == 0 {
   510  		return false
   511  	}
   512  
   513  	usagesRemaining := len(usages)
   514  
   515  	// We walk down the list and cross out any usages that aren't supported
   516  	// by each certificate. If we cross out all the usages, then the chain
   517  	// is unacceptable.
   518  
   519  NextCert:
   520  	for i := len(chain) - 1; i >= 0; i-- {
   521  		cert := chain[i]
   522  		if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
   523  			// The certificate doesn't have any extended key usage specified.
   524  			continue
   525  		}
   526  
   527  		for _, usage := range cert.ExtKeyUsage {
   528  			if usage == ExtKeyUsageAny {
   529  				// The certificate is explicitly good for any usage.
   530  				continue NextCert
   531  			}
   532  		}
   533  
   534  		const invalidUsage ExtKeyUsage = -1
   535  
   536  	NextRequestedUsage:
   537  		for i, requestedUsage := range usages {
   538  			if requestedUsage == invalidUsage {
   539  				continue
   540  			}
   541  
   542  			for _, usage := range cert.ExtKeyUsage {
   543  				if requestedUsage == usage {
   544  					continue NextRequestedUsage
   545  				} else if requestedUsage == ExtKeyUsageServerAuth &&
   546  					(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
   547  						usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
   548  					// In order to support COMODO
   549  					// certificate chains, we have to
   550  					// accept Netscape or Microsoft SGC
   551  					// usages as equal to ServerAuth.
   552  					continue NextRequestedUsage
   553  				}
   554  			}
   555  
   556  			usages[i] = invalidUsage
   557  			usagesRemaining--
   558  			if usagesRemaining == 0 {
   559  				return false
   560  			}
   561  		}
   562  	}
   563  
   564  	return true
   565  }