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