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