Imported Upstream version 4.7.3
[platform/upstream/gcc48.git] / libgo / go / 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 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 }