OSDN Git Service

Add BlockWitness (#54)
[bytom/vapor.git] / crypto / sm2 / verify.go
1 package sm2
2
3 import (
4         "bytes"
5         "errors"
6         "fmt"
7         "net"
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         // IncompatibleUsage results when the certificate's key usage indicates
31         // that it may only be used for a different purpose.
32         IncompatibleUsage
33         // NameMismatch results when the subject name of a parent certificate
34         // does not match the issuer name in the child.
35         NameMismatch
36 )
37
38 // CertificateInvalidError results when an odd error occurs. Users of this
39 // library probably want to handle all these errors uniformly.
40 type CertificateInvalidError struct {
41         Cert   *Certificate
42         Reason InvalidReason
43 }
44
45 func (e CertificateInvalidError) Error() string {
46         switch e.Reason {
47         case NotAuthorizedToSign:
48                 return "x509: certificate is not authorized to sign other certificates"
49         case Expired:
50                 return "x509: certificate has expired or is not yet valid"
51         case CANotAuthorizedForThisName:
52                 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
53         case TooManyIntermediates:
54                 return "x509: too many intermediates for path length constraint"
55         case IncompatibleUsage:
56                 return "x509: certificate specifies an incompatible key usage"
57         case NameMismatch:
58                 return "x509: issuer name does not match subject from issuing certificate"
59         }
60         return "x509: unknown error"
61 }
62
63 // HostnameError results when the set of authorized names doesn't match the
64 // requested name.
65 type HostnameError struct {
66         Certificate *Certificate
67         Host        string
68 }
69
70 func (h HostnameError) Error() string {
71         c := h.Certificate
72
73         var valid string
74         if ip := net.ParseIP(h.Host); ip != nil {
75                 // Trying to validate an IP
76                 if len(c.IPAddresses) == 0 {
77                         return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
78                 }
79                 for _, san := range c.IPAddresses {
80                         if len(valid) > 0 {
81                                 valid += ", "
82                         }
83                         valid += san.String()
84                 }
85         } else {
86                 if len(c.DNSNames) > 0 {
87                         valid = strings.Join(c.DNSNames, ", ")
88                 } else {
89                         valid = c.Subject.CommonName
90                 }
91         }
92
93         if len(valid) == 0 {
94                 return "x509: certificate is not valid for any names, but wanted to match " + h.Host
95         }
96         return "x509: certificate is valid for " + valid + ", not " + h.Host
97 }
98
99 // UnknownAuthorityError results when the certificate issuer is unknown
100 type UnknownAuthorityError struct {
101         Cert *Certificate
102         // hintErr contains an error that may be helpful in determining why an
103         // authority wasn't found.
104         hintErr error
105         // hintCert contains a possible authority certificate that was rejected
106         // because of the error in hintErr.
107         hintCert *Certificate
108 }
109
110 func (e UnknownAuthorityError) Error() string {
111         s := "x509: certificate signed by unknown authority"
112         if e.hintErr != nil {
113                 certName := e.hintCert.Subject.CommonName
114                 if len(certName) == 0 {
115                         if len(e.hintCert.Subject.Organization) > 0 {
116                                 certName = e.hintCert.Subject.Organization[0]
117                         } else {
118                                 certName = "serial:" + e.hintCert.SerialNumber.String()
119                         }
120                 }
121                 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
122         }
123         return s
124 }
125
126 // SystemRootsError results when we fail to load the system root certificates.
127 type SystemRootsError struct {
128         Err error
129 }
130
131 func (se SystemRootsError) Error() string {
132         msg := "x509: failed to load system roots and no roots provided"
133         if se.Err != nil {
134                 return msg + "; " + se.Err.Error()
135         }
136         return msg
137 }
138
139 // errNotParsed is returned when a certificate without ASN.1 contents is
140 // verified. Platform-specific verification needs the ASN.1 contents.
141 var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
142
143 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
144 // because other PKIX verification APIs have ended up needing many options.
145 type VerifyOptions struct {
146         DNSName       string
147         Intermediates *CertPool
148         Roots         *CertPool // if nil, the system roots are used
149         CurrentTime   time.Time // if zero, the current time is used
150         // KeyUsage specifies which Extended Key Usage values are acceptable.
151         // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
152         // constraint down the chain which mirrors Windows CryptoAPI behavior,
153         // but not the spec. To accept any key usage, include ExtKeyUsageAny.
154         KeyUsages []ExtKeyUsage
155 }
156
157 const (
158         leafCertificate = iota
159         intermediateCertificate
160         rootCertificate
161 )
162
163 func matchNameConstraint(domain, constraint string) bool {
164         // The meaning of zero length constraints is not specified, but this
165         // code follows NSS and accepts them as valid for everything.
166         if len(constraint) == 0 {
167                 return true
168         }
169
170         if len(domain) < len(constraint) {
171                 return false
172         }
173
174         prefixLen := len(domain) - len(constraint)
175         if !strings.EqualFold(domain[prefixLen:], constraint) {
176                 return false
177         }
178
179         if prefixLen == 0 {
180                 return true
181         }
182
183         isSubdomain := domain[prefixLen-1] == '.'
184         constraintHasLeadingDot := constraint[0] == '.'
185         return isSubdomain != constraintHasLeadingDot
186 }
187
188 // isValid performs validity checks on the c.
189 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
190         if len(currentChain) > 0 {
191                 child := currentChain[len(currentChain)-1]
192                 if !bytes.Equal(child.RawIssuer, c.RawSubject) {
193                         return CertificateInvalidError{c, NameMismatch}
194                 }
195         }
196         now := opts.CurrentTime
197         if now.IsZero() {
198                 now = time.Now()
199         }
200         if now.Before(c.NotBefore) || now.After(c.NotAfter) {
201                 return CertificateInvalidError{c, Expired}
202         }
203         if len(c.PermittedDNSDomains) > 0 {
204                 ok := false
205                 for _, constraint := range c.PermittedDNSDomains {
206                         ok = matchNameConstraint(opts.DNSName, constraint)
207                         if ok {
208                                 break
209                         }
210                 }
211
212                 if !ok {
213                         return CertificateInvalidError{c, CANotAuthorizedForThisName}
214                 }
215         }
216
217         // KeyUsage status flags are ignored. From Engineering Security, Peter
218         // Gutmann: A European government CA marked its signing certificates as
219         // being valid for encryption only, but no-one noticed. Another
220         // European CA marked its signature keys as not being valid for
221         // signatures. A different CA marked its own trusted root certificate
222         // as being invalid for certificate signing. Another national CA
223         // distributed a certificate to be used to encrypt data for the
224         // country‚Äôs tax authority that was marked as only being usable for
225         // digital signatures but not for encryption. Yet another CA reversed
226         // the order of the bit flags in the keyUsage due to confusion over
227         // encoding endianness, essentially setting a random keyUsage in
228         // certificates that it issued. Another CA created a self-invalidating
229         // certificate by adding a certificate policy statement stipulating
230         // that the certificate had to be used strictly as specified in the
231         // keyUsage, and a keyUsage containing a flag indicating that the RSA
232         // encryption key could only be used for Diffie-Hellman key agreement.
233
234         if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
235                 return CertificateInvalidError{c, NotAuthorizedToSign}
236         }
237
238         if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
239                 numIntermediates := len(currentChain) - 1
240                 if numIntermediates > c.MaxPathLen {
241                         return CertificateInvalidError{c, TooManyIntermediates}
242                 }
243         }
244
245         return nil
246 }
247
248 // Verify attempts to verify c by building one or more chains from c to a
249 // certificate in opts.Roots, using certificates in opts.Intermediates if
250 // needed. If successful, it returns one or more chains where the first
251 // element of the chain is c and the last element is from opts.Roots.
252 //
253 // If opts.Roots is nil and system roots are unavailable the returned error
254 // will be of type SystemRootsError.
255 //
256 // WARNING: this doesn't do any revocation checking.
257 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
258         // Platform-specific verification needs the ASN.1 contents so
259         // this makes the behavior consistent across platforms.
260         if len(c.Raw) == 0 {
261                 return nil, errNotParsed
262         }
263         if opts.Intermediates != nil {
264                 for _, intermediate := range opts.Intermediates.certs {
265                         if len(intermediate.Raw) == 0 {
266                                 return nil, errNotParsed
267                         }
268                 }
269         }
270
271         // Use Windows's own verification and chain building.
272         if opts.Roots == nil && runtime.GOOS == "windows" {
273                 return c.systemVerify(&opts)
274         }
275
276         if len(c.UnhandledCriticalExtensions) > 0 {
277                 return nil, UnhandledCriticalExtension{}
278         }
279
280         if opts.Roots == nil {
281                 opts.Roots = systemRootsPool()
282                 if opts.Roots == nil {
283                         return nil, SystemRootsError{systemRootsErr}
284                 }
285         }
286
287         err = c.isValid(leafCertificate, nil, &opts)
288         if err != nil {
289                 return
290         }
291
292         if len(opts.DNSName) > 0 {
293                 err = c.VerifyHostname(opts.DNSName)
294                 if err != nil {
295                         return
296                 }
297         }
298
299         var candidateChains [][]*Certificate
300         if opts.Roots.contains(c) {
301                 candidateChains = append(candidateChains, []*Certificate{c})
302         } else {
303                 if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
304                         return nil, err
305                 }
306         }
307
308         keyUsages := opts.KeyUsages
309         if len(keyUsages) == 0 {
310                 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
311         }
312
313         // If any key usage is acceptable then we're done.
314         for _, usage := range keyUsages {
315                 if usage == ExtKeyUsageAny {
316                         chains = candidateChains
317                         return
318                 }
319         }
320
321         for _, candidate := range candidateChains {
322                 if checkChainForKeyUsage(candidate, keyUsages) {
323                         chains = append(chains, candidate)
324                 }
325         }
326
327         if len(chains) == 0 {
328                 err = CertificateInvalidError{c, IncompatibleUsage}
329         }
330
331         return
332 }
333
334 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
335         n := make([]*Certificate, len(chain)+1)
336         copy(n, chain)
337         n[len(chain)] = cert
338         return n
339 }
340
341 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
342         possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
343 nextRoot:
344         for _, rootNum := range possibleRoots {
345                 root := opts.Roots.certs[rootNum]
346
347                 for _, cert := range currentChain {
348                         if cert.Equal(root) {
349                                 continue nextRoot
350                         }
351                 }
352
353                 err = root.isValid(rootCertificate, currentChain, opts)
354                 if err != nil {
355                         continue
356                 }
357                 chains = append(chains, appendToFreshChain(currentChain, root))
358         }
359
360         possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
361 nextIntermediate:
362         for _, intermediateNum := range possibleIntermediates {
363                 intermediate := opts.Intermediates.certs[intermediateNum]
364                 for _, cert := range currentChain {
365                         if cert.Equal(intermediate) {
366                                 continue nextIntermediate
367                         }
368                 }
369                 err = intermediate.isValid(intermediateCertificate, currentChain, opts)
370                 if err != nil {
371                         continue
372                 }
373                 var childChains [][]*Certificate
374                 childChains, ok := cache[intermediateNum]
375                 if !ok {
376                         childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
377                         cache[intermediateNum] = childChains
378                 }
379                 chains = append(chains, childChains...)
380         }
381
382         if len(chains) > 0 {
383                 err = nil
384         }
385
386         if len(chains) == 0 && err == nil {
387                 hintErr := rootErr
388                 hintCert := failedRoot
389                 if hintErr == nil {
390                         hintErr = intermediateErr
391                         hintCert = failedIntermediate
392                 }
393                 err = UnknownAuthorityError{c, hintErr, hintCert}
394         }
395
396         return
397 }
398
399 func matchHostnames(pattern, host string) bool {
400         host = strings.TrimSuffix(host, ".")
401         pattern = strings.TrimSuffix(pattern, ".")
402
403         if len(pattern) == 0 || len(host) == 0 {
404                 return false
405         }
406
407         patternParts := strings.Split(pattern, ".")
408         hostParts := strings.Split(host, ".")
409
410         if len(patternParts) != len(hostParts) {
411                 return false
412         }
413
414         for i, patternPart := range patternParts {
415                 if i == 0 && patternPart == "*" {
416                         continue
417                 }
418                 if patternPart != hostParts[i] {
419                         return false
420                 }
421         }
422
423         return true
424 }
425
426 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
427 // an explicitly ASCII function to avoid any sharp corners resulting from
428 // performing Unicode operations on DNS labels.
429 func toLowerCaseASCII(in string) string {
430         // If the string is already lower-case then there's nothing to do.
431         isAlreadyLowerCase := true
432         for _, c := range in {
433                 if c == utf8.RuneError {
434                         // If we get a UTF-8 error then there might be
435                         // upper-case ASCII bytes in the invalid sequence.
436                         isAlreadyLowerCase = false
437                         break
438                 }
439                 if 'A' <= c && c <= 'Z' {
440                         isAlreadyLowerCase = false
441                         break
442                 }
443         }
444
445         if isAlreadyLowerCase {
446                 return in
447         }
448
449         out := []byte(in)
450         for i, c := range out {
451                 if 'A' <= c && c <= 'Z' {
452                         out[i] += 'a' - 'A'
453                 }
454         }
455         return string(out)
456 }
457
458 // VerifyHostname returns nil if c is a valid certificate for the named host.
459 // Otherwise it returns an error describing the mismatch.
460 func (c *Certificate) VerifyHostname(h string) error {
461         // IP addresses may be written in [ ].
462         candidateIP := h
463         if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
464                 candidateIP = h[1 : len(h)-1]
465         }
466         if ip := net.ParseIP(candidateIP); ip != nil {
467                 // We only match IP addresses against IP SANs.
468                 // https://tools.ietf.org/html/rfc6125#appendix-B.2
469                 for _, candidate := range c.IPAddresses {
470                         if ip.Equal(candidate) {
471                                 return nil
472                         }
473                 }
474                 return HostnameError{c, candidateIP}
475         }
476
477         lowered := toLowerCaseASCII(h)
478
479         if len(c.DNSNames) > 0 {
480                 for _, match := range c.DNSNames {
481                         if matchHostnames(toLowerCaseASCII(match), lowered) {
482                                 return nil
483                         }
484                 }
485                 // If Subject Alt Name is given, we ignore the common name.
486         } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
487                 return nil
488         }
489
490         return HostnameError{c, h}
491 }
492
493 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
494         usages := make([]ExtKeyUsage, len(keyUsages))
495         copy(usages, keyUsages)
496
497         if len(chain) == 0 {
498                 return false
499         }
500
501         usagesRemaining := len(usages)
502
503         // We walk down the list and cross out any usages that aren't supported
504         // by each certificate. If we cross out all the usages, then the chain
505         // is unacceptable.
506
507 NextCert:
508         for i := len(chain) - 1; i >= 0; i-- {
509                 cert := chain[i]
510                 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
511                         // The certificate doesn't have any extended key usage specified.
512                         continue
513                 }
514
515                 for _, usage := range cert.ExtKeyUsage {
516                         if usage == ExtKeyUsageAny {
517                                 // The certificate is explicitly good for any usage.
518                                 continue NextCert
519                         }
520                 }
521
522                 const invalidUsage ExtKeyUsage = -1
523
524         NextRequestedUsage:
525                 for i, requestedUsage := range usages {
526                         if requestedUsage == invalidUsage {
527                                 continue
528                         }
529
530                         for _, usage := range cert.ExtKeyUsage {
531                                 if requestedUsage == usage {
532                                         continue NextRequestedUsage
533                                 } else if requestedUsage == ExtKeyUsageServerAuth &&
534                                         (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
535                                                 usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
536                                         // In order to support COMODO
537                                         // certificate chains, we have to
538                                         // accept Netscape or Microsoft SGC
539                                         // usages as equal to ServerAuth.
540                                         continue NextRequestedUsage
541                                 }
542                         }
543
544                         usages[i] = invalidUsage
545                         usagesRemaining--
546                         if usagesRemaining == 0 {
547                                 return false
548                         }
549                 }
550         }
551
552         return true
553 }