1
15
16 package x509
17
18 import (
19 "bytes"
20 "errors"
21 "fmt"
22 "net"
23 "runtime"
24 "strings"
25 "time"
26 "unicode/utf8"
27 )
28
29 type InvalidReason int
30
31 const (
32
33
34 NotAuthorizedToSign InvalidReason = iota
35
36
37 Expired
38
39
40
41 CANotAuthorizedForThisName
42
43
44 TooManyIntermediates
45
46
47 IncompatibleUsage
48
49
50 NameMismatch
51 )
52
53
54
55 type CertificateInvalidError struct {
56 Cert *Certificate
57 Reason InvalidReason
58 }
59
60 func (e CertificateInvalidError) Error() string {
61 switch e.Reason {
62 case NotAuthorizedToSign:
63 return "x509: certificate is not authorized to sign other certificates"
64 case Expired:
65 return "x509: certificate has expired or is not yet valid"
66 case CANotAuthorizedForThisName:
67 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
68 case TooManyIntermediates:
69 return "x509: too many intermediates for path length constraint"
70 case IncompatibleUsage:
71 return "x509: certificate specifies an incompatible key usage"
72 case NameMismatch:
73 return "x509: issuer name does not match subject from issuing certificate"
74 }
75 return "x509: unknown error"
76 }
77
78
79
80 type HostnameError struct {
81 Certificate *Certificate
82 Host string
83 }
84
85 func (h HostnameError) Error() string {
86 c := h.Certificate
87
88 var valid string
89 if ip := net.ParseIP(h.Host); ip != nil {
90
91 if len(c.IPAddresses) == 0 {
92 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
93 }
94 for _, san := range c.IPAddresses {
95 if len(valid) > 0 {
96 valid += ", "
97 }
98 valid += san.String()
99 }
100 } else {
101 if len(c.DNSNames) > 0 {
102 valid = strings.Join(c.DNSNames, ", ")
103 } else {
104 valid = c.Subject.CommonName
105 }
106 }
107
108 if len(valid) == 0 {
109 return "x509: certificate is not valid for any names, but wanted to match " + h.Host
110 }
111 return "x509: certificate is valid for " + valid + ", not " + h.Host
112 }
113
114
115 type UnknownAuthorityError struct {
116 Cert *Certificate
117
118
119 hintErr error
120
121
122 hintCert *Certificate
123 }
124
125 func (e UnknownAuthorityError) Error() string {
126 s := "x509: certificate signed by unknown authority"
127 if e.hintErr != nil {
128 certName := e.hintCert.Subject.CommonName
129 if len(certName) == 0 {
130 if len(e.hintCert.Subject.Organization) > 0 {
131 certName = e.hintCert.Subject.Organization[0]
132 } else {
133 certName = "serial:" + e.hintCert.SerialNumber.String()
134 }
135 }
136 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
137 }
138 return s
139 }
140
141
142 type SystemRootsError struct {
143 Err error
144 }
145
146 func (se SystemRootsError) Error() string {
147 msg := "x509: failed to load system roots and no roots provided"
148 if se.Err != nil {
149 return msg + "; " + se.Err.Error()
150 }
151 return msg
152 }
153
154
155
156 var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
157
158
159
160 type VerifyOptions struct {
161 DNSName string
162 Intermediates *CertPool
163 Roots *CertPool
164 CurrentTime time.Time
165
166
167
168
169 KeyUsages []ExtKeyUsage
170 }
171
172 const (
173 leafCertificate = iota
174 intermediateCertificate
175 rootCertificate
176 )
177
178 func matchNameConstraint(domain, constraint string) bool {
179
180
181 if len(constraint) == 0 {
182 return true
183 }
184
185 if len(domain) < len(constraint) {
186 return false
187 }
188
189 prefixLen := len(domain) - len(constraint)
190 if !strings.EqualFold(domain[prefixLen:], constraint) {
191 return false
192 }
193
194 if prefixLen == 0 {
195 return true
196 }
197
198 isSubdomain := domain[prefixLen-1] == '.'
199 constraintHasLeadingDot := constraint[0] == '.'
200 return isSubdomain != constraintHasLeadingDot
201 }
202
203
204 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
205 if len(currentChain) > 0 {
206 child := currentChain[len(currentChain)-1]
207 if !bytes.Equal(child.RawIssuer, c.RawSubject) {
208 return CertificateInvalidError{c, NameMismatch}
209 }
210 }
211 now := opts.CurrentTime
212 if now.IsZero() {
213 now = time.Now()
214 }
215 if now.Before(c.NotBefore) || now.After(c.NotAfter) {
216 return CertificateInvalidError{c, Expired}
217 }
218 if len(c.PermittedDNSDomains) > 0 {
219 ok := false
220 for _, constraint := range c.PermittedDNSDomains {
221 ok = matchNameConstraint(opts.DNSName, constraint)
222 if ok {
223 break
224 }
225 }
226
227 if !ok {
228 return CertificateInvalidError{c, CANotAuthorizedForThisName}
229 }
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
250 return CertificateInvalidError{c, NotAuthorizedToSign}
251 }
252
253 if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
254 numIntermediates := len(currentChain) - 1
255 if numIntermediates > c.MaxPathLen {
256 return CertificateInvalidError{c, TooManyIntermediates}
257 }
258 }
259
260 return nil
261 }
262
263
264
265
266
267
268
269
270
271
272 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
273
274
275 if len(c.Raw) == 0 {
276 return nil, errNotParsed
277 }
278 if opts.Intermediates != nil {
279 for _, intermediate := range opts.Intermediates.certs {
280 if len(intermediate.Raw) == 0 {
281 return nil, errNotParsed
282 }
283 }
284 }
285
286
287 if opts.Roots == nil && runtime.GOOS == "windows" {
288 return c.systemVerify(&opts)
289 }
290
291 if len(c.UnhandledCriticalExtensions) > 0 {
292 return nil, UnhandledCriticalExtension{}
293 }
294
295 if opts.Roots == nil {
296 opts.Roots = systemRootsPool()
297 if opts.Roots == nil {
298 return nil, SystemRootsError{systemRootsErr}
299 }
300 }
301
302 err = c.isValid(leafCertificate, nil, &opts)
303 if err != nil {
304 return
305 }
306
307 if len(opts.DNSName) > 0 {
308 err = c.VerifyHostname(opts.DNSName)
309 if err != nil {
310 return
311 }
312 }
313
314 var candidateChains [][]*Certificate
315 if opts.Roots.contains(c) {
316 candidateChains = append(candidateChains, []*Certificate{c})
317 } else {
318 if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
319 return nil, err
320 }
321 }
322
323 keyUsages := opts.KeyUsages
324 if len(keyUsages) == 0 {
325 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
326 }
327
328
329 for _, usage := range keyUsages {
330 if usage == ExtKeyUsageAny {
331 chains = candidateChains
332 return
333 }
334 }
335
336 for _, candidate := range candidateChains {
337 if checkChainForKeyUsage(candidate, keyUsages) {
338 chains = append(chains, candidate)
339 }
340 }
341
342 if len(chains) == 0 {
343 err = CertificateInvalidError{c, IncompatibleUsage}
344 }
345
346 return
347 }
348
349 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
350 n := make([]*Certificate, len(chain)+1)
351 copy(n, chain)
352 n[len(chain)] = cert
353 return n
354 }
355
356 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
357 possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
358 nextRoot:
359 for _, rootNum := range possibleRoots {
360 root := opts.Roots.certs[rootNum]
361
362 for _, cert := range currentChain {
363 if cert.Equal(root) {
364 continue nextRoot
365 }
366 }
367
368 err = root.isValid(rootCertificate, currentChain, opts)
369 if err != nil {
370 continue
371 }
372 chains = append(chains, appendToFreshChain(currentChain, root))
373 }
374
375 possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
376 nextIntermediate:
377 for _, intermediateNum := range possibleIntermediates {
378 intermediate := opts.Intermediates.certs[intermediateNum]
379 for _, cert := range currentChain {
380 if cert.Equal(intermediate) {
381 continue nextIntermediate
382 }
383 }
384 err = intermediate.isValid(intermediateCertificate, currentChain, opts)
385 if err != nil {
386 continue
387 }
388 var childChains [][]*Certificate
389 childChains, ok := cache[intermediateNum]
390 if !ok {
391 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
392 cache[intermediateNum] = childChains
393 }
394 chains = append(chains, childChains...)
395 }
396
397 if len(chains) > 0 {
398 err = nil
399 }
400
401 if len(chains) == 0 && err == nil {
402 hintErr := rootErr
403 hintCert := failedRoot
404 if hintErr == nil {
405 hintErr = intermediateErr
406 hintCert = failedIntermediate
407 }
408 err = UnknownAuthorityError{c, hintErr, hintCert}
409 }
410
411 return
412 }
413
414 func matchHostnames(pattern, host string) bool {
415 host = strings.TrimSuffix(host, ".")
416 pattern = strings.TrimSuffix(pattern, ".")
417
418 if len(pattern) == 0 || len(host) == 0 {
419 return false
420 }
421
422 patternParts := strings.Split(pattern, ".")
423 hostParts := strings.Split(host, ".")
424
425 if len(patternParts) != len(hostParts) {
426 return false
427 }
428
429 for i, patternPart := range patternParts {
430 if i == 0 && patternPart == "*" {
431 continue
432 }
433 if patternPart != hostParts[i] {
434 return false
435 }
436 }
437
438 return true
439 }
440
441
442
443
444 func toLowerCaseASCII(in string) string {
445
446 isAlreadyLowerCase := true
447 for _, c := range in {
448 if c == utf8.RuneError {
449
450
451 isAlreadyLowerCase = false
452 break
453 }
454 if 'A' <= c && c <= 'Z' {
455 isAlreadyLowerCase = false
456 break
457 }
458 }
459
460 if isAlreadyLowerCase {
461 return in
462 }
463
464 out := []byte(in)
465 for i, c := range out {
466 if 'A' <= c && c <= 'Z' {
467 out[i] += 'a' - 'A'
468 }
469 }
470 return string(out)
471 }
472
473
474
475 func (c *Certificate) VerifyHostname(h string) error {
476
477 candidateIP := h
478 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
479 candidateIP = h[1 : len(h)-1]
480 }
481 if ip := net.ParseIP(candidateIP); ip != nil {
482
483
484 for _, candidate := range c.IPAddresses {
485 if ip.Equal(candidate) {
486 return nil
487 }
488 }
489 return HostnameError{c, candidateIP}
490 }
491
492 lowered := toLowerCaseASCII(h)
493
494 if len(c.DNSNames) > 0 {
495 for _, match := range c.DNSNames {
496 if matchHostnames(toLowerCaseASCII(match), lowered) {
497 return nil
498 }
499 }
500
501 } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
502 return nil
503 }
504
505 return HostnameError{c, h}
506 }
507
508 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
509 usages := make([]ExtKeyUsage, len(keyUsages))
510 copy(usages, keyUsages)
511
512 if len(chain) == 0 {
513 return false
514 }
515
516 usagesRemaining := len(usages)
517
518
519
520
521
522 NextCert:
523 for i := len(chain) - 1; i >= 0; i-- {
524 cert := chain[i]
525 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
526
527 continue
528 }
529
530 for _, usage := range cert.ExtKeyUsage {
531 if usage == ExtKeyUsageAny {
532
533 continue NextCert
534 }
535 }
536
537 const invalidUsage ExtKeyUsage = -1
538
539 NextRequestedUsage:
540 for i, requestedUsage := range usages {
541 if requestedUsage == invalidUsage {
542 continue
543 }
544
545 for _, usage := range cert.ExtKeyUsage {
546 if requestedUsage == usage {
547 continue NextRequestedUsage
548 } else if requestedUsage == ExtKeyUsageServerAuth &&
549 (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
550 usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
551
552
553
554
555 continue NextRequestedUsage
556 }
557 }
558
559 usages[i] = invalidUsage
560 usagesRemaining--
561 if usagesRemaining == 0 {
562 return false
563 }
564 }
565 }
566
567 return true
568 }
569
View as plain text