1
2
3
4
5 package x509
6
7 import (
8 "bytes"
9 "crypto"
10 "crypto/x509/pkix"
11 "errors"
12 "fmt"
13 "iter"
14 "maps"
15 "net"
16 "net/netip"
17 "net/url"
18 "reflect"
19 "runtime"
20 "slices"
21 "strings"
22 "time"
23 "unicode/utf8"
24 )
25
26 type InvalidReason int
27
28 const (
29
30
31 NotAuthorizedToSign InvalidReason = iota
32
33
34 Expired
35
36
37
38 CANotAuthorizedForThisName
39
40
41 TooManyIntermediates
42
43
44 IncompatibleUsage
45
46
47 NameMismatch
48
49 NameConstraintsWithoutSANs
50
51
52
53 UnconstrainedName
54
55
56
57
58
59 TooManyConstraints
60
61
62 CANotAuthorizedForExtKeyUsage
63
64 NoValidChains
65 )
66
67
68
69 type CertificateInvalidError struct {
70 Cert *Certificate
71 Reason InvalidReason
72 Detail string
73 }
74
75 func (e CertificateInvalidError) Error() string {
76 switch e.Reason {
77 case NotAuthorizedToSign:
78 return "x509: certificate is not authorized to sign other certificates"
79 case Expired:
80 return "x509: certificate has expired or is not yet valid: " + e.Detail
81 case CANotAuthorizedForThisName:
82 return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail
83 case CANotAuthorizedForExtKeyUsage:
84 return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail
85 case TooManyIntermediates:
86 return "x509: too many intermediates for path length constraint"
87 case IncompatibleUsage:
88 return "x509: certificate specifies an incompatible key usage"
89 case NameMismatch:
90 return "x509: issuer name does not match subject from issuing certificate"
91 case NameConstraintsWithoutSANs:
92 return "x509: issuer has name constraints but leaf doesn't have a SAN extension"
93 case UnconstrainedName:
94 return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail
95 case NoValidChains:
96 s := "x509: no valid chains built"
97 if e.Detail != "" {
98 s = fmt.Sprintf("%s: %s", s, e.Detail)
99 }
100 return s
101 }
102 return "x509: unknown error"
103 }
104
105
106
107 type HostnameError struct {
108 Certificate *Certificate
109 Host string
110 }
111
112 func (h HostnameError) Error() string {
113 c := h.Certificate
114
115 if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) {
116 return "x509: certificate relies on legacy Common Name field, use SANs instead"
117 }
118
119 var valid string
120 if ip := net.ParseIP(h.Host); ip != nil {
121
122 if len(c.IPAddresses) == 0 {
123 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
124 }
125 for _, san := range c.IPAddresses {
126 if len(valid) > 0 {
127 valid += ", "
128 }
129 valid += san.String()
130 }
131 } else {
132 valid = strings.Join(c.DNSNames, ", ")
133 }
134
135 if len(valid) == 0 {
136 return "x509: certificate is not valid for any names, but wanted to match " + h.Host
137 }
138 return "x509: certificate is valid for " + valid + ", not " + h.Host
139 }
140
141
142 type UnknownAuthorityError struct {
143 Cert *Certificate
144
145
146 hintErr error
147
148
149 hintCert *Certificate
150 }
151
152 func (e UnknownAuthorityError) Error() string {
153 s := "x509: certificate signed by unknown authority"
154 if e.hintErr != nil {
155 certName := e.hintCert.Subject.CommonName
156 if len(certName) == 0 {
157 if len(e.hintCert.Subject.Organization) > 0 {
158 certName = e.hintCert.Subject.Organization[0]
159 } else {
160 certName = "serial:" + e.hintCert.SerialNumber.String()
161 }
162 }
163 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
164 }
165 return s
166 }
167
168
169 type SystemRootsError struct {
170 Err error
171 }
172
173 func (se SystemRootsError) Error() string {
174 msg := "x509: failed to load system roots and no roots provided"
175 if se.Err != nil {
176 return msg + "; " + se.Err.Error()
177 }
178 return msg
179 }
180
181 func (se SystemRootsError) Unwrap() error { return se.Err }
182
183
184
185 var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
186
187
188 type VerifyOptions struct {
189
190
191 DNSName string
192
193
194
195
196 Intermediates *CertPool
197
198
199 Roots *CertPool
200
201
202
203 CurrentTime time.Time
204
205
206
207
208 KeyUsages []ExtKeyUsage
209
210
211
212
213
214
215 MaxConstraintComparisions int
216
217
218
219
220 CertificatePolicies []OID
221
222
223
224
225
226
227
228 inhibitPolicyMapping bool
229
230
231
232 requireExplicitPolicy bool
233
234
235
236 inhibitAnyPolicy bool
237 }
238
239 const (
240 leafCertificate = iota
241 intermediateCertificate
242 rootCertificate
243 )
244
245
246
247
248 type rfc2821Mailbox struct {
249 local, domain string
250 }
251
252
253
254
255
256 func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
257 if len(in) == 0 {
258 return mailbox, false
259 }
260
261 localPartBytes := make([]byte, 0, len(in)/2)
262
263 if in[0] == '"' {
264
265
266
267
268
269
270
271
272
273
274 in = in[1:]
275 QuotedString:
276 for {
277 if len(in) == 0 {
278 return mailbox, false
279 }
280 c := in[0]
281 in = in[1:]
282
283 switch {
284 case c == '"':
285 break QuotedString
286
287 case c == '\\':
288
289 if len(in) == 0 {
290 return mailbox, false
291 }
292 if in[0] == 11 ||
293 in[0] == 12 ||
294 (1 <= in[0] && in[0] <= 9) ||
295 (14 <= in[0] && in[0] <= 127) {
296 localPartBytes = append(localPartBytes, in[0])
297 in = in[1:]
298 } else {
299 return mailbox, false
300 }
301
302 case c == 11 ||
303 c == 12 ||
304
305
306
307
308
309 c == 32 ||
310 c == 33 ||
311 c == 127 ||
312 (1 <= c && c <= 8) ||
313 (14 <= c && c <= 31) ||
314 (35 <= c && c <= 91) ||
315 (93 <= c && c <= 126):
316
317 localPartBytes = append(localPartBytes, c)
318
319 default:
320 return mailbox, false
321 }
322 }
323 } else {
324
325 NextChar:
326 for len(in) > 0 {
327
328 c := in[0]
329
330 switch {
331 case c == '\\':
332
333
334
335
336
337 in = in[1:]
338 if len(in) == 0 {
339 return mailbox, false
340 }
341 fallthrough
342
343 case ('0' <= c && c <= '9') ||
344 ('a' <= c && c <= 'z') ||
345 ('A' <= c && c <= 'Z') ||
346 c == '!' || c == '#' || c == '$' || c == '%' ||
347 c == '&' || c == '\'' || c == '*' || c == '+' ||
348 c == '-' || c == '/' || c == '=' || c == '?' ||
349 c == '^' || c == '_' || c == '`' || c == '{' ||
350 c == '|' || c == '}' || c == '~' || c == '.':
351 localPartBytes = append(localPartBytes, in[0])
352 in = in[1:]
353
354 default:
355 break NextChar
356 }
357 }
358
359 if len(localPartBytes) == 0 {
360 return mailbox, false
361 }
362
363
364
365
366
367 twoDots := []byte{'.', '.'}
368 if localPartBytes[0] == '.' ||
369 localPartBytes[len(localPartBytes)-1] == '.' ||
370 bytes.Contains(localPartBytes, twoDots) {
371 return mailbox, false
372 }
373 }
374
375 if len(in) == 0 || in[0] != '@' {
376 return mailbox, false
377 }
378 in = in[1:]
379
380
381
382
383 if _, ok := domainToReverseLabels(in); !ok {
384 return mailbox, false
385 }
386
387 mailbox.local = string(localPartBytes)
388 mailbox.domain = in
389 return mailbox, true
390 }
391
392
393
394 func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
395 reverseLabels = make([]string, 0, strings.Count(domain, ".")+1)
396 for len(domain) > 0 {
397 if i := strings.LastIndexByte(domain, '.'); i == -1 {
398 reverseLabels = append(reverseLabels, domain)
399 domain = ""
400 } else {
401 reverseLabels = append(reverseLabels, domain[i+1:])
402 domain = domain[:i]
403 if i == 0 {
404
405
406 reverseLabels = append(reverseLabels, "")
407 }
408 }
409 }
410
411 if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
412
413 return nil, false
414 }
415
416 for _, label := range reverseLabels {
417 if len(label) == 0 {
418
419 return nil, false
420 }
421
422 for _, c := range label {
423 if c < 33 || c > 126 {
424
425 return nil, false
426 }
427 }
428 }
429
430 return reverseLabels, true
431 }
432
433 func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) {
434
435
436 if strings.Contains(constraint, "@") {
437 constraintMailbox, ok := parseRFC2821Mailbox(constraint)
438 if !ok {
439 return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint)
440 }
441 return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil
442 }
443
444
445
446 return matchDomainConstraint(mailbox.domain, constraint, reversedDomainsCache, reversedConstraintsCache)
447 }
448
449 func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) {
450
451
452
453
454
455
456
457
458 host := uri.Host
459 if len(host) == 0 {
460 return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String())
461 }
462
463 if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") {
464 var err error
465 host, _, err = net.SplitHostPort(uri.Host)
466 if err != nil {
467 return false, err
468 }
469 }
470
471
472
473
474 if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) {
475 return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
476 }
477
478 return matchDomainConstraint(host, constraint, reversedDomainsCache, reversedConstraintsCache)
479 }
480
481 func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) {
482 if len(ip) != len(constraint.IP) {
483 return false, nil
484 }
485
486 for i := range ip {
487 if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask {
488 return false, nil
489 }
490 }
491
492 return true, nil
493 }
494
495 func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) {
496
497
498 if len(constraint) == 0 {
499 return true, nil
500 }
501
502 domainLabels, found := reversedDomainsCache[domain]
503 if !found {
504 var ok bool
505 domainLabels, ok = domainToReverseLabels(domain)
506 if !ok {
507 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain)
508 }
509 reversedDomainsCache[domain] = domainLabels
510 }
511
512
513
514
515
516
517 mustHaveSubdomains := false
518 if constraint[0] == '.' {
519 mustHaveSubdomains = true
520 constraint = constraint[1:]
521 }
522
523 constraintLabels, found := reversedConstraintsCache[constraint]
524 if !found {
525 var ok bool
526 constraintLabels, ok = domainToReverseLabels(constraint)
527 if !ok {
528 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint)
529 }
530 reversedConstraintsCache[constraint] = constraintLabels
531 }
532
533 if len(domainLabels) < len(constraintLabels) ||
534 (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) {
535 return false, nil
536 }
537
538 for i, constraintLabel := range constraintLabels {
539 if !strings.EqualFold(constraintLabel, domainLabels[i]) {
540 return false, nil
541 }
542 }
543
544 return true, nil
545 }
546
547
548
549
550
551
552 func (c *Certificate) checkNameConstraints(count *int,
553 maxConstraintComparisons int,
554 nameType string,
555 name string,
556 parsedName any,
557 match func(parsedName, constraint any) (match bool, err error),
558 permitted, excluded any) error {
559
560 excludedValue := reflect.ValueOf(excluded)
561
562 *count += excludedValue.Len()
563 if *count > maxConstraintComparisons {
564 return CertificateInvalidError{c, TooManyConstraints, ""}
565 }
566
567 for i := 0; i < excludedValue.Len(); i++ {
568 constraint := excludedValue.Index(i).Interface()
569 match, err := match(parsedName, constraint)
570 if err != nil {
571 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
572 }
573
574 if match {
575 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)}
576 }
577 }
578
579 permittedValue := reflect.ValueOf(permitted)
580
581 *count += permittedValue.Len()
582 if *count > maxConstraintComparisons {
583 return CertificateInvalidError{c, TooManyConstraints, ""}
584 }
585
586 ok := true
587 for i := 0; i < permittedValue.Len(); i++ {
588 constraint := permittedValue.Index(i).Interface()
589
590 var err error
591 if ok, err = match(parsedName, constraint); err != nil {
592 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
593 }
594
595 if ok {
596 break
597 }
598 }
599
600 if !ok {
601 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)}
602 }
603
604 return nil
605 }
606
607
608
609 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
610 if len(c.UnhandledCriticalExtensions) > 0 {
611 return UnhandledCriticalExtension{}
612 }
613
614 if len(currentChain) > 0 {
615 child := currentChain[len(currentChain)-1]
616 if !bytes.Equal(child.RawIssuer, c.RawSubject) {
617 return CertificateInvalidError{c, NameMismatch, ""}
618 }
619 }
620
621 now := opts.CurrentTime
622 if now.IsZero() {
623 now = time.Now()
624 }
625 if now.Before(c.NotBefore) {
626 return CertificateInvalidError{
627 Cert: c,
628 Reason: Expired,
629 Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)),
630 }
631 } else if now.After(c.NotAfter) {
632 return CertificateInvalidError{
633 Cert: c,
634 Reason: Expired,
635 Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)),
636 }
637 }
638
639 if (certType == intermediateCertificate || certType == rootCertificate) && len(currentChain) == 0 {
640 return errors.New("x509: internal error: empty chain when appending CA cert")
641 }
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
661 return CertificateInvalidError{c, NotAuthorizedToSign, ""}
662 }
663
664 if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
665 numIntermediates := len(currentChain) - 1
666 if numIntermediates > c.MaxPathLen {
667 return CertificateInvalidError{c, TooManyIntermediates, ""}
668 }
669 }
670
671 return nil
672 }
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706 func (c *Certificate) Verify(opts VerifyOptions) ([][]*Certificate, error) {
707
708
709 if len(c.Raw) == 0 {
710 return nil, errNotParsed
711 }
712 for i := 0; i < opts.Intermediates.len(); i++ {
713 c, _, err := opts.Intermediates.cert(i)
714 if err != nil {
715 return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err)
716 }
717 if len(c.Raw) == 0 {
718 return nil, errNotParsed
719 }
720 }
721
722
723 if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
724
725
726 systemPool := systemRootsPool()
727 if opts.Roots == nil && (systemPool == nil || systemPool.systemPool) {
728 return c.systemVerify(&opts)
729 }
730 if opts.Roots != nil && opts.Roots.systemPool {
731 platformChains, err := c.systemVerify(&opts)
732
733
734
735 if err == nil || opts.Roots.len() == 0 {
736 return platformChains, err
737 }
738 }
739 }
740
741 if opts.Roots == nil {
742 opts.Roots = systemRootsPool()
743 if opts.Roots == nil {
744 return nil, SystemRootsError{systemRootsErr}
745 }
746 }
747
748 err := c.isValid(leafCertificate, nil, &opts)
749 if err != nil {
750 return nil, err
751 }
752
753 if len(opts.DNSName) > 0 {
754 err = c.VerifyHostname(opts.DNSName)
755 if err != nil {
756 return nil, err
757 }
758 }
759
760 var candidateChains [][]*Certificate
761 if opts.Roots.contains(c) {
762 candidateChains = [][]*Certificate{{c}}
763 } else {
764 candidateChains, err = c.buildChains([]*Certificate{c}, nil, &opts)
765 if err != nil {
766 return nil, err
767 }
768 }
769
770 anyKeyUsage := false
771 for _, eku := range opts.KeyUsages {
772 if eku == ExtKeyUsageAny {
773
774 anyKeyUsage = true
775 break
776 }
777 }
778
779 if len(opts.KeyUsages) == 0 {
780 opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
781 }
782
783 var invalidPoliciesChains int
784 var incompatibleKeyUsageChains int
785 var constraintsHintErr error
786 candidateChains = slices.DeleteFunc(candidateChains, func(chain []*Certificate) bool {
787 if !policiesValid(chain, opts) {
788 invalidPoliciesChains++
789 return true
790 }
791
792
793 if !anyKeyUsage && !checkChainForKeyUsage(chain, opts.KeyUsages) {
794 incompatibleKeyUsageChains++
795 return true
796 }
797 if err := checkChainConstraints(chain, opts); err != nil {
798 if constraintsHintErr == nil {
799 constraintsHintErr = err
800 }
801 return true
802 }
803 return false
804 })
805
806 if len(candidateChains) == 0 {
807 if constraintsHintErr != nil {
808 return nil, constraintsHintErr
809 }
810 var details []string
811 if incompatibleKeyUsageChains > 0 {
812 if invalidPoliciesChains == 0 {
813 return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
814 }
815 details = append(details, fmt.Sprintf("%d candidate chains with incompatible key usage", incompatibleKeyUsageChains))
816 }
817 if invalidPoliciesChains > 0 {
818 details = append(details, fmt.Sprintf("%d candidate chains with invalid policies", invalidPoliciesChains))
819 }
820 err = CertificateInvalidError{c, NoValidChains, strings.Join(details, ", ")}
821 return nil, err
822 }
823
824 return candidateChains, nil
825 }
826
827 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
828 n := make([]*Certificate, len(chain)+1)
829 copy(n, chain)
830 n[len(chain)] = cert
831 return n
832 }
833
834
835
836
837
838
839 func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
840 type pubKeyEqual interface {
841 Equal(crypto.PublicKey) bool
842 }
843
844 var candidateSAN *pkix.Extension
845 for _, ext := range candidate.Extensions {
846 if ext.Id.Equal(oidExtensionSubjectAltName) {
847 candidateSAN = &ext
848 break
849 }
850 }
851
852 for _, cert := range chain {
853 if !bytes.Equal(candidate.RawSubject, cert.RawSubject) {
854 continue
855 }
856
857
858
859 if !bytes.Equal(candidate.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
860 continue
861 }
862 var certSAN *pkix.Extension
863 for _, ext := range cert.Extensions {
864 if ext.Id.Equal(oidExtensionSubjectAltName) {
865 certSAN = &ext
866 break
867 }
868 }
869 if candidateSAN == nil && certSAN == nil {
870 return true
871 } else if candidateSAN == nil || certSAN == nil {
872 return false
873 }
874 if bytes.Equal(candidateSAN.Value, certSAN.Value) {
875 return true
876 }
877 }
878 return false
879 }
880
881
882
883
884
885 const maxChainSignatureChecks = 100
886
887 func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
888 var (
889 hintErr error
890 hintCert *Certificate
891 )
892
893 considerCandidate := func(certType int, candidate potentialParent) {
894 if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) {
895 return
896 }
897
898 if sigChecks == nil {
899 sigChecks = new(int)
900 }
901 *sigChecks++
902 if *sigChecks > maxChainSignatureChecks {
903 err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
904 return
905 }
906
907 if err := c.CheckSignatureFrom(candidate.cert); err != nil {
908 if hintErr == nil {
909 hintErr = err
910 hintCert = candidate.cert
911 }
912 return
913 }
914
915 err = candidate.cert.isValid(certType, currentChain, opts)
916 if err != nil {
917 if hintErr == nil {
918 hintErr = err
919 hintCert = candidate.cert
920 }
921 return
922 }
923
924 if candidate.constraint != nil {
925 if err := candidate.constraint(currentChain); err != nil {
926 if hintErr == nil {
927 hintErr = err
928 hintCert = candidate.cert
929 }
930 return
931 }
932 }
933
934 switch certType {
935 case rootCertificate:
936 chains = append(chains, appendToFreshChain(currentChain, candidate.cert))
937 case intermediateCertificate:
938 var childChains [][]*Certificate
939 childChains, err = candidate.cert.buildChains(appendToFreshChain(currentChain, candidate.cert), sigChecks, opts)
940 chains = append(chains, childChains...)
941 }
942 }
943
944 for _, root := range opts.Roots.findPotentialParents(c) {
945 considerCandidate(rootCertificate, root)
946 }
947 for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
948 considerCandidate(intermediateCertificate, intermediate)
949 }
950
951 if len(chains) > 0 {
952 err = nil
953 }
954 if len(chains) == 0 && err == nil {
955 err = UnknownAuthorityError{c, hintErr, hintCert}
956 }
957
958 return
959 }
960
961 func validHostnamePattern(host string) bool { return validHostname(host, true) }
962 func validHostnameInput(host string) bool { return validHostname(host, false) }
963
964
965
966
967 func validHostname(host string, isPattern bool) bool {
968 if !isPattern {
969 host = strings.TrimSuffix(host, ".")
970 }
971 if len(host) == 0 {
972 return false
973 }
974 if host == "*" {
975
976
977 return false
978 }
979
980 for i, part := range strings.Split(host, ".") {
981 if part == "" {
982
983 return false
984 }
985 if isPattern && i == 0 && part == "*" {
986
987
988
989 continue
990 }
991 for j, c := range part {
992 if 'a' <= c && c <= 'z' {
993 continue
994 }
995 if '0' <= c && c <= '9' {
996 continue
997 }
998 if 'A' <= c && c <= 'Z' {
999 continue
1000 }
1001 if c == '-' && j != 0 {
1002 continue
1003 }
1004 if c == '_' {
1005
1006
1007 continue
1008 }
1009 return false
1010 }
1011 }
1012
1013 return true
1014 }
1015
1016 func matchExactly(hostA, hostB string) bool {
1017 if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
1018 return false
1019 }
1020 return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
1021 }
1022
1023 func matchHostnames(pattern, host string) bool {
1024 pattern = toLowerCaseASCII(pattern)
1025 host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
1026
1027 if len(pattern) == 0 || len(host) == 0 {
1028 return false
1029 }
1030
1031 patternParts := strings.Split(pattern, ".")
1032 hostParts := strings.Split(host, ".")
1033
1034 if len(patternParts) != len(hostParts) {
1035 return false
1036 }
1037
1038 for i, patternPart := range patternParts {
1039 if i == 0 && patternPart == "*" {
1040 continue
1041 }
1042 if patternPart != hostParts[i] {
1043 return false
1044 }
1045 }
1046
1047 return true
1048 }
1049
1050
1051
1052
1053 func toLowerCaseASCII(in string) string {
1054
1055 isAlreadyLowerCase := true
1056 for _, c := range in {
1057 if c == utf8.RuneError {
1058
1059
1060 isAlreadyLowerCase = false
1061 break
1062 }
1063 if 'A' <= c && c <= 'Z' {
1064 isAlreadyLowerCase = false
1065 break
1066 }
1067 }
1068
1069 if isAlreadyLowerCase {
1070 return in
1071 }
1072
1073 out := []byte(in)
1074 for i, c := range out {
1075 if 'A' <= c && c <= 'Z' {
1076 out[i] += 'a' - 'A'
1077 }
1078 }
1079 return string(out)
1080 }
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 func (c *Certificate) VerifyHostname(h string) error {
1092
1093 candidateIP := h
1094 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
1095 candidateIP = h[1 : len(h)-1]
1096 }
1097 if ip := net.ParseIP(candidateIP); ip != nil {
1098
1099
1100 for _, candidate := range c.IPAddresses {
1101 if ip.Equal(candidate) {
1102 return nil
1103 }
1104 }
1105 return HostnameError{c, candidateIP}
1106 }
1107
1108 candidateName := toLowerCaseASCII(h)
1109 validCandidateName := validHostnameInput(candidateName)
1110
1111 for _, match := range c.DNSNames {
1112
1113
1114
1115
1116
1117 if validCandidateName && validHostnamePattern(match) {
1118 if matchHostnames(match, candidateName) {
1119 return nil
1120 }
1121 } else {
1122 if matchExactly(match, candidateName) {
1123 return nil
1124 }
1125 }
1126 }
1127
1128 return HostnameError{c, h}
1129 }
1130
1131 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
1132 usages := make([]ExtKeyUsage, len(keyUsages))
1133 copy(usages, keyUsages)
1134
1135 if len(chain) == 0 {
1136 return false
1137 }
1138
1139 usagesRemaining := len(usages)
1140
1141
1142
1143
1144
1145 NextCert:
1146 for i := len(chain) - 1; i >= 0; i-- {
1147 cert := chain[i]
1148 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
1149
1150 continue
1151 }
1152
1153 for _, usage := range cert.ExtKeyUsage {
1154 if usage == ExtKeyUsageAny {
1155
1156 continue NextCert
1157 }
1158 }
1159
1160 const invalidUsage ExtKeyUsage = -1
1161
1162 NextRequestedUsage:
1163 for i, requestedUsage := range usages {
1164 if requestedUsage == invalidUsage {
1165 continue
1166 }
1167
1168 for _, usage := range cert.ExtKeyUsage {
1169 if requestedUsage == usage {
1170 continue NextRequestedUsage
1171 }
1172 }
1173
1174 usages[i] = invalidUsage
1175 usagesRemaining--
1176 if usagesRemaining == 0 {
1177 return false
1178 }
1179 }
1180 }
1181
1182 return true
1183 }
1184
1185 func checkChainConstraints(chain []*Certificate, opts VerifyOptions) error {
1186 maxConstraintComparisons := opts.MaxConstraintComparisions
1187 if maxConstraintComparisons == 0 {
1188 maxConstraintComparisons = 250000
1189 }
1190 comparisonCount := 0
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202 reversedDomainsCache := map[string][]string{}
1203 reversedConstraintsCache := map[string][]string{}
1204
1205 for i, c := range chain {
1206 if !c.hasNameConstraints() {
1207 continue
1208 }
1209 for _, sanCert := range chain[:i] {
1210 if !sanCert.hasSANExtension() {
1211 continue
1212 }
1213 err := forEachSAN(sanCert.getSANExtension(), func(tag int, data []byte) error {
1214 switch tag {
1215 case nameTypeEmail:
1216 name := string(data)
1217 mailbox, ok := parseRFC2821Mailbox(name)
1218 if !ok {
1219 return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
1220 }
1221
1222 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
1223 func(parsedName, constraint any) (bool, error) {
1224 return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), reversedDomainsCache, reversedConstraintsCache)
1225 }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil {
1226 return err
1227 }
1228
1229 case nameTypeDNS:
1230 name := string(data)
1231 if !domainNameValid(name, false) {
1232 return fmt.Errorf("x509: cannot parse dnsName %q", name)
1233 }
1234
1235 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
1236 func(parsedName, constraint any) (bool, error) {
1237 return matchDomainConstraint(parsedName.(string), constraint.(string), reversedDomainsCache, reversedConstraintsCache)
1238 }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil {
1239 return err
1240 }
1241
1242 case nameTypeURI:
1243 name := string(data)
1244 uri, err := url.Parse(name)
1245 if err != nil {
1246 return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name)
1247 }
1248
1249 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri,
1250 func(parsedName, constraint any) (bool, error) {
1251 return matchURIConstraint(parsedName.(*url.URL), constraint.(string), reversedDomainsCache, reversedConstraintsCache)
1252 }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil {
1253 return err
1254 }
1255
1256 case nameTypeIP:
1257 ip := net.IP(data)
1258 if l := len(ip); l != net.IPv4len && l != net.IPv6len {
1259 return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data)
1260 }
1261
1262 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip,
1263 func(parsedName, constraint any) (bool, error) {
1264 return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet))
1265 }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil {
1266 return err
1267 }
1268
1269 default:
1270
1271 }
1272
1273 return nil
1274 })
1275
1276 if err != nil {
1277 return err
1278 }
1279 }
1280 }
1281
1282 return nil
1283 }
1284
1285 func mustNewOIDFromInts(ints []uint64) OID {
1286 oid, err := OIDFromInts(ints)
1287 if err != nil {
1288 panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err))
1289 }
1290 return oid
1291 }
1292
1293 type policyGraphNode struct {
1294 validPolicy OID
1295 expectedPolicySet []OID
1296
1297
1298 parents map[*policyGraphNode]bool
1299 children map[*policyGraphNode]bool
1300 }
1301
1302 func newPolicyGraphNode(valid OID, parents []*policyGraphNode) *policyGraphNode {
1303 n := &policyGraphNode{
1304 validPolicy: valid,
1305 expectedPolicySet: []OID{valid},
1306 children: map[*policyGraphNode]bool{},
1307 parents: map[*policyGraphNode]bool{},
1308 }
1309 for _, p := range parents {
1310 p.children[n] = true
1311 n.parents[p] = true
1312 }
1313 return n
1314 }
1315
1316 type policyGraph struct {
1317 strata []map[string]*policyGraphNode
1318
1319 parentIndex map[string][]*policyGraphNode
1320 depth int
1321 }
1322
1323 var anyPolicyOID = mustNewOIDFromInts([]uint64{2, 5, 29, 32, 0})
1324
1325 func newPolicyGraph() *policyGraph {
1326 root := policyGraphNode{
1327 validPolicy: anyPolicyOID,
1328 expectedPolicySet: []OID{anyPolicyOID},
1329 children: map[*policyGraphNode]bool{},
1330 parents: map[*policyGraphNode]bool{},
1331 }
1332 return &policyGraph{
1333 depth: 0,
1334 strata: []map[string]*policyGraphNode{{string(anyPolicyOID.der): &root}},
1335 }
1336 }
1337
1338 func (pg *policyGraph) insert(n *policyGraphNode) {
1339 pg.strata[pg.depth][string(n.validPolicy.der)] = n
1340 }
1341
1342 func (pg *policyGraph) parentsWithExpected(expected OID) []*policyGraphNode {
1343 if pg.depth == 0 {
1344 return nil
1345 }
1346 return pg.parentIndex[string(expected.der)]
1347 }
1348
1349 func (pg *policyGraph) parentWithAnyPolicy() *policyGraphNode {
1350 if pg.depth == 0 {
1351 return nil
1352 }
1353 return pg.strata[pg.depth-1][string(anyPolicyOID.der)]
1354 }
1355
1356 func (pg *policyGraph) parents() iter.Seq[*policyGraphNode] {
1357 if pg.depth == 0 {
1358 return nil
1359 }
1360 return maps.Values(pg.strata[pg.depth-1])
1361 }
1362
1363 func (pg *policyGraph) leaves() map[string]*policyGraphNode {
1364 return pg.strata[pg.depth]
1365 }
1366
1367 func (pg *policyGraph) leafWithPolicy(policy OID) *policyGraphNode {
1368 return pg.strata[pg.depth][string(policy.der)]
1369 }
1370
1371 func (pg *policyGraph) deleteLeaf(policy OID) {
1372 n := pg.strata[pg.depth][string(policy.der)]
1373 if n == nil {
1374 return
1375 }
1376 for p := range n.parents {
1377 delete(p.children, n)
1378 }
1379 for c := range n.children {
1380 delete(c.parents, n)
1381 }
1382 delete(pg.strata[pg.depth], string(policy.der))
1383 }
1384
1385 func (pg *policyGraph) validPolicyNodes() []*policyGraphNode {
1386 var validNodes []*policyGraphNode
1387 for i := pg.depth; i >= 0; i-- {
1388 for _, n := range pg.strata[i] {
1389 if n.validPolicy.Equal(anyPolicyOID) {
1390 continue
1391 }
1392
1393 if len(n.parents) == 1 {
1394 for p := range n.parents {
1395 if p.validPolicy.Equal(anyPolicyOID) {
1396 validNodes = append(validNodes, n)
1397 }
1398 }
1399 }
1400 }
1401 }
1402 return validNodes
1403 }
1404
1405 func (pg *policyGraph) prune() {
1406 for i := pg.depth - 1; i > 0; i-- {
1407 for _, n := range pg.strata[i] {
1408 if len(n.children) == 0 {
1409 for p := range n.parents {
1410 delete(p.children, n)
1411 }
1412 delete(pg.strata[i], string(n.validPolicy.der))
1413 }
1414 }
1415 }
1416 }
1417
1418 func (pg *policyGraph) incrDepth() {
1419 pg.parentIndex = map[string][]*policyGraphNode{}
1420 for _, n := range pg.strata[pg.depth] {
1421 for _, e := range n.expectedPolicySet {
1422 pg.parentIndex[string(e.der)] = append(pg.parentIndex[string(e.der)], n)
1423 }
1424 }
1425
1426 pg.depth++
1427 pg.strata = append(pg.strata, map[string]*policyGraphNode{})
1428 }
1429
1430 func policiesValid(chain []*Certificate, opts VerifyOptions) bool {
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441 if len(chain) == 1 {
1442 return true
1443 }
1444
1445
1446 n := len(chain) - 1
1447
1448 pg := newPolicyGraph()
1449 var inhibitAnyPolicy, explicitPolicy, policyMapping int
1450 if !opts.inhibitAnyPolicy {
1451 inhibitAnyPolicy = n + 1
1452 }
1453 if !opts.requireExplicitPolicy {
1454 explicitPolicy = n + 1
1455 }
1456 if !opts.inhibitPolicyMapping {
1457 policyMapping = n + 1
1458 }
1459
1460 initialUserPolicySet := map[string]bool{}
1461 for _, p := range opts.CertificatePolicies {
1462 initialUserPolicySet[string(p.der)] = true
1463 }
1464
1465
1466 if len(initialUserPolicySet) == 0 {
1467 initialUserPolicySet[string(anyPolicyOID.der)] = true
1468 }
1469
1470 for i := n - 1; i >= 0; i-- {
1471 cert := chain[i]
1472
1473 isSelfSigned := bytes.Equal(cert.RawIssuer, cert.RawSubject)
1474
1475
1476 if len(cert.Policies) == 0 {
1477 pg = nil
1478 }
1479
1480
1481 if explicitPolicy == 0 && pg == nil {
1482 return false
1483 }
1484
1485 if pg != nil {
1486 pg.incrDepth()
1487
1488 policies := map[string]bool{}
1489
1490
1491 for _, policy := range cert.Policies {
1492 policies[string(policy.der)] = true
1493
1494 if policy.Equal(anyPolicyOID) {
1495 continue
1496 }
1497
1498
1499 parents := pg.parentsWithExpected(policy)
1500 if len(parents) == 0 {
1501
1502 if anyParent := pg.parentWithAnyPolicy(); anyParent != nil {
1503 parents = []*policyGraphNode{anyParent}
1504 }
1505 }
1506 if len(parents) > 0 {
1507 pg.insert(newPolicyGraphNode(policy, parents))
1508 }
1509 }
1510
1511
1512
1513
1514
1515
1516 if policies[string(anyPolicyOID.der)] && (inhibitAnyPolicy > 0 || (n-i < n && isSelfSigned)) {
1517 missing := map[string][]*policyGraphNode{}
1518 leaves := pg.leaves()
1519 for p := range pg.parents() {
1520 for _, expected := range p.expectedPolicySet {
1521 if leaves[string(expected.der)] == nil {
1522 missing[string(expected.der)] = append(missing[string(expected.der)], p)
1523 }
1524 }
1525 }
1526
1527 for oidStr, parents := range missing {
1528 pg.insert(newPolicyGraphNode(OID{der: []byte(oidStr)}, parents))
1529 }
1530 }
1531
1532
1533 pg.prune()
1534
1535 if i != 0 {
1536
1537 if len(cert.PolicyMappings) > 0 {
1538
1539 mappings := map[string][]OID{}
1540
1541 for _, mapping := range cert.PolicyMappings {
1542 if policyMapping > 0 {
1543 if mapping.IssuerDomainPolicy.Equal(anyPolicyOID) || mapping.SubjectDomainPolicy.Equal(anyPolicyOID) {
1544
1545 return false
1546 }
1547 mappings[string(mapping.IssuerDomainPolicy.der)] = append(mappings[string(mapping.IssuerDomainPolicy.der)], mapping.SubjectDomainPolicy)
1548 } else {
1549
1550 pg.deleteLeaf(mapping.IssuerDomainPolicy)
1551
1552
1553 pg.prune()
1554 }
1555 }
1556
1557 for issuerStr, subjectPolicies := range mappings {
1558
1559 if matching := pg.leafWithPolicy(OID{der: []byte(issuerStr)}); matching != nil {
1560 matching.expectedPolicySet = subjectPolicies
1561 } else if matching := pg.leafWithPolicy(anyPolicyOID); matching != nil {
1562
1563 n := newPolicyGraphNode(OID{der: []byte(issuerStr)}, []*policyGraphNode{matching})
1564 n.expectedPolicySet = subjectPolicies
1565 pg.insert(n)
1566 }
1567 }
1568 }
1569 }
1570 }
1571
1572 if i != 0 {
1573
1574 if !isSelfSigned {
1575 if explicitPolicy > 0 {
1576 explicitPolicy--
1577 }
1578 if policyMapping > 0 {
1579 policyMapping--
1580 }
1581 if inhibitAnyPolicy > 0 {
1582 inhibitAnyPolicy--
1583 }
1584 }
1585
1586
1587 if (cert.RequireExplicitPolicy > 0 || cert.RequireExplicitPolicyZero) && cert.RequireExplicitPolicy < explicitPolicy {
1588 explicitPolicy = cert.RequireExplicitPolicy
1589 }
1590 if (cert.InhibitPolicyMapping > 0 || cert.InhibitPolicyMappingZero) && cert.InhibitPolicyMapping < policyMapping {
1591 policyMapping = cert.InhibitPolicyMapping
1592 }
1593
1594 if (cert.InhibitAnyPolicy > 0 || cert.InhibitAnyPolicyZero) && cert.InhibitAnyPolicy < inhibitAnyPolicy {
1595 inhibitAnyPolicy = cert.InhibitAnyPolicy
1596 }
1597 }
1598 }
1599
1600
1601 if explicitPolicy > 0 {
1602 explicitPolicy--
1603 }
1604
1605
1606 if chain[0].RequireExplicitPolicyZero {
1607 explicitPolicy = 0
1608 }
1609
1610
1611 var validPolicyNodeSet []*policyGraphNode
1612
1613 if pg != nil {
1614 validPolicyNodeSet = pg.validPolicyNodes()
1615
1616 if currentAny := pg.leafWithPolicy(anyPolicyOID); currentAny != nil {
1617 validPolicyNodeSet = append(validPolicyNodeSet, currentAny)
1618 }
1619 }
1620
1621
1622 authorityConstrainedPolicySet := map[string]bool{}
1623 for _, n := range validPolicyNodeSet {
1624 authorityConstrainedPolicySet[string(n.validPolicy.der)] = true
1625 }
1626
1627 userConstrainedPolicySet := maps.Clone(authorityConstrainedPolicySet)
1628
1629 if len(initialUserPolicySet) != 1 || !initialUserPolicySet[string(anyPolicyOID.der)] {
1630
1631 for p := range userConstrainedPolicySet {
1632 if !initialUserPolicySet[p] {
1633 delete(userConstrainedPolicySet, p)
1634 }
1635 }
1636
1637 if authorityConstrainedPolicySet[string(anyPolicyOID.der)] {
1638 for policy := range initialUserPolicySet {
1639 userConstrainedPolicySet[policy] = true
1640 }
1641 }
1642 }
1643
1644 if explicitPolicy == 0 && len(userConstrainedPolicySet) == 0 {
1645 return false
1646 }
1647
1648 return true
1649 }
1650
View as plain text