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