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