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, splitHostname(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 string, hostParts []string) bool {
871 pattern = toLowerCaseASCII(pattern)
872
873 if len(pattern) == 0 || len(hostParts) == 0 {
874 return false
875 }
876
877 patternParts := strings.Split(pattern, ".")
878
879 if len(patternParts) != len(hostParts) {
880 return false
881 }
882
883 for i, patternPart := range patternParts {
884 if i == 0 && patternPart == "*" {
885 continue
886 }
887 if patternPart != hostParts[i] {
888 return false
889 }
890 }
891
892 return true
893 }
894
895
896
897
898 func toLowerCaseASCII(in string) string {
899
900 isAlreadyLowerCase := true
901 for _, c := range in {
902 if c == utf8.RuneError {
903
904
905 isAlreadyLowerCase = false
906 break
907 }
908 if 'A' <= c && c <= 'Z' {
909 isAlreadyLowerCase = false
910 break
911 }
912 }
913
914 if isAlreadyLowerCase {
915 return in
916 }
917
918 out := []byte(in)
919 for i, c := range out {
920 if 'A' <= c && c <= 'Z' {
921 out[i] += 'a' - 'A'
922 }
923 }
924 return string(out)
925 }
926
927
928
929
930
931
932
933
934
935
936 func (c *Certificate) VerifyHostname(h string) error {
937
938 candidateIP := h
939 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
940 candidateIP = h[1 : len(h)-1]
941 }
942 if ip := net.ParseIP(candidateIP); ip != nil {
943
944
945 for _, candidate := range c.IPAddresses {
946 if ip.Equal(candidate) {
947 return nil
948 }
949 }
950 return HostnameError{c, candidateIP}
951 }
952
953 candidateName := toLowerCaseASCII(h)
954 validCandidateName := validHostnameInput(candidateName)
955 hostParts := splitHostname(candidateName)
956
957 for _, match := range c.DNSNames {
958
959
960
961
962
963 if validCandidateName && validHostnamePattern(match) {
964 if matchHostnames(match, hostParts) {
965 return nil
966 }
967 } else {
968 if matchExactly(match, candidateName) {
969 return nil
970 }
971 }
972 }
973
974 return HostnameError{c, h}
975 }
976
977 func splitHostname(host string) []string {
978 return strings.Split(toLowerCaseASCII(strings.TrimSuffix(host, ".")), ".")
979 }
980
981 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
982 usages := make([]ExtKeyUsage, len(keyUsages))
983 copy(usages, keyUsages)
984
985 if len(chain) == 0 {
986 return false
987 }
988
989 usagesRemaining := len(usages)
990
991
992
993
994
995 NextCert:
996 for i := len(chain) - 1; i >= 0; i-- {
997 cert := chain[i]
998 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
999
1000 continue
1001 }
1002
1003 for _, usage := range cert.ExtKeyUsage {
1004 if usage == ExtKeyUsageAny {
1005
1006 continue NextCert
1007 }
1008 }
1009
1010 const invalidUsage = -1
1011
1012 NextRequestedUsage:
1013 for i, requestedUsage := range usages {
1014 if requestedUsage == invalidUsage {
1015 continue
1016 }
1017
1018 for _, usage := range cert.ExtKeyUsage {
1019 if requestedUsage == usage {
1020 continue NextRequestedUsage
1021 }
1022 }
1023
1024 usages[i] = invalidUsage
1025 usagesRemaining--
1026 if usagesRemaining == 0 {
1027 return false
1028 }
1029 }
1030 }
1031
1032 return true
1033 }
1034
1035 func mustNewOIDFromInts(ints []uint64) OID {
1036 oid, err := OIDFromInts(ints)
1037 if err != nil {
1038 panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err))
1039 }
1040 return oid
1041 }
1042
1043 type policyGraphNode struct {
1044 validPolicy OID
1045 expectedPolicySet []OID
1046
1047
1048 parents map[*policyGraphNode]bool
1049 children map[*policyGraphNode]bool
1050 }
1051
1052 func newPolicyGraphNode(valid OID, parents []*policyGraphNode) *policyGraphNode {
1053 n := &policyGraphNode{
1054 validPolicy: valid,
1055 expectedPolicySet: []OID{valid},
1056 children: map[*policyGraphNode]bool{},
1057 parents: map[*policyGraphNode]bool{},
1058 }
1059 for _, p := range parents {
1060 p.children[n] = true
1061 n.parents[p] = true
1062 }
1063 return n
1064 }
1065
1066 type policyGraph struct {
1067 strata []map[string]*policyGraphNode
1068
1069 parentIndex map[string][]*policyGraphNode
1070 depth int
1071 }
1072
1073 var anyPolicyOID = mustNewOIDFromInts([]uint64{2, 5, 29, 32, 0})
1074
1075 func newPolicyGraph() *policyGraph {
1076 root := policyGraphNode{
1077 validPolicy: anyPolicyOID,
1078 expectedPolicySet: []OID{anyPolicyOID},
1079 children: map[*policyGraphNode]bool{},
1080 parents: map[*policyGraphNode]bool{},
1081 }
1082 return &policyGraph{
1083 depth: 0,
1084 strata: []map[string]*policyGraphNode{{string(anyPolicyOID.der): &root}},
1085 }
1086 }
1087
1088 func (pg *policyGraph) insert(n *policyGraphNode) {
1089 pg.strata[pg.depth][string(n.validPolicy.der)] = n
1090 }
1091
1092 func (pg *policyGraph) parentsWithExpected(expected OID) []*policyGraphNode {
1093 if pg.depth == 0 {
1094 return nil
1095 }
1096 return pg.parentIndex[string(expected.der)]
1097 }
1098
1099 func (pg *policyGraph) parentWithAnyPolicy() *policyGraphNode {
1100 if pg.depth == 0 {
1101 return nil
1102 }
1103 return pg.strata[pg.depth-1][string(anyPolicyOID.der)]
1104 }
1105
1106 func (pg *policyGraph) parents() iter.Seq[*policyGraphNode] {
1107 if pg.depth == 0 {
1108 return nil
1109 }
1110 return maps.Values(pg.strata[pg.depth-1])
1111 }
1112
1113 func (pg *policyGraph) leaves() map[string]*policyGraphNode {
1114 return pg.strata[pg.depth]
1115 }
1116
1117 func (pg *policyGraph) leafWithPolicy(policy OID) *policyGraphNode {
1118 return pg.strata[pg.depth][string(policy.der)]
1119 }
1120
1121 func (pg *policyGraph) deleteLeaf(policy OID) {
1122 n := pg.strata[pg.depth][string(policy.der)]
1123 if n == nil {
1124 return
1125 }
1126 for p := range n.parents {
1127 delete(p.children, n)
1128 }
1129 for c := range n.children {
1130 delete(c.parents, n)
1131 }
1132 delete(pg.strata[pg.depth], string(policy.der))
1133 }
1134
1135 func (pg *policyGraph) validPolicyNodes() []*policyGraphNode {
1136 var validNodes []*policyGraphNode
1137 for i := pg.depth; i >= 0; i-- {
1138 for _, n := range pg.strata[i] {
1139 if n.validPolicy.Equal(anyPolicyOID) {
1140 continue
1141 }
1142
1143 if len(n.parents) == 1 {
1144 for p := range n.parents {
1145 if p.validPolicy.Equal(anyPolicyOID) {
1146 validNodes = append(validNodes, n)
1147 }
1148 }
1149 }
1150 }
1151 }
1152 return validNodes
1153 }
1154
1155 func (pg *policyGraph) prune() {
1156 for i := pg.depth - 1; i > 0; i-- {
1157 for _, n := range pg.strata[i] {
1158 if len(n.children) == 0 {
1159 for p := range n.parents {
1160 delete(p.children, n)
1161 }
1162 delete(pg.strata[i], string(n.validPolicy.der))
1163 }
1164 }
1165 }
1166 }
1167
1168 func (pg *policyGraph) incrDepth() {
1169 pg.parentIndex = map[string][]*policyGraphNode{}
1170 for _, n := range pg.strata[pg.depth] {
1171 for _, e := range n.expectedPolicySet {
1172 pg.parentIndex[string(e.der)] = append(pg.parentIndex[string(e.der)], n)
1173 }
1174 }
1175
1176 pg.depth++
1177 pg.strata = append(pg.strata, map[string]*policyGraphNode{})
1178 }
1179
1180 func policiesValid(chain []*Certificate, opts VerifyOptions) bool {
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191 if len(chain) == 1 {
1192 return true
1193 }
1194
1195
1196 n := len(chain) - 1
1197
1198 pg := newPolicyGraph()
1199 var inhibitAnyPolicy, explicitPolicy, policyMapping int
1200 if !opts.inhibitAnyPolicy {
1201 inhibitAnyPolicy = n + 1
1202 }
1203 if !opts.requireExplicitPolicy {
1204 explicitPolicy = n + 1
1205 }
1206 if !opts.inhibitPolicyMapping {
1207 policyMapping = n + 1
1208 }
1209
1210 initialUserPolicySet := map[string]bool{}
1211 for _, p := range opts.CertificatePolicies {
1212 initialUserPolicySet[string(p.der)] = true
1213 }
1214
1215
1216 if len(initialUserPolicySet) == 0 {
1217 initialUserPolicySet[string(anyPolicyOID.der)] = true
1218 }
1219
1220 for i := n - 1; i >= 0; i-- {
1221 cert := chain[i]
1222
1223 isSelfSigned := bytes.Equal(cert.RawIssuer, cert.RawSubject)
1224
1225
1226 if len(cert.Policies) == 0 {
1227 pg = nil
1228 }
1229
1230
1231 if explicitPolicy == 0 && pg == nil {
1232 return false
1233 }
1234
1235 if pg != nil {
1236 pg.incrDepth()
1237
1238 policies := map[string]bool{}
1239
1240
1241 for _, policy := range cert.Policies {
1242 policies[string(policy.der)] = true
1243
1244 if policy.Equal(anyPolicyOID) {
1245 continue
1246 }
1247
1248
1249 parents := pg.parentsWithExpected(policy)
1250 if len(parents) == 0 {
1251
1252 if anyParent := pg.parentWithAnyPolicy(); anyParent != nil {
1253 parents = []*policyGraphNode{anyParent}
1254 }
1255 }
1256 if len(parents) > 0 {
1257 pg.insert(newPolicyGraphNode(policy, parents))
1258 }
1259 }
1260
1261
1262
1263
1264
1265
1266 if policies[string(anyPolicyOID.der)] && (inhibitAnyPolicy > 0 || (n-i < n && isSelfSigned)) {
1267 missing := map[string][]*policyGraphNode{}
1268 leaves := pg.leaves()
1269 for p := range pg.parents() {
1270 for _, expected := range p.expectedPolicySet {
1271 if leaves[string(expected.der)] == nil {
1272 missing[string(expected.der)] = append(missing[string(expected.der)], p)
1273 }
1274 }
1275 }
1276
1277 for oidStr, parents := range missing {
1278 pg.insert(newPolicyGraphNode(OID{der: []byte(oidStr)}, parents))
1279 }
1280 }
1281
1282
1283 pg.prune()
1284
1285 if i != 0 {
1286
1287 if len(cert.PolicyMappings) > 0 {
1288
1289 mappings := map[string][]OID{}
1290
1291 for _, mapping := range cert.PolicyMappings {
1292 if policyMapping > 0 {
1293 if mapping.IssuerDomainPolicy.Equal(anyPolicyOID) || mapping.SubjectDomainPolicy.Equal(anyPolicyOID) {
1294
1295 return false
1296 }
1297 mappings[string(mapping.IssuerDomainPolicy.der)] = append(mappings[string(mapping.IssuerDomainPolicy.der)], mapping.SubjectDomainPolicy)
1298 } else {
1299
1300 pg.deleteLeaf(mapping.IssuerDomainPolicy)
1301 }
1302 }
1303
1304
1305 pg.prune()
1306
1307 for issuerStr, subjectPolicies := range mappings {
1308
1309 if matching := pg.leafWithPolicy(OID{der: []byte(issuerStr)}); matching != nil {
1310 matching.expectedPolicySet = subjectPolicies
1311 } else if matching := pg.leafWithPolicy(anyPolicyOID); matching != nil {
1312
1313 n := newPolicyGraphNode(OID{der: []byte(issuerStr)}, []*policyGraphNode{matching})
1314 n.expectedPolicySet = subjectPolicies
1315 pg.insert(n)
1316 }
1317 }
1318 }
1319 }
1320 }
1321
1322 if i != 0 {
1323
1324 if !isSelfSigned {
1325 if explicitPolicy > 0 {
1326 explicitPolicy--
1327 }
1328 if policyMapping > 0 {
1329 policyMapping--
1330 }
1331 if inhibitAnyPolicy > 0 {
1332 inhibitAnyPolicy--
1333 }
1334 }
1335
1336
1337 if (cert.RequireExplicitPolicy > 0 || cert.RequireExplicitPolicyZero) && cert.RequireExplicitPolicy < explicitPolicy {
1338 explicitPolicy = cert.RequireExplicitPolicy
1339 }
1340 if (cert.InhibitPolicyMapping > 0 || cert.InhibitPolicyMappingZero) && cert.InhibitPolicyMapping < policyMapping {
1341 policyMapping = cert.InhibitPolicyMapping
1342 }
1343
1344 if (cert.InhibitAnyPolicy > 0 || cert.InhibitAnyPolicyZero) && cert.InhibitAnyPolicy < inhibitAnyPolicy {
1345 inhibitAnyPolicy = cert.InhibitAnyPolicy
1346 }
1347 }
1348 }
1349
1350
1351 if explicitPolicy > 0 {
1352 explicitPolicy--
1353 }
1354
1355
1356 if chain[0].RequireExplicitPolicyZero {
1357 explicitPolicy = 0
1358 }
1359
1360
1361 var validPolicyNodeSet []*policyGraphNode
1362
1363 if pg != nil {
1364 validPolicyNodeSet = pg.validPolicyNodes()
1365
1366 if currentAny := pg.leafWithPolicy(anyPolicyOID); currentAny != nil {
1367 validPolicyNodeSet = append(validPolicyNodeSet, currentAny)
1368 }
1369 }
1370
1371
1372 authorityConstrainedPolicySet := map[string]bool{}
1373 for _, n := range validPolicyNodeSet {
1374 authorityConstrainedPolicySet[string(n.validPolicy.der)] = true
1375 }
1376
1377 userConstrainedPolicySet := maps.Clone(authorityConstrainedPolicySet)
1378
1379 if len(initialUserPolicySet) != 1 || !initialUserPolicySet[string(anyPolicyOID.der)] {
1380
1381 for p := range userConstrainedPolicySet {
1382 if !initialUserPolicySet[p] {
1383 delete(userConstrainedPolicySet, p)
1384 }
1385 }
1386
1387 if authorityConstrainedPolicySet[string(anyPolicyOID.der)] {
1388 for policy := range initialUserPolicySet {
1389 userConstrainedPolicySet[policy] = true
1390 }
1391 }
1392 }
1393
1394 if explicitPolicy == 0 && len(userConstrainedPolicySet) == 0 {
1395 return false
1396 }
1397
1398 return true
1399 }
1400
View as plain text