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 var errSignatureLimit = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
724
725 func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
726 var (
727 hintErr error
728 hintCert *Certificate
729 )
730
731 considerCandidate := func(certType int, candidate potentialParent) {
732 if sigChecks == nil {
733 sigChecks = new(int)
734 }
735 *sigChecks++
736 if *sigChecks > maxChainSignatureChecks {
737 err = errSignatureLimit
738 return
739 }
740
741 if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) {
742 return
743 }
744
745 if err := c.CheckSignatureFrom(candidate.cert); err != nil {
746 if hintErr == nil {
747 hintErr = err
748 hintCert = candidate.cert
749 }
750 return
751 }
752
753 err = candidate.cert.isValid(certType, currentChain, opts)
754 if err != nil {
755 if hintErr == nil {
756 hintErr = err
757 hintCert = candidate.cert
758 }
759 return
760 }
761
762 if candidate.constraint != nil {
763 if err := candidate.constraint(currentChain); err != nil {
764 if hintErr == nil {
765 hintErr = err
766 hintCert = candidate.cert
767 }
768 return
769 }
770 }
771
772 switch certType {
773 case rootCertificate:
774 chains = append(chains, appendToFreshChain(currentChain, candidate.cert))
775 case intermediateCertificate:
776 var childChains [][]*Certificate
777 childChains, err = candidate.cert.buildChains(appendToFreshChain(currentChain, candidate.cert), sigChecks, opts)
778 chains = append(chains, childChains...)
779 }
780 }
781
782 candidateLoop:
783 for _, parents := range []struct {
784 certType int
785 potentials []potentialParent
786 }{
787 {rootCertificate, opts.Roots.findPotentialParents(c)},
788 {intermediateCertificate, opts.Intermediates.findPotentialParents(c)},
789 } {
790 for _, parent := range parents.potentials {
791 considerCandidate(parents.certType, parent)
792 if err == errSignatureLimit {
793 break candidateLoop
794 }
795 }
796 }
797
798 if len(chains) > 0 {
799 err = nil
800 }
801 if len(chains) == 0 && err == nil {
802 err = UnknownAuthorityError{c, hintErr, hintCert}
803 }
804
805 return
806 }
807
808 func validHostnamePattern(host string) bool { return validHostname(host, true) }
809 func validHostnameInput(host string) bool { return validHostname(host, false) }
810
811
812
813
814 func validHostname(host string, isPattern bool) bool {
815 if !isPattern {
816 host = strings.TrimSuffix(host, ".")
817 }
818 if len(host) == 0 {
819 return false
820 }
821 if host == "*" {
822
823
824 return false
825 }
826
827 for i, part := range strings.Split(host, ".") {
828 if part == "" {
829
830 return false
831 }
832 if isPattern && i == 0 && part == "*" {
833
834
835
836 continue
837 }
838 for j, c := range part {
839 if 'a' <= c && c <= 'z' {
840 continue
841 }
842 if '0' <= c && c <= '9' {
843 continue
844 }
845 if 'A' <= c && c <= 'Z' {
846 continue
847 }
848 if c == '-' && j != 0 {
849 continue
850 }
851 if c == '_' {
852
853
854 continue
855 }
856 return false
857 }
858 }
859
860 return true
861 }
862
863 func matchExactly(hostA, hostB string) bool {
864 if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
865 return false
866 }
867 return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
868 }
869
870 func matchHostnames(pattern, host string) bool {
871 pattern = toLowerCaseASCII(pattern)
872 host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
873
874 if len(pattern) == 0 || len(host) == 0 {
875 return false
876 }
877
878 patternParts := strings.Split(pattern, ".")
879 hostParts := strings.Split(host, ".")
880
881 if len(patternParts) != len(hostParts) {
882 return false
883 }
884
885 for i, patternPart := range patternParts {
886 if i == 0 && patternPart == "*" {
887 continue
888 }
889 if patternPart != hostParts[i] {
890 return false
891 }
892 }
893
894 return true
895 }
896
897
898
899
900 func toLowerCaseASCII(in string) string {
901
902 isAlreadyLowerCase := true
903 for _, c := range in {
904 if c == utf8.RuneError {
905
906
907 isAlreadyLowerCase = false
908 break
909 }
910 if 'A' <= c && c <= 'Z' {
911 isAlreadyLowerCase = false
912 break
913 }
914 }
915
916 if isAlreadyLowerCase {
917 return in
918 }
919
920 out := []byte(in)
921 for i, c := range out {
922 if 'A' <= c && c <= 'Z' {
923 out[i] += 'a' - 'A'
924 }
925 }
926 return string(out)
927 }
928
929
930
931
932
933
934
935
936
937
938 func (c *Certificate) VerifyHostname(h string) error {
939
940 candidateIP := h
941 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
942 candidateIP = h[1 : len(h)-1]
943 }
944 if ip := net.ParseIP(candidateIP); ip != nil {
945
946
947 for _, candidate := range c.IPAddresses {
948 if ip.Equal(candidate) {
949 return nil
950 }
951 }
952 return HostnameError{c, candidateIP}
953 }
954
955 candidateName := toLowerCaseASCII(h)
956 validCandidateName := validHostnameInput(candidateName)
957
958 for _, match := range c.DNSNames {
959
960
961
962
963
964 if validCandidateName && validHostnamePattern(match) {
965 if matchHostnames(match, candidateName) {
966 return nil
967 }
968 } else {
969 if matchExactly(match, candidateName) {
970 return nil
971 }
972 }
973 }
974
975 return HostnameError{c, h}
976 }
977
978 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
979 usages := make([]ExtKeyUsage, len(keyUsages))
980 copy(usages, keyUsages)
981
982 if len(chain) == 0 {
983 return false
984 }
985
986 usagesRemaining := len(usages)
987
988
989
990
991
992 NextCert:
993 for i := len(chain) - 1; i >= 0; i-- {
994 cert := chain[i]
995 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
996
997 continue
998 }
999
1000 for _, usage := range cert.ExtKeyUsage {
1001 if usage == ExtKeyUsageAny {
1002
1003 continue NextCert
1004 }
1005 }
1006
1007 const invalidUsage = -1
1008
1009 NextRequestedUsage:
1010 for i, requestedUsage := range usages {
1011 if requestedUsage == invalidUsage {
1012 continue
1013 }
1014
1015 for _, usage := range cert.ExtKeyUsage {
1016 if requestedUsage == usage {
1017 continue NextRequestedUsage
1018 }
1019 }
1020
1021 usages[i] = invalidUsage
1022 usagesRemaining--
1023 if usagesRemaining == 0 {
1024 return false
1025 }
1026 }
1027 }
1028
1029 return true
1030 }
1031
1032 func mustNewOIDFromInts(ints []uint64) OID {
1033 oid, err := OIDFromInts(ints)
1034 if err != nil {
1035 panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err))
1036 }
1037 return oid
1038 }
1039
1040 type policyGraphNode struct {
1041 validPolicy OID
1042 expectedPolicySet []OID
1043
1044
1045 parents map[*policyGraphNode]bool
1046 children map[*policyGraphNode]bool
1047 }
1048
1049 func newPolicyGraphNode(valid OID, parents []*policyGraphNode) *policyGraphNode {
1050 n := &policyGraphNode{
1051 validPolicy: valid,
1052 expectedPolicySet: []OID{valid},
1053 children: map[*policyGraphNode]bool{},
1054 parents: map[*policyGraphNode]bool{},
1055 }
1056 for _, p := range parents {
1057 p.children[n] = true
1058 n.parents[p] = true
1059 }
1060 return n
1061 }
1062
1063 type policyGraph struct {
1064 strata []map[string]*policyGraphNode
1065
1066 parentIndex map[string][]*policyGraphNode
1067 depth int
1068 }
1069
1070 var anyPolicyOID = mustNewOIDFromInts([]uint64{2, 5, 29, 32, 0})
1071
1072 func newPolicyGraph() *policyGraph {
1073 root := policyGraphNode{
1074 validPolicy: anyPolicyOID,
1075 expectedPolicySet: []OID{anyPolicyOID},
1076 children: map[*policyGraphNode]bool{},
1077 parents: map[*policyGraphNode]bool{},
1078 }
1079 return &policyGraph{
1080 depth: 0,
1081 strata: []map[string]*policyGraphNode{{string(anyPolicyOID.der): &root}},
1082 }
1083 }
1084
1085 func (pg *policyGraph) insert(n *policyGraphNode) {
1086 pg.strata[pg.depth][string(n.validPolicy.der)] = n
1087 }
1088
1089 func (pg *policyGraph) parentsWithExpected(expected OID) []*policyGraphNode {
1090 if pg.depth == 0 {
1091 return nil
1092 }
1093 return pg.parentIndex[string(expected.der)]
1094 }
1095
1096 func (pg *policyGraph) parentWithAnyPolicy() *policyGraphNode {
1097 if pg.depth == 0 {
1098 return nil
1099 }
1100 return pg.strata[pg.depth-1][string(anyPolicyOID.der)]
1101 }
1102
1103 func (pg *policyGraph) parents() iter.Seq[*policyGraphNode] {
1104 if pg.depth == 0 {
1105 return nil
1106 }
1107 return maps.Values(pg.strata[pg.depth-1])
1108 }
1109
1110 func (pg *policyGraph) leaves() map[string]*policyGraphNode {
1111 return pg.strata[pg.depth]
1112 }
1113
1114 func (pg *policyGraph) leafWithPolicy(policy OID) *policyGraphNode {
1115 return pg.strata[pg.depth][string(policy.der)]
1116 }
1117
1118 func (pg *policyGraph) deleteLeaf(policy OID) {
1119 n := pg.strata[pg.depth][string(policy.der)]
1120 if n == nil {
1121 return
1122 }
1123 for p := range n.parents {
1124 delete(p.children, n)
1125 }
1126 for c := range n.children {
1127 delete(c.parents, n)
1128 }
1129 delete(pg.strata[pg.depth], string(policy.der))
1130 }
1131
1132 func (pg *policyGraph) validPolicyNodes() []*policyGraphNode {
1133 var validNodes []*policyGraphNode
1134 for i := pg.depth; i >= 0; i-- {
1135 for _, n := range pg.strata[i] {
1136 if n.validPolicy.Equal(anyPolicyOID) {
1137 continue
1138 }
1139
1140 if len(n.parents) == 1 {
1141 for p := range n.parents {
1142 if p.validPolicy.Equal(anyPolicyOID) {
1143 validNodes = append(validNodes, n)
1144 }
1145 }
1146 }
1147 }
1148 }
1149 return validNodes
1150 }
1151
1152 func (pg *policyGraph) prune() {
1153 for i := pg.depth - 1; i > 0; i-- {
1154 for _, n := range pg.strata[i] {
1155 if len(n.children) == 0 {
1156 for p := range n.parents {
1157 delete(p.children, n)
1158 }
1159 delete(pg.strata[i], string(n.validPolicy.der))
1160 }
1161 }
1162 }
1163 }
1164
1165 func (pg *policyGraph) incrDepth() {
1166 pg.parentIndex = map[string][]*policyGraphNode{}
1167 for _, n := range pg.strata[pg.depth] {
1168 for _, e := range n.expectedPolicySet {
1169 pg.parentIndex[string(e.der)] = append(pg.parentIndex[string(e.der)], n)
1170 }
1171 }
1172
1173 pg.depth++
1174 pg.strata = append(pg.strata, map[string]*policyGraphNode{})
1175 }
1176
1177 func policiesValid(chain []*Certificate, opts VerifyOptions) bool {
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188 if len(chain) == 1 {
1189 return true
1190 }
1191
1192
1193 n := len(chain) - 1
1194
1195 pg := newPolicyGraph()
1196 var inhibitAnyPolicy, explicitPolicy, policyMapping int
1197 if !opts.inhibitAnyPolicy {
1198 inhibitAnyPolicy = n + 1
1199 }
1200 if !opts.requireExplicitPolicy {
1201 explicitPolicy = n + 1
1202 }
1203 if !opts.inhibitPolicyMapping {
1204 policyMapping = n + 1
1205 }
1206
1207 initialUserPolicySet := map[string]bool{}
1208 for _, p := range opts.CertificatePolicies {
1209 initialUserPolicySet[string(p.der)] = true
1210 }
1211
1212
1213 if len(initialUserPolicySet) == 0 {
1214 initialUserPolicySet[string(anyPolicyOID.der)] = true
1215 }
1216
1217 for i := n - 1; i >= 0; i-- {
1218 cert := chain[i]
1219
1220 isSelfSigned := bytes.Equal(cert.RawIssuer, cert.RawSubject)
1221
1222
1223 if len(cert.Policies) == 0 {
1224 pg = nil
1225 }
1226
1227
1228 if explicitPolicy == 0 && pg == nil {
1229 return false
1230 }
1231
1232 if pg != nil {
1233 pg.incrDepth()
1234
1235 policies := map[string]bool{}
1236
1237
1238 for _, policy := range cert.Policies {
1239 policies[string(policy.der)] = true
1240
1241 if policy.Equal(anyPolicyOID) {
1242 continue
1243 }
1244
1245
1246 parents := pg.parentsWithExpected(policy)
1247 if len(parents) == 0 {
1248
1249 if anyParent := pg.parentWithAnyPolicy(); anyParent != nil {
1250 parents = []*policyGraphNode{anyParent}
1251 }
1252 }
1253 if len(parents) > 0 {
1254 pg.insert(newPolicyGraphNode(policy, parents))
1255 }
1256 }
1257
1258
1259
1260
1261
1262
1263 if policies[string(anyPolicyOID.der)] && (inhibitAnyPolicy > 0 || (n-i < n && isSelfSigned)) {
1264 missing := map[string][]*policyGraphNode{}
1265 leaves := pg.leaves()
1266 for p := range pg.parents() {
1267 for _, expected := range p.expectedPolicySet {
1268 if leaves[string(expected.der)] == nil {
1269 missing[string(expected.der)] = append(missing[string(expected.der)], p)
1270 }
1271 }
1272 }
1273
1274 for oidStr, parents := range missing {
1275 pg.insert(newPolicyGraphNode(OID{der: []byte(oidStr)}, parents))
1276 }
1277 }
1278
1279
1280 pg.prune()
1281
1282 if i != 0 {
1283
1284 if len(cert.PolicyMappings) > 0 {
1285
1286 mappings := map[string][]OID{}
1287
1288 for _, mapping := range cert.PolicyMappings {
1289 if policyMapping > 0 {
1290 if mapping.IssuerDomainPolicy.Equal(anyPolicyOID) || mapping.SubjectDomainPolicy.Equal(anyPolicyOID) {
1291
1292 return false
1293 }
1294 mappings[string(mapping.IssuerDomainPolicy.der)] = append(mappings[string(mapping.IssuerDomainPolicy.der)], mapping.SubjectDomainPolicy)
1295 } else {
1296
1297 pg.deleteLeaf(mapping.IssuerDomainPolicy)
1298 }
1299 }
1300
1301
1302 pg.prune()
1303
1304 for issuerStr, subjectPolicies := range mappings {
1305
1306 if matching := pg.leafWithPolicy(OID{der: []byte(issuerStr)}); matching != nil {
1307 matching.expectedPolicySet = subjectPolicies
1308 } else if matching := pg.leafWithPolicy(anyPolicyOID); matching != nil {
1309
1310 n := newPolicyGraphNode(OID{der: []byte(issuerStr)}, []*policyGraphNode{matching})
1311 n.expectedPolicySet = subjectPolicies
1312 pg.insert(n)
1313 }
1314 }
1315 }
1316 }
1317 }
1318
1319 if i != 0 {
1320
1321 if !isSelfSigned {
1322 if explicitPolicy > 0 {
1323 explicitPolicy--
1324 }
1325 if policyMapping > 0 {
1326 policyMapping--
1327 }
1328 if inhibitAnyPolicy > 0 {
1329 inhibitAnyPolicy--
1330 }
1331 }
1332
1333
1334 if (cert.RequireExplicitPolicy > 0 || cert.RequireExplicitPolicyZero) && cert.RequireExplicitPolicy < explicitPolicy {
1335 explicitPolicy = cert.RequireExplicitPolicy
1336 }
1337 if (cert.InhibitPolicyMapping > 0 || cert.InhibitPolicyMappingZero) && cert.InhibitPolicyMapping < policyMapping {
1338 policyMapping = cert.InhibitPolicyMapping
1339 }
1340
1341 if (cert.InhibitAnyPolicy > 0 || cert.InhibitAnyPolicyZero) && cert.InhibitAnyPolicy < inhibitAnyPolicy {
1342 inhibitAnyPolicy = cert.InhibitAnyPolicy
1343 }
1344 }
1345 }
1346
1347
1348 if explicitPolicy > 0 {
1349 explicitPolicy--
1350 }
1351
1352
1353 if chain[0].RequireExplicitPolicyZero {
1354 explicitPolicy = 0
1355 }
1356
1357
1358 var validPolicyNodeSet []*policyGraphNode
1359
1360 if pg != nil {
1361 validPolicyNodeSet = pg.validPolicyNodes()
1362
1363 if currentAny := pg.leafWithPolicy(anyPolicyOID); currentAny != nil {
1364 validPolicyNodeSet = append(validPolicyNodeSet, currentAny)
1365 }
1366 }
1367
1368
1369 authorityConstrainedPolicySet := map[string]bool{}
1370 for _, n := range validPolicyNodeSet {
1371 authorityConstrainedPolicySet[string(n.validPolicy.der)] = true
1372 }
1373
1374 userConstrainedPolicySet := maps.Clone(authorityConstrainedPolicySet)
1375
1376 if len(initialUserPolicySet) != 1 || !initialUserPolicySet[string(anyPolicyOID.der)] {
1377
1378 for p := range userConstrainedPolicySet {
1379 if !initialUserPolicySet[p] {
1380 delete(userConstrainedPolicySet, p)
1381 }
1382 }
1383
1384 if authorityConstrainedPolicySet[string(anyPolicyOID.der)] {
1385 for policy := range initialUserPolicySet {
1386 userConstrainedPolicySet[policy] = true
1387 }
1388 }
1389 }
1390
1391 if explicitPolicy == 0 && len(userConstrainedPolicySet) == 0 {
1392 return false
1393 }
1394
1395 return true
1396 }
1397
View as plain text