src/pkg/crypto/x509/verify.go - The Go Programming Language

Golang

Source file src/pkg/crypto/x509/verify.go

     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		"runtime"
     9		"strings"
    10		"time"
    11		"unicode/utf8"
    12	)
    13	
    14	type InvalidReason int
    15	
    16	const (
    17		// NotAuthorizedToSign results when a certificate is signed by another
    18		// which isn't marked as a CA certificate.
    19		NotAuthorizedToSign InvalidReason = iota
    20		// Expired results when a certificate has expired, based on the time
    21		// given in the VerifyOptions.
    22		Expired
    23		// CANotAuthorizedForThisName results when an intermediate or root
    24		// certificate has a name constraint which doesn't include the name
    25		// being checked.
    26		CANotAuthorizedForThisName
    27		// TooManyIntermediates results when a path length constraint is
    28		// violated.
    29		TooManyIntermediates
    30	)
    31	
    32	// CertificateInvalidError results when an odd error occurs. Users of this
    33	// library probably want to handle all these errors uniformly.
    34	type CertificateInvalidError struct {
    35		Cert   *Certificate
    36		Reason InvalidReason
    37	}
    38	
    39	func (e CertificateInvalidError) Error() string {
    40		switch e.Reason {
    41		case NotAuthorizedToSign:
    42			return "x509: certificate is not authorized to sign other other certificates"
    43		case Expired:
    44			return "x509: certificate has expired or is not yet valid"
    45		case CANotAuthorizedForThisName:
    46			return "x509: a root or intermediate certificate is not authorized to sign in this domain"
    47		case TooManyIntermediates:
    48			return "x509: too many intermediates for path length constraint"
    49		}
    50		return "x509: unknown error"
    51	}
    52	
    53	// HostnameError results when the set of authorized names doesn't match the
    54	// requested name.
    55	type HostnameError struct {
    56		Certificate *Certificate
    57		Host        string
    58	}
    59	
    60	func (h HostnameError) Error() string {
    61		var valid string
    62		c := h.Certificate
    63		if len(c.DNSNames) > 0 {
    64			valid = strings.Join(c.DNSNames, ", ")
    65		} else {
    66			valid = c.Subject.CommonName
    67		}
    68		return "certificate is valid for " + valid + ", not " + h.Host
    69	}
    70	
    71	// UnknownAuthorityError results when the certificate issuer is unknown
    72	type UnknownAuthorityError struct {
    73		cert *Certificate
    74	}
    75	
    76	func (e UnknownAuthorityError) Error() string {
    77		return "x509: certificate signed by unknown authority"
    78	}
    79	
    80	// VerifyOptions contains parameters for Certificate.Verify. It's a structure
    81	// because other PKIX verification APIs have ended up needing many options.
    82	type VerifyOptions struct {
    83		DNSName       string
    84		Intermediates *CertPool
    85		Roots         *CertPool // if nil, the system roots are used
    86		CurrentTime   time.Time // if zero, the current time is used
    87	}
    88	
    89	const (
    90		leafCertificate = iota
    91		intermediateCertificate
    92		rootCertificate
    93	)
    94	
    95	// isValid performs validity checks on the c.
    96	func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
    97		now := opts.CurrentTime
    98		if now.IsZero() {
    99			now = time.Now()
   100		}
   101		if now.Before(c.NotBefore) || now.After(c.NotAfter) {
   102			return CertificateInvalidError{c, Expired}
   103		}
   104	
   105		if len(c.PermittedDNSDomains) > 0 {
   106			for _, domain := range c.PermittedDNSDomains {
   107				if opts.DNSName == domain ||
   108					(strings.HasSuffix(opts.DNSName, domain) &&
   109						len(opts.DNSName) >= 1+len(domain) &&
   110						opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
   111					continue
   112				}
   113	
   114				return CertificateInvalidError{c, CANotAuthorizedForThisName}
   115			}
   116		}
   117	
   118		// KeyUsage status flags are ignored. From Engineering Security, Peter
   119		// Gutmann: A European government CA marked its signing certificates as
   120		// being valid for encryption only, but no-one noticed. Another
   121		// European CA marked its signature keys as not being valid for
   122		// signatures. A different CA marked its own trusted root certificate
   123		// as being invalid for certificate signing.  Another national CA
   124		// distributed a certificate to be used to encrypt data for the
   125		// country’s tax authority that was marked as only being usable for
   126		// digital signatures but not for encryption. Yet another CA reversed
   127		// the order of the bit flags in the keyUsage due to confusion over
   128		// encoding endianness, essentially setting a random keyUsage in
   129		// certificates that it issued. Another CA created a self-invalidating
   130		// certificate by adding a certificate policy statement stipulating
   131		// that the certificate had to be used strictly as specified in the
   132		// keyUsage, and a keyUsage containing a flag indicating that the RSA
   133		// encryption key could only be used for Diffie-Hellman key agreement.
   134	
   135		if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
   136			return CertificateInvalidError{c, NotAuthorizedToSign}
   137		}
   138	
   139		if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
   140			numIntermediates := len(currentChain) - 1
   141			if numIntermediates > c.MaxPathLen {
   142				return CertificateInvalidError{c, TooManyIntermediates}
   143			}
   144		}
   145	
   146		return nil
   147	}
   148	
   149	// Verify attempts to verify c by building one or more chains from c to a
   150	// certificate in opts.Roots, using certificates in opts.Intermediates if
   151	// needed. If successful, it returns one or more chains where the first
   152	// element of the chain is c and the last element is from opts.Roots.
   153	//
   154	// WARNING: this doesn't do any revocation checking.
   155	func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
   156		// Use Windows's own verification and chain building.
   157		if opts.Roots == nil && runtime.GOOS == "windows" {
   158			return c.systemVerify(&opts)
   159		}
   160	
   161		if opts.Roots == nil {
   162			opts.Roots = systemRootsPool()
   163		}
   164	
   165		err = c.isValid(leafCertificate, nil, &opts)
   166		if err != nil {
   167			return
   168		}
   169	
   170		if len(opts.DNSName) > 0 {
   171			err = c.VerifyHostname(opts.DNSName)
   172			if err != nil {
   173				return
   174			}
   175		}
   176	
   177		return c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
   178	}
   179	
   180	func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
   181		n := make([]*Certificate, len(chain)+1)
   182		copy(n, chain)
   183		n[len(chain)] = cert
   184		return n
   185	}
   186	
   187	func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
   188		for _, rootNum := range opts.Roots.findVerifiedParents(c) {
   189			root := opts.Roots.certs[rootNum]
   190			err = root.isValid(rootCertificate, currentChain, opts)
   191			if err != nil {
   192				continue
   193			}
   194			chains = append(chains, appendToFreshChain(currentChain, root))
   195		}
   196	
   197	nextIntermediate:
   198		for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) {
   199			intermediate := opts.Intermediates.certs[intermediateNum]
   200			for _, cert := range currentChain {
   201				if cert == intermediate {
   202					continue nextIntermediate
   203				}
   204			}
   205			err = intermediate.isValid(intermediateCertificate, currentChain, opts)
   206			if err != nil {
   207				continue
   208			}
   209			var childChains [][]*Certificate
   210			childChains, ok := cache[intermediateNum]
   211			if !ok {
   212				childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
   213				cache[intermediateNum] = childChains
   214			}
   215			chains = append(chains, childChains...)
   216		}
   217	
   218		if len(chains) > 0 {
   219			err = nil
   220		}
   221	
   222		if len(chains) == 0 && err == nil {
   223			err = UnknownAuthorityError{c}
   224		}
   225	
   226		return
   227	}
   228	
   229	func matchHostnames(pattern, host string) bool {
   230		if len(pattern) == 0 || len(host) == 0 {
   231			return false
   232		}
   233	
   234		patternParts := strings.Split(pattern, ".")
   235		hostParts := strings.Split(host, ".")
   236	
   237		if len(patternParts) != len(hostParts) {
   238			return false
   239		}
   240	
   241		for i, patternPart := range patternParts {
   242			if patternPart == "*" {
   243				continue
   244			}
   245			if patternPart != hostParts[i] {
   246				return false
   247			}
   248		}
   249	
   250		return true
   251	}
   252	
   253	// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
   254	// an explicitly ASCII function to avoid any sharp corners resulting from
   255	// performing Unicode operations on DNS labels.
   256	func toLowerCaseASCII(in string) string {
   257		// If the string is already lower-case then there's nothing to do.
   258		isAlreadyLowerCase := true
   259		for _, c := range in {
   260			if c == utf8.RuneError {
   261				// If we get a UTF-8 error then there might be
   262				// upper-case ASCII bytes in the invalid sequence.
   263				isAlreadyLowerCase = false
   264				break
   265			}
   266			if 'A' <= c && c <= 'Z' {
   267				isAlreadyLowerCase = false
   268				break
   269			}
   270		}
   271	
   272		if isAlreadyLowerCase {
   273			return in
   274		}
   275	
   276		out := []byte(in)
   277		for i, c := range out {
   278			if 'A' <= c && c <= 'Z' {
   279				out[i] += 'a' - 'A'
   280			}
   281		}
   282		return string(out)
   283	}
   284	
   285	// VerifyHostname returns nil if c is a valid certificate for the named host.
   286	// Otherwise it returns an error describing the mismatch.
   287	func (c *Certificate) VerifyHostname(h string) error {
   288		lowered := toLowerCaseASCII(h)
   289	
   290		if len(c.DNSNames) > 0 {
   291			for _, match := range c.DNSNames {
   292				if matchHostnames(toLowerCaseASCII(match), lowered) {
   293					return nil
   294				}
   295			}
   296			// If Subject Alt Name is given, we ignore the common name.
   297		} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
   298			return nil
   299		}
   300	
   301		return HostnameError{c, h}
   302	}