github.com/Hyperledger-TWGC/tjfoc-gm@v1.4.0/x509/verify.go (about)

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