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