1
2
3
4
5 package x509
6
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "net"
12 "net/url"
13 "reflect"
14 "runtime"
15 "strings"
16 "time"
17 "unicode/utf8"
18 )
19
20 type InvalidReason int
21
22 const (
23
24
25 NotAuthorizedToSign InvalidReason = iota
26
27
28 Expired
29
30
31
32 CANotAuthorizedForThisName
33
34
35 TooManyIntermediates
36
37
38 IncompatibleUsage
39
40
41 NameMismatch
42
43
44
45 NameConstraintsWithoutSANs
46
47
48
49 UnconstrainedName
50
51
52
53
54
55 TooManyConstraints
56
57
58
59 CANotAuthorizedForExtKeyUsage
60 )
61
62
63
64 type CertificateInvalidError struct {
65 Cert *Certificate
66 Reason InvalidReason
67 Detail string
68 }
69
70 func (e CertificateInvalidError) Error() string {
71 switch e.Reason {
72 case NotAuthorizedToSign:
73 return "x509: certificate is not authorized to sign other certificates"
74 case Expired:
75 return "x509: certificate has expired or is not yet valid"
76 case CANotAuthorizedForThisName:
77 return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail
78 case CANotAuthorizedForExtKeyUsage:
79 return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail
80 case TooManyIntermediates:
81 return "x509: too many intermediates for path length constraint"
82 case IncompatibleUsage:
83 return "x509: certificate specifies an incompatible key usage: " + e.Detail
84 case NameMismatch:
85 return "x509: issuer name does not match subject from issuing certificate"
86 case NameConstraintsWithoutSANs:
87 return "x509: issuer has name constraints but leaf doesn't have a SAN extension"
88 case UnconstrainedName:
89 return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail
90 }
91 return "x509: unknown error"
92 }
93
94
95
96 type HostnameError struct {
97 Certificate *Certificate
98 Host string
99 }
100
101 func (h HostnameError) Error() string {
102 c := h.Certificate
103
104 var valid string
105 if ip := net.ParseIP(h.Host); ip != nil {
106
107 if len(c.IPAddresses) == 0 {
108 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
109 }
110 for _, san := range c.IPAddresses {
111 if len(valid) > 0 {
112 valid += ", "
113 }
114 valid += san.String()
115 }
116 } else {
117 if c.hasSANExtension() {
118 valid = strings.Join(c.DNSNames, ", ")
119 } else {
120 valid = c.Subject.CommonName
121 }
122 }
123
124 if len(valid) == 0 {
125 return "x509: certificate is not valid for any names, but wanted to match " + h.Host
126 }
127 return "x509: certificate is valid for " + valid + ", not " + h.Host
128 }
129
130
131 type UnknownAuthorityError struct {
132 Cert *Certificate
133
134
135 hintErr error
136
137
138 hintCert *Certificate
139 }
140
141 func (e UnknownAuthorityError) Error() string {
142 s := "x509: certificate signed by unknown authority"
143 if e.hintErr != nil {
144 certName := e.hintCert.Subject.CommonName
145 if len(certName) == 0 {
146 if len(e.hintCert.Subject.Organization) > 0 {
147 certName = e.hintCert.Subject.Organization[0]
148 } else {
149 certName = "serial:" + e.hintCert.SerialNumber.String()
150 }
151 }
152 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
153 }
154 return s
155 }
156
157
158 type SystemRootsError struct {
159 Err error
160 }
161
162 func (se SystemRootsError) Error() string {
163 msg := "x509: failed to load system roots and no roots provided"
164 if se.Err != nil {
165 return msg + "; " + se.Err.Error()
166 }
167 return msg
168 }
169
170
171
172 var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
173
174
175
176 type VerifyOptions struct {
177 DNSName string
178 Intermediates *CertPool
179 Roots *CertPool
180 CurrentTime time.Time
181
182
183
184
185 KeyUsages []ExtKeyUsage
186
187
188
189
190
191 MaxConstraintComparisions int
192 }
193
194 const (
195 leafCertificate = iota
196 intermediateCertificate
197 rootCertificate
198 )
199
200
201
202
203 type rfc2821Mailbox struct {
204 local, domain string
205 }
206
207
208
209
210
211
212 func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
213 if len(in) == 0 {
214 return mailbox, false
215 }
216
217 localPartBytes := make([]byte, 0, len(in)/2)
218
219 if in[0] == '"' {
220
221
222
223
224
225
226
227
228
229
230
231 in = in[1:]
232 QuotedString:
233 for {
234 if len(in) == 0 {
235 return mailbox, false
236 }
237 c := in[0]
238 in = in[1:]
239
240 switch {
241 case c == '"':
242 break QuotedString
243
244 case c == '\\':
245
246 if len(in) == 0 {
247 return mailbox, false
248 }
249 if in[0] == 11 ||
250 in[0] == 12 ||
251 (1 <= in[0] && in[0] <= 9) ||
252 (14 <= in[0] && in[0] <= 127) {
253 localPartBytes = append(localPartBytes, in[0])
254 in = in[1:]
255 } else {
256 return mailbox, false
257 }
258
259 case c == 11 ||
260 c == 12 ||
261
262
263
264
265
266 c == 32 ||
267 c == 33 ||
268 c == 127 ||
269 (1 <= c && c <= 8) ||
270 (14 <= c && c <= 31) ||
271 (35 <= c && c <= 91) ||
272 (93 <= c && c <= 126):
273
274 localPartBytes = append(localPartBytes, c)
275
276 default:
277 return mailbox, false
278 }
279 }
280 } else {
281
282 NextChar:
283 for len(in) > 0 {
284
285 c := in[0]
286
287 switch {
288 case c == '\\':
289
290
291
292
293
294 in = in[1:]
295 if len(in) == 0 {
296 return mailbox, false
297 }
298 fallthrough
299
300 case ('0' <= c && c <= '9') ||
301 ('a' <= c && c <= 'z') ||
302 ('A' <= c && c <= 'Z') ||
303 c == '!' || c == '#' || c == '$' || c == '%' ||
304 c == '&' || c == '\'' || c == '*' || c == '+' ||
305 c == '-' || c == '/' || c == '=' || c == '?' ||
306 c == '^' || c == '_' || c == '`' || c == '{' ||
307 c == '|' || c == '}' || c == '~' || c == '.':
308 localPartBytes = append(localPartBytes, in[0])
309 in = in[1:]
310
311 default:
312 break NextChar
313 }
314 }
315
316 if len(localPartBytes) == 0 {
317 return mailbox, false
318 }
319
320
321
322
323
324 twoDots := []byte{'.', '.'}
325 if localPartBytes[0] == '.' ||
326 localPartBytes[len(localPartBytes)-1] == '.' ||
327 bytes.Contains(localPartBytes, twoDots) {
328 return mailbox, false
329 }
330 }
331
332 if len(in) == 0 || in[0] != '@' {
333 return mailbox, false
334 }
335 in = in[1:]
336
337
338
339
340 if _, ok := domainToReverseLabels(in); !ok {
341 return mailbox, false
342 }
343
344 mailbox.local = string(localPartBytes)
345 mailbox.domain = in
346 return mailbox, true
347 }
348
349
350
351 func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
352 for len(domain) > 0 {
353 if i := strings.LastIndexByte(domain, '.'); i == -1 {
354 reverseLabels = append(reverseLabels, domain)
355 domain = ""
356 } else {
357 reverseLabels = append(reverseLabels, domain[i+1:len(domain)])
358 domain = domain[:i]
359 }
360 }
361
362 if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
363
364 return nil, false
365 }
366
367 for _, label := range reverseLabels {
368 if len(label) == 0 {
369
370 return nil, false
371 }
372
373 for _, c := range label {
374 if c < 33 || c > 126 {
375
376 return nil, false
377 }
378 }
379 }
380
381 return reverseLabels, true
382 }
383
384 func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) {
385
386
387 if strings.Contains(constraint, "@") {
388 constraintMailbox, ok := parseRFC2821Mailbox(constraint)
389 if !ok {
390 return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint)
391 }
392 return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil
393 }
394
395
396
397 return matchDomainConstraint(mailbox.domain, constraint)
398 }
399
400 func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
401
402
403
404
405
406
407
408
409 host := uri.Host
410 if len(host) == 0 {
411 return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String())
412 }
413
414 if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") {
415 var err error
416 host, _, err = net.SplitHostPort(uri.Host)
417 if err != nil {
418 return false, err
419 }
420 }
421
422 if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
423 net.ParseIP(host) != nil {
424 return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
425 }
426
427 return matchDomainConstraint(host, constraint)
428 }
429
430 func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) {
431 if len(ip) != len(constraint.IP) {
432 return false, nil
433 }
434
435 for i := range ip {
436 if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask {
437 return false, nil
438 }
439 }
440
441 return true, nil
442 }
443
444 func matchDomainConstraint(domain, constraint string) (bool, error) {
445
446
447 if len(constraint) == 0 {
448 return true, nil
449 }
450
451 domainLabels, ok := domainToReverseLabels(domain)
452 if !ok {
453 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain)
454 }
455
456
457
458
459
460
461 mustHaveSubdomains := false
462 if constraint[0] == '.' {
463 mustHaveSubdomains = true
464 constraint = constraint[1:]
465 }
466
467 constraintLabels, ok := domainToReverseLabels(constraint)
468 if !ok {
469 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint)
470 }
471
472 if len(domainLabels) < len(constraintLabels) ||
473 (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) {
474 return false, nil
475 }
476
477 for i, constraintLabel := range constraintLabels {
478 if !strings.EqualFold(constraintLabel, domainLabels[i]) {
479 return false, nil
480 }
481 }
482
483 return true, nil
484 }
485
486
487
488
489
490
491 func (c *Certificate) checkNameConstraints(count *int,
492 maxConstraintComparisons int,
493 nameType string,
494 name string,
495 parsedName interface{},
496 match func(parsedName, constraint interface{}) (match bool, err error),
497 permitted, excluded interface{}) error {
498
499 excludedValue := reflect.ValueOf(excluded)
500
501 *count += excludedValue.Len()
502 if *count > maxConstraintComparisons {
503 return CertificateInvalidError{c, TooManyConstraints, ""}
504 }
505
506 for i := 0; i < excludedValue.Len(); i++ {
507 constraint := excludedValue.Index(i).Interface()
508 match, err := match(parsedName, constraint)
509 if err != nil {
510 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
511 }
512
513 if match {
514 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)}
515 }
516 }
517
518 permittedValue := reflect.ValueOf(permitted)
519
520 *count += permittedValue.Len()
521 if *count > maxConstraintComparisons {
522 return CertificateInvalidError{c, TooManyConstraints, ""}
523 }
524
525 ok := true
526 for i := 0; i < permittedValue.Len(); i++ {
527 constraint := permittedValue.Index(i).Interface()
528
529 var err error
530 if ok, err = match(parsedName, constraint); err != nil {
531 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
532 }
533
534 if ok {
535 break
536 }
537 }
538
539 if !ok {
540 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)}
541 }
542
543 return nil
544 }
545
546
547
548
549
550 func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
551 if certEKU == ExtKeyUsageAny || eku == certEKU {
552 return true
553 }
554
555
556
557 mapServerAuthEKUs := func(eku ExtKeyUsage) ExtKeyUsage {
558 if eku == ExtKeyUsageNetscapeServerGatedCrypto || eku == ExtKeyUsageMicrosoftServerGatedCrypto {
559 return ExtKeyUsageServerAuth
560 }
561 return eku
562 }
563
564 eku = mapServerAuthEKUs(eku)
565 certEKU = mapServerAuthEKUs(certEKU)
566
567 if eku == certEKU ||
568
569 (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
570
571 eku == ExtKeyUsageOCSPSigning ||
572
573
574 ((eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning) {
575 return true
576 }
577
578 return false
579 }
580
581
582
583 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
584 if len(c.UnhandledCriticalExtensions) > 0 {
585 return UnhandledCriticalExtension{}
586 }
587
588 if len(currentChain) > 0 {
589 child := currentChain[len(currentChain)-1]
590 if !bytes.Equal(child.RawIssuer, c.RawSubject) {
591 return CertificateInvalidError{c, NameMismatch, ""}
592 }
593 }
594
595 now := opts.CurrentTime
596 if now.IsZero() {
597 now = time.Now()
598 }
599 if now.Before(c.NotBefore) || now.After(c.NotAfter) {
600 return CertificateInvalidError{c, Expired, ""}
601 }
602
603 maxConstraintComparisons := opts.MaxConstraintComparisions
604 if maxConstraintComparisons == 0 {
605 maxConstraintComparisons = 250000
606 }
607 comparisonCount := 0
608
609 var leaf *Certificate
610 if certType == intermediateCertificate || certType == rootCertificate {
611 if len(currentChain) == 0 {
612 return errors.New("x509: internal error: empty chain when appending CA cert")
613 }
614 leaf = currentChain[0]
615 }
616
617 if (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints() {
618 sanExtension, ok := leaf.getSANExtension()
619 if !ok {
620
621
622
623
624 return CertificateInvalidError{c, NameConstraintsWithoutSANs, ""}
625 }
626
627 err := forEachSAN(sanExtension, func(tag int, data []byte) error {
628 switch tag {
629 case nameTypeEmail:
630 name := string(data)
631 mailbox, ok := parseRFC2821Mailbox(name)
632 if !ok {
633
634 return errors.New("x509: internal error: rfc822Name SAN failed to parse")
635 }
636
637 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
638 func(parsedName, constraint interface{}) (bool, error) {
639 return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string))
640 }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil {
641 return err
642 }
643
644 case nameTypeDNS:
645 name := string(data)
646 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
647 func(parsedName, constraint interface{}) (bool, error) {
648 return matchDomainConstraint(parsedName.(string), constraint.(string))
649 }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil {
650 return err
651 }
652
653 case nameTypeURI:
654 name := string(data)
655 uri, err := url.Parse(name)
656 if err != nil {
657 return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name)
658 }
659
660 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri,
661 func(parsedName, constraint interface{}) (bool, error) {
662 return matchURIConstraint(parsedName.(*url.URL), constraint.(string))
663 }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil {
664 return err
665 }
666
667 case nameTypeIP:
668 ip := net.IP(data)
669 if l := len(ip); l != net.IPv4len && l != net.IPv6len {
670 return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data)
671 }
672
673 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip,
674 func(parsedName, constraint interface{}) (bool, error) {
675 return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet))
676 }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil {
677 return err
678 }
679
680 default:
681
682 }
683
684 return nil
685 })
686
687 if err != nil {
688 return err
689 }
690 }
691
692 checkEKUs := certType == intermediateCertificate
693
694
695 if checkEKUs && (len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0) {
696 checkEKUs = false
697 }
698
699
700 if checkEKUs {
701 for _, caEKU := range c.ExtKeyUsage {
702 comparisonCount++
703 if caEKU == ExtKeyUsageAny {
704 checkEKUs = false
705 break
706 }
707 }
708 }
709
710 if checkEKUs {
711 NextEKU:
712 for _, eku := range leaf.ExtKeyUsage {
713 if comparisonCount > maxConstraintComparisons {
714 return CertificateInvalidError{c, TooManyConstraints, ""}
715 }
716
717 for _, caEKU := range c.ExtKeyUsage {
718 comparisonCount++
719 if ekuPermittedBy(eku, caEKU) {
720 continue NextEKU
721 }
722 }
723
724 oid, _ := oidFromExtKeyUsage(eku)
725 return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", oid)}
726 }
727
728 NextUnknownEKU:
729 for _, eku := range leaf.UnknownExtKeyUsage {
730 if comparisonCount > maxConstraintComparisons {
731 return CertificateInvalidError{c, TooManyConstraints, ""}
732 }
733
734 for _, caEKU := range c.UnknownExtKeyUsage {
735 comparisonCount++
736 if caEKU.Equal(eku) {
737 continue NextUnknownEKU
738 }
739 }
740
741 return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", eku)}
742 }
743 }
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
763 return CertificateInvalidError{c, NotAuthorizedToSign, ""}
764 }
765
766 if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
767 numIntermediates := len(currentChain) - 1
768 if numIntermediates > c.MaxPathLen {
769 return CertificateInvalidError{c, TooManyIntermediates, ""}
770 }
771 }
772
773 return nil
774 }
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
796
797
798 if len(c.Raw) == 0 {
799 return nil, errNotParsed
800 }
801 if opts.Intermediates != nil {
802 for _, intermediate := range opts.Intermediates.certs {
803 if len(intermediate.Raw) == 0 {
804 return nil, errNotParsed
805 }
806 }
807 }
808
809
810 if opts.Roots == nil && runtime.GOOS == "windows" {
811 return c.systemVerify(&opts)
812 }
813
814 if opts.Roots == nil {
815 opts.Roots = systemRootsPool()
816 if opts.Roots == nil {
817 return nil, SystemRootsError{systemRootsErr}
818 }
819 }
820
821 err = c.isValid(leafCertificate, nil, &opts)
822 if err != nil {
823 return
824 }
825
826 if len(opts.DNSName) > 0 {
827 err = c.VerifyHostname(opts.DNSName)
828 if err != nil {
829 return
830 }
831 }
832
833 requestedKeyUsages := make([]ExtKeyUsage, len(opts.KeyUsages))
834 copy(requestedKeyUsages, opts.KeyUsages)
835 if len(requestedKeyUsages) == 0 {
836 requestedKeyUsages = append(requestedKeyUsages, ExtKeyUsageServerAuth)
837 }
838
839
840 checkEKU := len(c.ExtKeyUsage) > 0
841
842 for _, eku := range requestedKeyUsages {
843 if eku == ExtKeyUsageAny {
844 checkEKU = false
845 break
846 }
847 }
848
849 if checkEKU {
850 NextUsage:
851 for _, eku := range requestedKeyUsages {
852 for _, leafEKU := range c.ExtKeyUsage {
853 if ekuPermittedBy(eku, leafEKU) {
854 continue NextUsage
855 }
856 }
857
858 oid, _ := oidFromExtKeyUsage(eku)
859 return nil, CertificateInvalidError{c, IncompatibleUsage, fmt.Sprintf("%#v", oid)}
860 }
861 }
862
863 var candidateChains [][]*Certificate
864 if opts.Roots.contains(c) {
865 candidateChains = append(candidateChains, []*Certificate{c})
866 } else {
867 if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
868 return nil, err
869 }
870 }
871
872 return candidateChains, nil
873 }
874
875 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
876 n := make([]*Certificate, len(chain)+1)
877 copy(n, chain)
878 n[len(chain)] = cert
879 return n
880 }
881
882 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
883 possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
884 nextRoot:
885 for _, rootNum := range possibleRoots {
886 root := opts.Roots.certs[rootNum]
887
888 for _, cert := range currentChain {
889 if cert.Equal(root) {
890 continue nextRoot
891 }
892 }
893
894 err = root.isValid(rootCertificate, currentChain, opts)
895 if err != nil {
896 continue
897 }
898 chains = append(chains, appendToFreshChain(currentChain, root))
899 }
900
901 possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
902 nextIntermediate:
903 for _, intermediateNum := range possibleIntermediates {
904 intermediate := opts.Intermediates.certs[intermediateNum]
905 for _, cert := range currentChain {
906 if cert.Equal(intermediate) {
907 continue nextIntermediate
908 }
909 }
910 err = intermediate.isValid(intermediateCertificate, currentChain, opts)
911 if err != nil {
912 continue
913 }
914 var childChains [][]*Certificate
915 childChains, ok := cache[intermediateNum]
916 if !ok {
917 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
918 cache[intermediateNum] = childChains
919 }
920 chains = append(chains, childChains...)
921 }
922
923 if len(chains) > 0 {
924 err = nil
925 }
926
927 if len(chains) == 0 && err == nil {
928 hintErr := rootErr
929 hintCert := failedRoot
930 if hintErr == nil {
931 hintErr = intermediateErr
932 hintCert = failedIntermediate
933 }
934 err = UnknownAuthorityError{c, hintErr, hintCert}
935 }
936
937 return
938 }
939
940 func matchHostnames(pattern, host string) bool {
941 host = strings.TrimSuffix(host, ".")
942 pattern = strings.TrimSuffix(pattern, ".")
943
944 if len(pattern) == 0 || len(host) == 0 {
945 return false
946 }
947
948 patternParts := strings.Split(pattern, ".")
949 hostParts := strings.Split(host, ".")
950
951 if len(patternParts) != len(hostParts) {
952 return false
953 }
954
955 for i, patternPart := range patternParts {
956 if i == 0 && patternPart == "*" {
957 continue
958 }
959 if patternPart != hostParts[i] {
960 return false
961 }
962 }
963
964 return true
965 }
966
967
968
969
970 func toLowerCaseASCII(in string) string {
971
972 isAlreadyLowerCase := true
973 for _, c := range in {
974 if c == utf8.RuneError {
975
976
977 isAlreadyLowerCase = false
978 break
979 }
980 if 'A' <= c && c <= 'Z' {
981 isAlreadyLowerCase = false
982 break
983 }
984 }
985
986 if isAlreadyLowerCase {
987 return in
988 }
989
990 out := []byte(in)
991 for i, c := range out {
992 if 'A' <= c && c <= 'Z' {
993 out[i] += 'a' - 'A'
994 }
995 }
996 return string(out)
997 }
998
999
1000
1001 func (c *Certificate) VerifyHostname(h string) error {
1002
1003 candidateIP := h
1004 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
1005 candidateIP = h[1 : len(h)-1]
1006 }
1007 if ip := net.ParseIP(candidateIP); ip != nil {
1008
1009
1010 for _, candidate := range c.IPAddresses {
1011 if ip.Equal(candidate) {
1012 return nil
1013 }
1014 }
1015 return HostnameError{c, candidateIP}
1016 }
1017
1018 lowered := toLowerCaseASCII(h)
1019
1020 if c.hasSANExtension() {
1021 for _, match := range c.DNSNames {
1022 if matchHostnames(toLowerCaseASCII(match), lowered) {
1023 return nil
1024 }
1025 }
1026
1027 } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
1028 return nil
1029 }
1030
1031 return HostnameError{c, h}
1032 }
1033
View as plain text