| // Copyright 2011 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package x509 | 
 |  | 
 | import ( | 
 | 	"net" | 
 | 	"runtime" | 
 | 	"strings" | 
 | 	"time" | 
 | 	"unicode/utf8" | 
 | ) | 
 |  | 
 | type InvalidReason int | 
 |  | 
 | const ( | 
 | 	// NotAuthorizedToSign results when a certificate is signed by another | 
 | 	// which isn't marked as a CA certificate. | 
 | 	NotAuthorizedToSign InvalidReason = iota | 
 | 	// Expired results when a certificate has expired, based on the time | 
 | 	// given in the VerifyOptions. | 
 | 	Expired | 
 | 	// CANotAuthorizedForThisName results when an intermediate or root | 
 | 	// certificate has a name constraint which doesn't include the name | 
 | 	// being checked. | 
 | 	CANotAuthorizedForThisName | 
 | 	// TooManyIntermediates results when a path length constraint is | 
 | 	// violated. | 
 | 	TooManyIntermediates | 
 | 	// IncompatibleUsage results when the certificate's key usage indicates | 
 | 	// that it may only be used for a different purpose. | 
 | 	IncompatibleUsage | 
 | ) | 
 |  | 
 | // CertificateInvalidError results when an odd error occurs. Users of this | 
 | // library probably want to handle all these errors uniformly. | 
 | type CertificateInvalidError struct { | 
 | 	Cert   *Certificate | 
 | 	Reason InvalidReason | 
 | } | 
 |  | 
 | func (e CertificateInvalidError) Error() string { | 
 | 	switch e.Reason { | 
 | 	case NotAuthorizedToSign: | 
 | 		return "x509: certificate is not authorized to sign other certificates" | 
 | 	case Expired: | 
 | 		return "x509: certificate has expired or is not yet valid" | 
 | 	case CANotAuthorizedForThisName: | 
 | 		return "x509: a root or intermediate certificate is not authorized to sign in this domain" | 
 | 	case TooManyIntermediates: | 
 | 		return "x509: too many intermediates for path length constraint" | 
 | 	case IncompatibleUsage: | 
 | 		return "x509: certificate specifies an incompatible key usage" | 
 | 	} | 
 | 	return "x509: unknown error" | 
 | } | 
 |  | 
 | // HostnameError results when the set of authorized names doesn't match the | 
 | // requested name. | 
 | type HostnameError struct { | 
 | 	Certificate *Certificate | 
 | 	Host        string | 
 | } | 
 |  | 
 | func (h HostnameError) Error() string { | 
 | 	c := h.Certificate | 
 |  | 
 | 	var valid string | 
 | 	if ip := net.ParseIP(h.Host); ip != nil { | 
 | 		// Trying to validate an IP | 
 | 		if len(c.IPAddresses) == 0 { | 
 | 			return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" | 
 | 		} | 
 | 		for _, san := range c.IPAddresses { | 
 | 			if len(valid) > 0 { | 
 | 				valid += ", " | 
 | 			} | 
 | 			valid += san.String() | 
 | 		} | 
 | 	} else { | 
 | 		if len(c.DNSNames) > 0 { | 
 | 			valid = strings.Join(c.DNSNames, ", ") | 
 | 		} else { | 
 | 			valid = c.Subject.CommonName | 
 | 		} | 
 | 	} | 
 | 	return "x509: certificate is valid for " + valid + ", not " + h.Host | 
 | } | 
 |  | 
 | // UnknownAuthorityError results when the certificate issuer is unknown | 
 | type UnknownAuthorityError struct { | 
 | 	cert *Certificate | 
 | } | 
 |  | 
 | func (e UnknownAuthorityError) Error() string { | 
 | 	return "x509: certificate signed by unknown authority" | 
 | } | 
 |  | 
 | // SystemRootsError results when we fail to load the system root certificates. | 
 | type SystemRootsError struct { | 
 | } | 
 |  | 
 | func (e SystemRootsError) Error() string { | 
 | 	return "x509: failed to load system roots and no roots provided" | 
 | } | 
 |  | 
 | // VerifyOptions contains parameters for Certificate.Verify. It's a structure | 
 | // because other PKIX verification APIs have ended up needing many options. | 
 | type VerifyOptions struct { | 
 | 	DNSName       string | 
 | 	Intermediates *CertPool | 
 | 	Roots         *CertPool // if nil, the system roots are used | 
 | 	CurrentTime   time.Time // if zero, the current time is used | 
 | 	// KeyUsage specifies which Extended Key Usage values are acceptable. | 
 | 	// An empty list means ExtKeyUsageServerAuth. Key usage is considered a | 
 | 	// constraint down the chain which mirrors Windows CryptoAPI behaviour, | 
 | 	// but not the spec. To accept any key usage, include ExtKeyUsageAny. | 
 | 	KeyUsages []ExtKeyUsage | 
 | } | 
 |  | 
 | const ( | 
 | 	leafCertificate = iota | 
 | 	intermediateCertificate | 
 | 	rootCertificate | 
 | ) | 
 |  | 
 | // isValid performs validity checks on the c. | 
 | func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { | 
 | 	now := opts.CurrentTime | 
 | 	if now.IsZero() { | 
 | 		now = time.Now() | 
 | 	} | 
 | 	if now.Before(c.NotBefore) || now.After(c.NotAfter) { | 
 | 		return CertificateInvalidError{c, Expired} | 
 | 	} | 
 |  | 
 | 	if len(c.PermittedDNSDomains) > 0 { | 
 | 		for _, domain := range c.PermittedDNSDomains { | 
 | 			if opts.DNSName == domain || | 
 | 				(strings.HasSuffix(opts.DNSName, domain) && | 
 | 					len(opts.DNSName) >= 1+len(domain) && | 
 | 					opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') { | 
 | 				continue | 
 | 			} | 
 |  | 
 | 			return CertificateInvalidError{c, CANotAuthorizedForThisName} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// KeyUsage status flags are ignored. From Engineering Security, Peter | 
 | 	// Gutmann: A European government CA marked its signing certificates as | 
 | 	// being valid for encryption only, but no-one noticed. Another | 
 | 	// European CA marked its signature keys as not being valid for | 
 | 	// signatures. A different CA marked its own trusted root certificate | 
 | 	// as being invalid for certificate signing.  Another national CA | 
 | 	// distributed a certificate to be used to encrypt data for the | 
 | 	// country’s tax authority that was marked as only being usable for | 
 | 	// digital signatures but not for encryption. Yet another CA reversed | 
 | 	// the order of the bit flags in the keyUsage due to confusion over | 
 | 	// encoding endianness, essentially setting a random keyUsage in | 
 | 	// certificates that it issued. Another CA created a self-invalidating | 
 | 	// certificate by adding a certificate policy statement stipulating | 
 | 	// that the certificate had to be used strictly as specified in the | 
 | 	// keyUsage, and a keyUsage containing a flag indicating that the RSA | 
 | 	// encryption key could only be used for Diffie-Hellman key agreement. | 
 |  | 
 | 	if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) { | 
 | 		return CertificateInvalidError{c, NotAuthorizedToSign} | 
 | 	} | 
 |  | 
 | 	if c.BasicConstraintsValid && c.MaxPathLen >= 0 { | 
 | 		numIntermediates := len(currentChain) - 1 | 
 | 		if numIntermediates > c.MaxPathLen { | 
 | 			return CertificateInvalidError{c, TooManyIntermediates} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return nil | 
 | } | 
 |  | 
 | // Verify attempts to verify c by building one or more chains from c to a | 
 | // certificate in opts.Roots, using certificates in opts.Intermediates if | 
 | // needed. If successful, it returns one or more chains where the first | 
 | // element of the chain is c and the last element is from opts.Roots. | 
 | // | 
 | // WARNING: this doesn't do any revocation checking. | 
 | func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { | 
 | 	// Use Windows's own verification and chain building. | 
 | 	if opts.Roots == nil && runtime.GOOS == "windows" { | 
 | 		return c.systemVerify(&opts) | 
 | 	} | 
 |  | 
 | 	if opts.Roots == nil { | 
 | 		opts.Roots = systemRootsPool() | 
 | 		if opts.Roots == nil { | 
 | 			return nil, SystemRootsError{} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	err = c.isValid(leafCertificate, nil, &opts) | 
 | 	if err != nil { | 
 | 		return | 
 | 	} | 
 |  | 
 | 	if len(opts.DNSName) > 0 { | 
 | 		err = c.VerifyHostname(opts.DNSName) | 
 | 		if err != nil { | 
 | 			return | 
 | 		} | 
 | 	} | 
 |  | 
 | 	candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts) | 
 | 	if err != nil { | 
 | 		return | 
 | 	} | 
 |  | 
 | 	keyUsages := opts.KeyUsages | 
 | 	if len(keyUsages) == 0 { | 
 | 		keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} | 
 | 	} | 
 |  | 
 | 	// If any key usage is acceptable then we're done. | 
 | 	for _, usage := range keyUsages { | 
 | 		if usage == ExtKeyUsageAny { | 
 | 			chains = candidateChains | 
 | 			return | 
 | 		} | 
 | 	} | 
 |  | 
 | 	for _, candidate := range candidateChains { | 
 | 		if checkChainForKeyUsage(candidate, keyUsages) { | 
 | 			chains = append(chains, candidate) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if len(chains) == 0 { | 
 | 		err = CertificateInvalidError{c, IncompatibleUsage} | 
 | 	} | 
 |  | 
 | 	return | 
 | } | 
 |  | 
 | func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { | 
 | 	n := make([]*Certificate, len(chain)+1) | 
 | 	copy(n, chain) | 
 | 	n[len(chain)] = cert | 
 | 	return n | 
 | } | 
 |  | 
 | func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) { | 
 | 	for _, rootNum := range opts.Roots.findVerifiedParents(c) { | 
 | 		root := opts.Roots.certs[rootNum] | 
 | 		err = root.isValid(rootCertificate, currentChain, opts) | 
 | 		if err != nil { | 
 | 			continue | 
 | 		} | 
 | 		chains = append(chains, appendToFreshChain(currentChain, root)) | 
 | 	} | 
 |  | 
 | nextIntermediate: | 
 | 	for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) { | 
 | 		intermediate := opts.Intermediates.certs[intermediateNum] | 
 | 		for _, cert := range currentChain { | 
 | 			if cert == intermediate { | 
 | 				continue nextIntermediate | 
 | 			} | 
 | 		} | 
 | 		err = intermediate.isValid(intermediateCertificate, currentChain, opts) | 
 | 		if err != nil { | 
 | 			continue | 
 | 		} | 
 | 		var childChains [][]*Certificate | 
 | 		childChains, ok := cache[intermediateNum] | 
 | 		if !ok { | 
 | 			childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts) | 
 | 			cache[intermediateNum] = childChains | 
 | 		} | 
 | 		chains = append(chains, childChains...) | 
 | 	} | 
 |  | 
 | 	if len(chains) > 0 { | 
 | 		err = nil | 
 | 	} | 
 |  | 
 | 	if len(chains) == 0 && err == nil { | 
 | 		err = UnknownAuthorityError{c} | 
 | 	} | 
 |  | 
 | 	return | 
 | } | 
 |  | 
 | func matchHostnames(pattern, host string) bool { | 
 | 	if len(pattern) == 0 || len(host) == 0 { | 
 | 		return false | 
 | 	} | 
 |  | 
 | 	patternParts := strings.Split(pattern, ".") | 
 | 	hostParts := strings.Split(host, ".") | 
 |  | 
 | 	if len(patternParts) != len(hostParts) { | 
 | 		return false | 
 | 	} | 
 |  | 
 | 	for i, patternPart := range patternParts { | 
 | 		if patternPart == "*" { | 
 | 			continue | 
 | 		} | 
 | 		if patternPart != hostParts[i] { | 
 | 			return false | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return true | 
 | } | 
 |  | 
 | // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use | 
 | // an explicitly ASCII function to avoid any sharp corners resulting from | 
 | // performing Unicode operations on DNS labels. | 
 | func toLowerCaseASCII(in string) string { | 
 | 	// If the string is already lower-case then there's nothing to do. | 
 | 	isAlreadyLowerCase := true | 
 | 	for _, c := range in { | 
 | 		if c == utf8.RuneError { | 
 | 			// If we get a UTF-8 error then there might be | 
 | 			// upper-case ASCII bytes in the invalid sequence. | 
 | 			isAlreadyLowerCase = false | 
 | 			break | 
 | 		} | 
 | 		if 'A' <= c && c <= 'Z' { | 
 | 			isAlreadyLowerCase = false | 
 | 			break | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if isAlreadyLowerCase { | 
 | 		return in | 
 | 	} | 
 |  | 
 | 	out := []byte(in) | 
 | 	for i, c := range out { | 
 | 		if 'A' <= c && c <= 'Z' { | 
 | 			out[i] += 'a' - 'A' | 
 | 		} | 
 | 	} | 
 | 	return string(out) | 
 | } | 
 |  | 
 | // VerifyHostname returns nil if c is a valid certificate for the named host. | 
 | // Otherwise it returns an error describing the mismatch. | 
 | func (c *Certificate) VerifyHostname(h string) error { | 
 | 	// IP addresses may be written in [ ]. | 
 | 	candidateIP := h | 
 | 	if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { | 
 | 		candidateIP = h[1 : len(h)-1] | 
 | 	} | 
 | 	if ip := net.ParseIP(candidateIP); ip != nil { | 
 | 		// We only match IP addresses against IP SANs. | 
 | 		// https://tools.ietf.org/html/rfc6125#appendix-B.2 | 
 | 		for _, candidate := range c.IPAddresses { | 
 | 			if ip.Equal(candidate) { | 
 | 				return nil | 
 | 			} | 
 | 		} | 
 | 		return HostnameError{c, candidateIP} | 
 | 	} | 
 |  | 
 | 	lowered := toLowerCaseASCII(h) | 
 |  | 
 | 	if len(c.DNSNames) > 0 { | 
 | 		for _, match := range c.DNSNames { | 
 | 			if matchHostnames(toLowerCaseASCII(match), lowered) { | 
 | 				return nil | 
 | 			} | 
 | 		} | 
 | 		// If Subject Alt Name is given, we ignore the common name. | 
 | 	} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	return HostnameError{c, h} | 
 | } | 
 |  | 
 | func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { | 
 | 	usages := make([]ExtKeyUsage, len(keyUsages)) | 
 | 	copy(usages, keyUsages) | 
 |  | 
 | 	if len(chain) == 0 { | 
 | 		return false | 
 | 	} | 
 |  | 
 | 	usagesRemaining := len(usages) | 
 |  | 
 | 	// We walk down the list and cross out any usages that aren't supported | 
 | 	// by each certificate. If we cross out all the usages, then the chain | 
 | 	// is unacceptable. | 
 |  | 
 | 	for i := len(chain) - 1; i >= 0; i-- { | 
 | 		cert := chain[i] | 
 | 		if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { | 
 | 			// The certificate doesn't have any extended key usage specified. | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		for _, usage := range cert.ExtKeyUsage { | 
 | 			if usage == ExtKeyUsageAny { | 
 | 				// The certificate is explicitly good for any usage. | 
 | 				continue | 
 | 			} | 
 | 		} | 
 |  | 
 | 		const invalidUsage ExtKeyUsage = -1 | 
 |  | 
 | 	NextRequestedUsage: | 
 | 		for i, requestedUsage := range usages { | 
 | 			if requestedUsage == invalidUsage { | 
 | 				continue | 
 | 			} | 
 |  | 
 | 			for _, usage := range cert.ExtKeyUsage { | 
 | 				if requestedUsage == usage { | 
 | 					continue NextRequestedUsage | 
 | 				} else if requestedUsage == ExtKeyUsageServerAuth && | 
 | 					(usage == ExtKeyUsageNetscapeServerGatedCrypto || | 
 | 						usage == ExtKeyUsageMicrosoftServerGatedCrypto) { | 
 | 					// In order to support COMODO | 
 | 					// certificate chains, we have to | 
 | 					// accept Netscape or Microsoft SGC | 
 | 					// usages as equal to ServerAuth. | 
 | 					continue NextRequestedUsage | 
 | 				} | 
 | 			} | 
 |  | 
 | 			usages[i] = invalidUsage | 
 | 			usagesRemaining-- | 
 | 			if usagesRemaining == 0 { | 
 | 				return false | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return true | 
 | } |