Fix bootstrap/PR63632
[official-gcc.git] / libgo / go / crypto / x509 / verify.go
blob5fd8e371747d85dc6fb2fb838b8e8e3b17f763b7
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.
5 package x509
7 import (
8 "fmt"
9 "net"
10 "runtime"
11 "strings"
12 "time"
13 "unicode/utf8"
16 type InvalidReason int
18 const (
19 // NotAuthorizedToSign results when a certificate is signed by another
20 // which isn't marked as a CA certificate.
21 NotAuthorizedToSign InvalidReason = iota
22 // Expired results when a certificate has expired, based on the time
23 // given in the VerifyOptions.
24 Expired
25 // CANotAuthorizedForThisName results when an intermediate or root
26 // certificate has a name constraint which doesn't include the name
27 // being checked.
28 CANotAuthorizedForThisName
29 // TooManyIntermediates results when a path length constraint is
30 // violated.
31 TooManyIntermediates
32 // IncompatibleUsage results when the certificate's key usage indicates
33 // that it may only be used for a different purpose.
34 IncompatibleUsage
37 // CertificateInvalidError results when an odd error occurs. Users of this
38 // library probably want to handle all these errors uniformly.
39 type CertificateInvalidError struct {
40 Cert *Certificate
41 Reason InvalidReason
44 func (e CertificateInvalidError) Error() string {
45 switch e.Reason {
46 case NotAuthorizedToSign:
47 return "x509: certificate is not authorized to sign other certificates"
48 case Expired:
49 return "x509: certificate has expired or is not yet valid"
50 case CANotAuthorizedForThisName:
51 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
52 case TooManyIntermediates:
53 return "x509: too many intermediates for path length constraint"
54 case IncompatibleUsage:
55 return "x509: certificate specifies an incompatible key usage"
57 return "x509: unknown error"
60 // HostnameError results when the set of authorized names doesn't match the
61 // requested name.
62 type HostnameError struct {
63 Certificate *Certificate
64 Host string
67 func (h HostnameError) Error() string {
68 c := h.Certificate
70 var valid string
71 if ip := net.ParseIP(h.Host); ip != nil {
72 // Trying to validate an IP
73 if len(c.IPAddresses) == 0 {
74 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
76 for _, san := range c.IPAddresses {
77 if len(valid) > 0 {
78 valid += ", "
80 valid += san.String()
82 } else {
83 if len(c.DNSNames) > 0 {
84 valid = strings.Join(c.DNSNames, ", ")
85 } else {
86 valid = c.Subject.CommonName
89 return "x509: certificate is valid for " + valid + ", not " + h.Host
92 // UnknownAuthorityError results when the certificate issuer is unknown
93 type UnknownAuthorityError struct {
94 cert *Certificate
95 // hintErr contains an error that may be helpful in determining why an
96 // authority wasn't found.
97 hintErr error
98 // hintCert contains a possible authority certificate that was rejected
99 // because of the error in hintErr.
100 hintCert *Certificate
103 func (e UnknownAuthorityError) Error() string {
104 s := "x509: certificate signed by unknown authority"
105 if e.hintErr != nil {
106 certName := e.hintCert.Subject.CommonName
107 if len(certName) == 0 {
108 if len(e.hintCert.Subject.Organization) > 0 {
109 certName = e.hintCert.Subject.Organization[0]
111 certName = "serial:" + e.hintCert.SerialNumber.String()
113 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
115 return s
118 // SystemRootsError results when we fail to load the system root certificates.
119 type SystemRootsError struct {
122 func (e SystemRootsError) Error() string {
123 return "x509: failed to load system roots and no roots provided"
126 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
127 // because other PKIX verification APIs have ended up needing many options.
128 type VerifyOptions struct {
129 DNSName string
130 Intermediates *CertPool
131 Roots *CertPool // if nil, the system roots are used
132 CurrentTime time.Time // if zero, the current time is used
133 // KeyUsage specifies which Extended Key Usage values are acceptable.
134 // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
135 // constraint down the chain which mirrors Windows CryptoAPI behaviour,
136 // but not the spec. To accept any key usage, include ExtKeyUsageAny.
137 KeyUsages []ExtKeyUsage
140 const (
141 leafCertificate = iota
142 intermediateCertificate
143 rootCertificate
146 // isValid performs validity checks on the c.
147 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
148 now := opts.CurrentTime
149 if now.IsZero() {
150 now = time.Now()
152 if now.Before(c.NotBefore) || now.After(c.NotAfter) {
153 return CertificateInvalidError{c, Expired}
156 if len(c.PermittedDNSDomains) > 0 {
157 ok := false
158 for _, domain := range c.PermittedDNSDomains {
159 if opts.DNSName == domain ||
160 (strings.HasSuffix(opts.DNSName, domain) &&
161 len(opts.DNSName) >= 1+len(domain) &&
162 opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
163 ok = true
164 break
168 if !ok {
169 return CertificateInvalidError{c, CANotAuthorizedForThisName}
173 // KeyUsage status flags are ignored. From Engineering Security, Peter
174 // Gutmann: A European government CA marked its signing certificates as
175 // being valid for encryption only, but no-one noticed. Another
176 // European CA marked its signature keys as not being valid for
177 // signatures. A different CA marked its own trusted root certificate
178 // as being invalid for certificate signing. Another national CA
179 // distributed a certificate to be used to encrypt data for the
180 // country’s tax authority that was marked as only being usable for
181 // digital signatures but not for encryption. Yet another CA reversed
182 // the order of the bit flags in the keyUsage due to confusion over
183 // encoding endianness, essentially setting a random keyUsage in
184 // certificates that it issued. Another CA created a self-invalidating
185 // certificate by adding a certificate policy statement stipulating
186 // that the certificate had to be used strictly as specified in the
187 // keyUsage, and a keyUsage containing a flag indicating that the RSA
188 // encryption key could only be used for Diffie-Hellman key agreement.
190 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
191 return CertificateInvalidError{c, NotAuthorizedToSign}
194 if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
195 numIntermediates := len(currentChain) - 1
196 if numIntermediates > c.MaxPathLen {
197 return CertificateInvalidError{c, TooManyIntermediates}
201 return nil
204 // Verify attempts to verify c by building one or more chains from c to a
205 // certificate in opts.Roots, using certificates in opts.Intermediates if
206 // needed. If successful, it returns one or more chains where the first
207 // element of the chain is c and the last element is from opts.Roots.
209 // WARNING: this doesn't do any revocation checking.
210 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
211 // Use Windows's own verification and chain building.
212 if opts.Roots == nil && runtime.GOOS == "windows" {
213 return c.systemVerify(&opts)
216 if opts.Roots == nil {
217 opts.Roots = systemRootsPool()
218 if opts.Roots == nil {
219 return nil, SystemRootsError{}
223 err = c.isValid(leafCertificate, nil, &opts)
224 if err != nil {
225 return
228 if len(opts.DNSName) > 0 {
229 err = c.VerifyHostname(opts.DNSName)
230 if err != nil {
231 return
235 candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
236 if err != nil {
237 return
240 keyUsages := opts.KeyUsages
241 if len(keyUsages) == 0 {
242 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
245 // If any key usage is acceptable then we're done.
246 for _, usage := range keyUsages {
247 if usage == ExtKeyUsageAny {
248 chains = candidateChains
249 return
253 for _, candidate := range candidateChains {
254 if checkChainForKeyUsage(candidate, keyUsages) {
255 chains = append(chains, candidate)
259 if len(chains) == 0 {
260 err = CertificateInvalidError{c, IncompatibleUsage}
263 return
266 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
267 n := make([]*Certificate, len(chain)+1)
268 copy(n, chain)
269 n[len(chain)] = cert
270 return n
273 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
274 possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
275 for _, rootNum := range possibleRoots {
276 root := opts.Roots.certs[rootNum]
277 err = root.isValid(rootCertificate, currentChain, opts)
278 if err != nil {
279 continue
281 chains = append(chains, appendToFreshChain(currentChain, root))
284 possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
285 nextIntermediate:
286 for _, intermediateNum := range possibleIntermediates {
287 intermediate := opts.Intermediates.certs[intermediateNum]
288 for _, cert := range currentChain {
289 if cert == intermediate {
290 continue nextIntermediate
293 err = intermediate.isValid(intermediateCertificate, currentChain, opts)
294 if err != nil {
295 continue
297 var childChains [][]*Certificate
298 childChains, ok := cache[intermediateNum]
299 if !ok {
300 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
301 cache[intermediateNum] = childChains
303 chains = append(chains, childChains...)
306 if len(chains) > 0 {
307 err = nil
310 if len(chains) == 0 && err == nil {
311 hintErr := rootErr
312 hintCert := failedRoot
313 if hintErr == nil {
314 hintErr = intermediateErr
315 hintCert = failedIntermediate
317 err = UnknownAuthorityError{c, hintErr, hintCert}
320 return
323 func matchHostnames(pattern, host string) bool {
324 if len(pattern) == 0 || len(host) == 0 {
325 return false
328 patternParts := strings.Split(pattern, ".")
329 hostParts := strings.Split(host, ".")
331 if len(patternParts) != len(hostParts) {
332 return false
335 for i, patternPart := range patternParts {
336 if patternPart == "*" {
337 continue
339 if patternPart != hostParts[i] {
340 return false
344 return true
347 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
348 // an explicitly ASCII function to avoid any sharp corners resulting from
349 // performing Unicode operations on DNS labels.
350 func toLowerCaseASCII(in string) string {
351 // If the string is already lower-case then there's nothing to do.
352 isAlreadyLowerCase := true
353 for _, c := range in {
354 if c == utf8.RuneError {
355 // If we get a UTF-8 error then there might be
356 // upper-case ASCII bytes in the invalid sequence.
357 isAlreadyLowerCase = false
358 break
360 if 'A' <= c && c <= 'Z' {
361 isAlreadyLowerCase = false
362 break
366 if isAlreadyLowerCase {
367 return in
370 out := []byte(in)
371 for i, c := range out {
372 if 'A' <= c && c <= 'Z' {
373 out[i] += 'a' - 'A'
376 return string(out)
379 // VerifyHostname returns nil if c is a valid certificate for the named host.
380 // Otherwise it returns an error describing the mismatch.
381 func (c *Certificate) VerifyHostname(h string) error {
382 // IP addresses may be written in [ ].
383 candidateIP := h
384 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
385 candidateIP = h[1 : len(h)-1]
387 if ip := net.ParseIP(candidateIP); ip != nil {
388 // We only match IP addresses against IP SANs.
389 // https://tools.ietf.org/html/rfc6125#appendix-B.2
390 for _, candidate := range c.IPAddresses {
391 if ip.Equal(candidate) {
392 return nil
395 return HostnameError{c, candidateIP}
398 lowered := toLowerCaseASCII(h)
400 if len(c.DNSNames) > 0 {
401 for _, match := range c.DNSNames {
402 if matchHostnames(toLowerCaseASCII(match), lowered) {
403 return nil
406 // If Subject Alt Name is given, we ignore the common name.
407 } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
408 return nil
411 return HostnameError{c, h}
414 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
415 usages := make([]ExtKeyUsage, len(keyUsages))
416 copy(usages, keyUsages)
418 if len(chain) == 0 {
419 return false
422 usagesRemaining := len(usages)
424 // We walk down the list and cross out any usages that aren't supported
425 // by each certificate. If we cross out all the usages, then the chain
426 // is unacceptable.
428 NextCert:
429 for i := len(chain) - 1; i >= 0; i-- {
430 cert := chain[i]
431 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
432 // The certificate doesn't have any extended key usage specified.
433 continue
436 for _, usage := range cert.ExtKeyUsage {
437 if usage == ExtKeyUsageAny {
438 // The certificate is explicitly good for any usage.
439 continue NextCert
443 const invalidUsage ExtKeyUsage = -1
445 NextRequestedUsage:
446 for i, requestedUsage := range usages {
447 if requestedUsage == invalidUsage {
448 continue
451 for _, usage := range cert.ExtKeyUsage {
452 if requestedUsage == usage {
453 continue NextRequestedUsage
454 } else if requestedUsage == ExtKeyUsageServerAuth &&
455 (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
456 usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
457 // In order to support COMODO
458 // certificate chains, we have to
459 // accept Netscape or Microsoft SGC
460 // usages as equal to ServerAuth.
461 continue NextRequestedUsage
465 usages[i] = invalidUsage
466 usagesRemaining--
467 if usagesRemaining == 0 {
468 return false
473 return true