* gcc.dg/guality/guality.exp: Skip on AIX.
[official-gcc.git] / libgo / go / crypto / x509 / verify.go
blobb29ddbc80f0377cc434ea29c0f08c5cc68910041
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 "net"
9 "runtime"
10 "strings"
11 "time"
12 "unicode/utf8"
15 type InvalidReason int
17 const (
18 // NotAuthorizedToSign results when a certificate is signed by another
19 // which isn't marked as a CA certificate.
20 NotAuthorizedToSign InvalidReason = iota
21 // Expired results when a certificate has expired, based on the time
22 // given in the VerifyOptions.
23 Expired
24 // CANotAuthorizedForThisName results when an intermediate or root
25 // certificate has a name constraint which doesn't include the name
26 // being checked.
27 CANotAuthorizedForThisName
28 // TooManyIntermediates results when a path length constraint is
29 // violated.
30 TooManyIntermediates
31 // IncompatibleUsage results when the certificate's key usage indicates
32 // that it may only be used for a different purpose.
33 IncompatibleUsage
36 // CertificateInvalidError results when an odd error occurs. Users of this
37 // library probably want to handle all these errors uniformly.
38 type CertificateInvalidError struct {
39 Cert *Certificate
40 Reason InvalidReason
43 func (e CertificateInvalidError) Error() string {
44 switch e.Reason {
45 case NotAuthorizedToSign:
46 return "x509: certificate is not authorized to sign other certificates"
47 case Expired:
48 return "x509: certificate has expired or is not yet valid"
49 case CANotAuthorizedForThisName:
50 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
51 case TooManyIntermediates:
52 return "x509: too many intermediates for path length constraint"
53 case IncompatibleUsage:
54 return "x509: certificate specifies an incompatible key usage"
56 return "x509: unknown error"
59 // HostnameError results when the set of authorized names doesn't match the
60 // requested name.
61 type HostnameError struct {
62 Certificate *Certificate
63 Host string
66 func (h HostnameError) Error() string {
67 c := h.Certificate
69 var valid string
70 if ip := net.ParseIP(h.Host); ip != nil {
71 // Trying to validate an IP
72 if len(c.IPAddresses) == 0 {
73 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
75 for _, san := range c.IPAddresses {
76 if len(valid) > 0 {
77 valid += ", "
79 valid += san.String()
81 } else {
82 if len(c.DNSNames) > 0 {
83 valid = strings.Join(c.DNSNames, ", ")
84 } else {
85 valid = c.Subject.CommonName
88 return "x509: certificate is valid for " + valid + ", not " + h.Host
91 // UnknownAuthorityError results when the certificate issuer is unknown
92 type UnknownAuthorityError struct {
93 cert *Certificate
96 func (e UnknownAuthorityError) Error() string {
97 return "x509: certificate signed by unknown authority"
100 // SystemRootsError results when we fail to load the system root certificates.
101 type SystemRootsError struct {
104 func (e SystemRootsError) Error() string {
105 return "x509: failed to load system roots and no roots provided"
108 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
109 // because other PKIX verification APIs have ended up needing many options.
110 type VerifyOptions struct {
111 DNSName string
112 Intermediates *CertPool
113 Roots *CertPool // if nil, the system roots are used
114 CurrentTime time.Time // if zero, the current time is used
115 // KeyUsage specifies which Extended Key Usage values are acceptable.
116 // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
117 // constraint down the chain which mirrors Windows CryptoAPI behaviour,
118 // but not the spec. To accept any key usage, include ExtKeyUsageAny.
119 KeyUsages []ExtKeyUsage
122 const (
123 leafCertificate = iota
124 intermediateCertificate
125 rootCertificate
128 // isValid performs validity checks on the c.
129 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
130 now := opts.CurrentTime
131 if now.IsZero() {
132 now = time.Now()
134 if now.Before(c.NotBefore) || now.After(c.NotAfter) {
135 return CertificateInvalidError{c, Expired}
138 if len(c.PermittedDNSDomains) > 0 {
139 for _, domain := range c.PermittedDNSDomains {
140 if opts.DNSName == domain ||
141 (strings.HasSuffix(opts.DNSName, domain) &&
142 len(opts.DNSName) >= 1+len(domain) &&
143 opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
144 continue
147 return CertificateInvalidError{c, CANotAuthorizedForThisName}
151 // KeyUsage status flags are ignored. From Engineering Security, Peter
152 // Gutmann: A European government CA marked its signing certificates as
153 // being valid for encryption only, but no-one noticed. Another
154 // European CA marked its signature keys as not being valid for
155 // signatures. A different CA marked its own trusted root certificate
156 // as being invalid for certificate signing. Another national CA
157 // distributed a certificate to be used to encrypt data for the
158 // country’s tax authority that was marked as only being usable for
159 // digital signatures but not for encryption. Yet another CA reversed
160 // the order of the bit flags in the keyUsage due to confusion over
161 // encoding endianness, essentially setting a random keyUsage in
162 // certificates that it issued. Another CA created a self-invalidating
163 // certificate by adding a certificate policy statement stipulating
164 // that the certificate had to be used strictly as specified in the
165 // keyUsage, and a keyUsage containing a flag indicating that the RSA
166 // encryption key could only be used for Diffie-Hellman key agreement.
168 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
169 return CertificateInvalidError{c, NotAuthorizedToSign}
172 if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
173 numIntermediates := len(currentChain) - 1
174 if numIntermediates > c.MaxPathLen {
175 return CertificateInvalidError{c, TooManyIntermediates}
179 return nil
182 // Verify attempts to verify c by building one or more chains from c to a
183 // certificate in opts.Roots, using certificates in opts.Intermediates if
184 // needed. If successful, it returns one or more chains where the first
185 // element of the chain is c and the last element is from opts.Roots.
187 // WARNING: this doesn't do any revocation checking.
188 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
189 // Use Windows's own verification and chain building.
190 if opts.Roots == nil && runtime.GOOS == "windows" {
191 return c.systemVerify(&opts)
194 if opts.Roots == nil {
195 opts.Roots = systemRootsPool()
196 if opts.Roots == nil {
197 return nil, SystemRootsError{}
201 err = c.isValid(leafCertificate, nil, &opts)
202 if err != nil {
203 return
206 if len(opts.DNSName) > 0 {
207 err = c.VerifyHostname(opts.DNSName)
208 if err != nil {
209 return
213 candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
214 if err != nil {
215 return
218 keyUsages := opts.KeyUsages
219 if len(keyUsages) == 0 {
220 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
223 // If any key usage is acceptable then we're done.
224 for _, usage := range keyUsages {
225 if usage == ExtKeyUsageAny {
226 chains = candidateChains
227 return
231 for _, candidate := range candidateChains {
232 if checkChainForKeyUsage(candidate, keyUsages) {
233 chains = append(chains, candidate)
237 if len(chains) == 0 {
238 err = CertificateInvalidError{c, IncompatibleUsage}
241 return
244 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
245 n := make([]*Certificate, len(chain)+1)
246 copy(n, chain)
247 n[len(chain)] = cert
248 return n
251 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
252 for _, rootNum := range opts.Roots.findVerifiedParents(c) {
253 root := opts.Roots.certs[rootNum]
254 err = root.isValid(rootCertificate, currentChain, opts)
255 if err != nil {
256 continue
258 chains = append(chains, appendToFreshChain(currentChain, root))
261 nextIntermediate:
262 for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) {
263 intermediate := opts.Intermediates.certs[intermediateNum]
264 for _, cert := range currentChain {
265 if cert == intermediate {
266 continue nextIntermediate
269 err = intermediate.isValid(intermediateCertificate, currentChain, opts)
270 if err != nil {
271 continue
273 var childChains [][]*Certificate
274 childChains, ok := cache[intermediateNum]
275 if !ok {
276 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
277 cache[intermediateNum] = childChains
279 chains = append(chains, childChains...)
282 if len(chains) > 0 {
283 err = nil
286 if len(chains) == 0 && err == nil {
287 err = UnknownAuthorityError{c}
290 return
293 func matchHostnames(pattern, host string) bool {
294 if len(pattern) == 0 || len(host) == 0 {
295 return false
298 patternParts := strings.Split(pattern, ".")
299 hostParts := strings.Split(host, ".")
301 if len(patternParts) != len(hostParts) {
302 return false
305 for i, patternPart := range patternParts {
306 if patternPart == "*" {
307 continue
309 if patternPart != hostParts[i] {
310 return false
314 return true
317 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
318 // an explicitly ASCII function to avoid any sharp corners resulting from
319 // performing Unicode operations on DNS labels.
320 func toLowerCaseASCII(in string) string {
321 // If the string is already lower-case then there's nothing to do.
322 isAlreadyLowerCase := true
323 for _, c := range in {
324 if c == utf8.RuneError {
325 // If we get a UTF-8 error then there might be
326 // upper-case ASCII bytes in the invalid sequence.
327 isAlreadyLowerCase = false
328 break
330 if 'A' <= c && c <= 'Z' {
331 isAlreadyLowerCase = false
332 break
336 if isAlreadyLowerCase {
337 return in
340 out := []byte(in)
341 for i, c := range out {
342 if 'A' <= c && c <= 'Z' {
343 out[i] += 'a' - 'A'
346 return string(out)
349 // VerifyHostname returns nil if c is a valid certificate for the named host.
350 // Otherwise it returns an error describing the mismatch.
351 func (c *Certificate) VerifyHostname(h string) error {
352 // IP addresses may be written in [ ].
353 candidateIP := h
354 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
355 candidateIP = h[1 : len(h)-1]
357 if ip := net.ParseIP(candidateIP); ip != nil {
358 // We only match IP addresses against IP SANs.
359 // https://tools.ietf.org/html/rfc6125#appendix-B.2
360 for _, candidate := range c.IPAddresses {
361 if ip.Equal(candidate) {
362 return nil
365 return HostnameError{c, candidateIP}
368 lowered := toLowerCaseASCII(h)
370 if len(c.DNSNames) > 0 {
371 for _, match := range c.DNSNames {
372 if matchHostnames(toLowerCaseASCII(match), lowered) {
373 return nil
376 // If Subject Alt Name is given, we ignore the common name.
377 } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
378 return nil
381 return HostnameError{c, h}
384 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
385 usages := make([]ExtKeyUsage, len(keyUsages))
386 copy(usages, keyUsages)
388 if len(chain) == 0 {
389 return false
392 usagesRemaining := len(usages)
394 // We walk down the list and cross out any usages that aren't supported
395 // by each certificate. If we cross out all the usages, then the chain
396 // is unacceptable.
398 for i := len(chain) - 1; i >= 0; i-- {
399 cert := chain[i]
400 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
401 // The certificate doesn't have any extended key usage specified.
402 continue
405 for _, usage := range cert.ExtKeyUsage {
406 if usage == ExtKeyUsageAny {
407 // The certificate is explicitly good for any usage.
408 continue
412 const invalidUsage ExtKeyUsage = -1
414 NextRequestedUsage:
415 for i, requestedUsage := range usages {
416 if requestedUsage == invalidUsage {
417 continue
420 for _, usage := range cert.ExtKeyUsage {
421 if requestedUsage == usage {
422 continue NextRequestedUsage
423 } else if requestedUsage == ExtKeyUsageServerAuth &&
424 (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
425 usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
426 // In order to support COMODO
427 // certificate chains, we have to
428 // accept Netscape or Microsoft SGC
429 // usages as equal to ServerAuth.
430 continue NextRequestedUsage
434 usages[i] = invalidUsage
435 usagesRemaining--
436 if usagesRemaining == 0 {
437 return false
442 return true