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