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