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