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