OSDN Git Service

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