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, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]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, reversedDomainsCache, reversedConstraintsCache)
446 }
447
448 func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]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, reversedDomainsCache, reversedConstraintsCache)
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, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) {
495
496
497 if len(constraint) == 0 {
498 return true, nil
499 }
500
501 domainLabels, found := reversedDomainsCache[domain]
502 if !found {
503 var ok bool
504 domainLabels, ok = domainToReverseLabels(domain)
505 if !ok {
506 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain)
507 }
508 reversedDomainsCache[domain] = domainLabels
509 }
510
511
512
513
514
515
516 mustHaveSubdomains := false
517 if constraint[0] == '.' {
518 mustHaveSubdomains = true
519 constraint = constraint[1:]
520 }
521
522 constraintLabels, found := reversedConstraintsCache[constraint]
523 if !found {
524 var ok bool
525 constraintLabels, ok = domainToReverseLabels(constraint)
526 if !ok {
527 return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint)
528 }
529 reversedConstraintsCache[constraint] = constraintLabels
530 }
531
532 if len(domainLabels) < len(constraintLabels) ||
533 (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) {
534 return false, nil
535 }
536
537 for i, constraintLabel := range constraintLabels {
538 if !strings.EqualFold(constraintLabel, domainLabels[i]) {
539 return false, nil
540 }
541 }
542
543 return true, nil
544 }
545
546
547
548
549
550
551 func (c *Certificate) checkNameConstraints(count *int,
552 maxConstraintComparisons int,
553 nameType string,
554 name string,
555 parsedName any,
556 match func(parsedName, constraint any) (match bool, err error),
557 permitted, excluded any) error {
558
559 excludedValue := reflect.ValueOf(excluded)
560
561 *count += excludedValue.Len()
562 if *count > maxConstraintComparisons {
563 return CertificateInvalidError{c, TooManyConstraints, ""}
564 }
565
566 for i := 0; i < excludedValue.Len(); i++ {
567 constraint := excludedValue.Index(i).Interface()
568 match, err := match(parsedName, constraint)
569 if err != nil {
570 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
571 }
572
573 if match {
574 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)}
575 }
576 }
577
578 permittedValue := reflect.ValueOf(permitted)
579
580 *count += permittedValue.Len()
581 if *count > maxConstraintComparisons {
582 return CertificateInvalidError{c, TooManyConstraints, ""}
583 }
584
585 ok := true
586 for i := 0; i < permittedValue.Len(); i++ {
587 constraint := permittedValue.Index(i).Interface()
588
589 var err error
590 if ok, err = match(parsedName, constraint); err != nil {
591 return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
592 }
593
594 if ok {
595 break
596 }
597 }
598
599 if !ok {
600 return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)}
601 }
602
603 return nil
604 }
605
606
607
608 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
609 if len(c.UnhandledCriticalExtensions) > 0 {
610 return UnhandledCriticalExtension{}
611 }
612
613 if len(currentChain) > 0 {
614 child := currentChain[len(currentChain)-1]
615 if !bytes.Equal(child.RawIssuer, c.RawSubject) {
616 return CertificateInvalidError{c, NameMismatch, ""}
617 }
618 }
619
620 now := opts.CurrentTime
621 if now.IsZero() {
622 now = time.Now()
623 }
624 if now.Before(c.NotBefore) {
625 return CertificateInvalidError{
626 Cert: c,
627 Reason: Expired,
628 Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)),
629 }
630 } else if now.After(c.NotAfter) {
631 return CertificateInvalidError{
632 Cert: c,
633 Reason: Expired,
634 Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)),
635 }
636 }
637
638 maxConstraintComparisons := opts.MaxConstraintComparisions
639 if maxConstraintComparisons == 0 {
640 maxConstraintComparisons = 250000
641 }
642 comparisonCount := 0
643
644 if certType == intermediateCertificate || certType == rootCertificate {
645 if len(currentChain) == 0 {
646 return errors.New("x509: internal error: empty chain when appending CA cert")
647 }
648 }
649
650
651
652
653
654
655
656
657
658
659
660 reversedDomainsCache := map[string][]string{}
661 reversedConstraintsCache := map[string][]string{}
662
663 if (certType == intermediateCertificate || certType == rootCertificate) &&
664 c.hasNameConstraints() {
665 toCheck := []*Certificate{}
666 for _, c := range currentChain {
667 if c.hasSANExtension() {
668 toCheck = append(toCheck, c)
669 }
670 }
671 for _, sanCert := range toCheck {
672 err := forEachSAN(sanCert.getSANExtension(), func(tag int, data []byte) error {
673 switch tag {
674 case nameTypeEmail:
675 name := string(data)
676 mailbox, ok := parseRFC2821Mailbox(name)
677 if !ok {
678 return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
679 }
680
681 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
682 func(parsedName, constraint any) (bool, error) {
683 return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), reversedDomainsCache, reversedConstraintsCache)
684 }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil {
685 return err
686 }
687
688 case nameTypeDNS:
689 name := string(data)
690 if !domainNameValid(name, false) {
691 return fmt.Errorf("x509: cannot parse dnsName %q", name)
692 }
693
694 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
695 func(parsedName, constraint any) (bool, error) {
696 return matchDomainConstraint(parsedName.(string), constraint.(string), reversedDomainsCache, reversedConstraintsCache)
697 }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil {
698 return err
699 }
700
701 case nameTypeURI:
702 name := string(data)
703 uri, err := url.Parse(name)
704 if err != nil {
705 return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name)
706 }
707
708 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri,
709 func(parsedName, constraint any) (bool, error) {
710 return matchURIConstraint(parsedName.(*url.URL), constraint.(string), reversedDomainsCache, reversedConstraintsCache)
711 }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil {
712 return err
713 }
714
715 case nameTypeIP:
716 ip := net.IP(data)
717 if l := len(ip); l != net.IPv4len && l != net.IPv6len {
718 return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data)
719 }
720
721 if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip,
722 func(parsedName, constraint any) (bool, error) {
723 return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet))
724 }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil {
725 return err
726 }
727
728 default:
729
730 }
731
732 return nil
733 })
734
735 if err != nil {
736 return err
737 }
738 }
739 }
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
759 return CertificateInvalidError{c, NotAuthorizedToSign, ""}
760 }
761
762 if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
763 numIntermediates := len(currentChain) - 1
764 if numIntermediates > c.MaxPathLen {
765 return CertificateInvalidError{c, TooManyIntermediates, ""}
766 }
767 }
768
769 return nil
770 }
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
805
806
807 if len(c.Raw) == 0 {
808 return nil, errNotParsed
809 }
810 for i := 0; i < opts.Intermediates.len(); i++ {
811 c, _, err := opts.Intermediates.cert(i)
812 if err != nil {
813 return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err)
814 }
815 if len(c.Raw) == 0 {
816 return nil, errNotParsed
817 }
818 }
819
820
821 if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
822
823
824 systemPool := systemRootsPool()
825 if opts.Roots == nil && (systemPool == nil || systemPool.systemPool) {
826 return c.systemVerify(&opts)
827 }
828 if opts.Roots != nil && opts.Roots.systemPool {
829 platformChains, err := c.systemVerify(&opts)
830
831
832
833 if err == nil || opts.Roots.len() == 0 {
834 return platformChains, err
835 }
836 }
837 }
838
839 if opts.Roots == nil {
840 opts.Roots = systemRootsPool()
841 if opts.Roots == nil {
842 return nil, SystemRootsError{systemRootsErr}
843 }
844 }
845
846 err = c.isValid(leafCertificate, nil, &opts)
847 if err != nil {
848 return
849 }
850
851 if len(opts.DNSName) > 0 {
852 err = c.VerifyHostname(opts.DNSName)
853 if err != nil {
854 return
855 }
856 }
857
858 var candidateChains [][]*Certificate
859 if opts.Roots.contains(c) {
860 candidateChains = [][]*Certificate{{c}}
861 } else {
862 candidateChains, err = c.buildChains([]*Certificate{c}, nil, &opts)
863 if err != nil {
864 return nil, err
865 }
866 }
867
868 chains = make([][]*Certificate, 0, len(candidateChains))
869
870 var invalidPoliciesChains int
871 for _, candidate := range candidateChains {
872 if !policiesValid(candidate, opts) {
873 invalidPoliciesChains++
874 continue
875 }
876 chains = append(chains, candidate)
877 }
878
879 if len(chains) == 0 {
880 return nil, CertificateInvalidError{c, NoValidChains, "all candidate chains have invalid policies"}
881 }
882
883 for _, eku := range opts.KeyUsages {
884 if eku == ExtKeyUsageAny {
885
886
887 return chains, nil
888 }
889 }
890
891 if len(opts.KeyUsages) == 0 {
892 opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
893 }
894
895 candidateChains = chains
896 chains = chains[:0]
897
898 var incompatibleKeyUsageChains int
899 for _, candidate := range candidateChains {
900 if !checkChainForKeyUsage(candidate, opts.KeyUsages) {
901 incompatibleKeyUsageChains++
902 continue
903 }
904 chains = append(chains, candidate)
905 }
906
907 if len(chains) == 0 {
908 var details []string
909 if incompatibleKeyUsageChains > 0 {
910 if invalidPoliciesChains == 0 {
911 return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
912 }
913 details = append(details, fmt.Sprintf("%d chains with incompatible key usage", incompatibleKeyUsageChains))
914 }
915 if invalidPoliciesChains > 0 {
916 details = append(details, fmt.Sprintf("%d chains with invalid policies", invalidPoliciesChains))
917 }
918 err = CertificateInvalidError{c, NoValidChains, strings.Join(details, ", ")}
919 return nil, err
920 }
921
922 return chains, nil
923 }
924
925 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
926 n := make([]*Certificate, len(chain)+1)
927 copy(n, chain)
928 n[len(chain)] = cert
929 return n
930 }
931
932
933
934
935
936
937 func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
938 type pubKeyEqual interface {
939 Equal(crypto.PublicKey) bool
940 }
941
942 var candidateSAN *pkix.Extension
943 for _, ext := range candidate.Extensions {
944 if ext.Id.Equal(oidExtensionSubjectAltName) {
945 candidateSAN = &ext
946 break
947 }
948 }
949
950 for _, cert := range chain {
951 if !bytes.Equal(candidate.RawSubject, cert.RawSubject) {
952 continue
953 }
954
955
956
957 if !bytes.Equal(candidate.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
958 continue
959 }
960 var certSAN *pkix.Extension
961 for _, ext := range cert.Extensions {
962 if ext.Id.Equal(oidExtensionSubjectAltName) {
963 certSAN = &ext
964 break
965 }
966 }
967 if candidateSAN == nil && certSAN == nil {
968 return true
969 } else if candidateSAN == nil || certSAN == nil {
970 return false
971 }
972 if bytes.Equal(candidateSAN.Value, certSAN.Value) {
973 return true
974 }
975 }
976 return false
977 }
978
979
980
981
982
983 const maxChainSignatureChecks = 100
984
985 func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
986 var (
987 hintErr error
988 hintCert *Certificate
989 )
990
991 considerCandidate := func(certType int, candidate potentialParent) {
992 if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) {
993 return
994 }
995
996 if sigChecks == nil {
997 sigChecks = new(int)
998 }
999 *sigChecks++
1000 if *sigChecks > maxChainSignatureChecks {
1001 err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
1002 return
1003 }
1004
1005 if err := c.CheckSignatureFrom(candidate.cert); err != nil {
1006 if hintErr == nil {
1007 hintErr = err
1008 hintCert = candidate.cert
1009 }
1010 return
1011 }
1012
1013 err = candidate.cert.isValid(certType, currentChain, opts)
1014 if err != nil {
1015 if hintErr == nil {
1016 hintErr = err
1017 hintCert = candidate.cert
1018 }
1019 return
1020 }
1021
1022 if candidate.constraint != nil {
1023 if err := candidate.constraint(currentChain); err != nil {
1024 if hintErr == nil {
1025 hintErr = err
1026 hintCert = candidate.cert
1027 }
1028 return
1029 }
1030 }
1031
1032 switch certType {
1033 case rootCertificate:
1034 chains = append(chains, appendToFreshChain(currentChain, candidate.cert))
1035 case intermediateCertificate:
1036 var childChains [][]*Certificate
1037 childChains, err = candidate.cert.buildChains(appendToFreshChain(currentChain, candidate.cert), sigChecks, opts)
1038 chains = append(chains, childChains...)
1039 }
1040 }
1041
1042 for _, root := range opts.Roots.findPotentialParents(c) {
1043 considerCandidate(rootCertificate, root)
1044 }
1045 for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
1046 considerCandidate(intermediateCertificate, intermediate)
1047 }
1048
1049 if len(chains) > 0 {
1050 err = nil
1051 }
1052 if len(chains) == 0 && err == nil {
1053 err = UnknownAuthorityError{c, hintErr, hintCert}
1054 }
1055
1056 return
1057 }
1058
1059 func validHostnamePattern(host string) bool { return validHostname(host, true) }
1060 func validHostnameInput(host string) bool { return validHostname(host, false) }
1061
1062
1063
1064
1065 func validHostname(host string, isPattern bool) bool {
1066 if !isPattern {
1067 host = strings.TrimSuffix(host, ".")
1068 }
1069 if len(host) == 0 {
1070 return false
1071 }
1072 if host == "*" {
1073
1074
1075 return false
1076 }
1077
1078 for i, part := range strings.Split(host, ".") {
1079 if part == "" {
1080
1081 return false
1082 }
1083 if isPattern && i == 0 && part == "*" {
1084
1085
1086
1087 continue
1088 }
1089 for j, c := range part {
1090 if 'a' <= c && c <= 'z' {
1091 continue
1092 }
1093 if '0' <= c && c <= '9' {
1094 continue
1095 }
1096 if 'A' <= c && c <= 'Z' {
1097 continue
1098 }
1099 if c == '-' && j != 0 {
1100 continue
1101 }
1102 if c == '_' {
1103
1104
1105 continue
1106 }
1107 return false
1108 }
1109 }
1110
1111 return true
1112 }
1113
1114 func matchExactly(hostA, hostB string) bool {
1115 if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
1116 return false
1117 }
1118 return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
1119 }
1120
1121 func matchHostnames(pattern, host string) bool {
1122 pattern = toLowerCaseASCII(pattern)
1123 host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
1124
1125 if len(pattern) == 0 || len(host) == 0 {
1126 return false
1127 }
1128
1129 patternParts := strings.Split(pattern, ".")
1130 hostParts := strings.Split(host, ".")
1131
1132 if len(patternParts) != len(hostParts) {
1133 return false
1134 }
1135
1136 for i, patternPart := range patternParts {
1137 if i == 0 && patternPart == "*" {
1138 continue
1139 }
1140 if patternPart != hostParts[i] {
1141 return false
1142 }
1143 }
1144
1145 return true
1146 }
1147
1148
1149
1150
1151 func toLowerCaseASCII(in string) string {
1152
1153 isAlreadyLowerCase := true
1154 for _, c := range in {
1155 if c == utf8.RuneError {
1156
1157
1158 isAlreadyLowerCase = false
1159 break
1160 }
1161 if 'A' <= c && c <= 'Z' {
1162 isAlreadyLowerCase = false
1163 break
1164 }
1165 }
1166
1167 if isAlreadyLowerCase {
1168 return in
1169 }
1170
1171 out := []byte(in)
1172 for i, c := range out {
1173 if 'A' <= c && c <= 'Z' {
1174 out[i] += 'a' - 'A'
1175 }
1176 }
1177 return string(out)
1178 }
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189 func (c *Certificate) VerifyHostname(h string) error {
1190
1191 candidateIP := h
1192 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
1193 candidateIP = h[1 : len(h)-1]
1194 }
1195 if ip := net.ParseIP(candidateIP); ip != nil {
1196
1197
1198 for _, candidate := range c.IPAddresses {
1199 if ip.Equal(candidate) {
1200 return nil
1201 }
1202 }
1203 return HostnameError{c, candidateIP}
1204 }
1205
1206 candidateName := toLowerCaseASCII(h)
1207 validCandidateName := validHostnameInput(candidateName)
1208
1209 for _, match := range c.DNSNames {
1210
1211
1212
1213
1214
1215 if validCandidateName && validHostnamePattern(match) {
1216 if matchHostnames(match, candidateName) {
1217 return nil
1218 }
1219 } else {
1220 if matchExactly(match, candidateName) {
1221 return nil
1222 }
1223 }
1224 }
1225
1226 return HostnameError{c, h}
1227 }
1228
1229 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
1230 usages := make([]ExtKeyUsage, len(keyUsages))
1231 copy(usages, keyUsages)
1232
1233 if len(chain) == 0 {
1234 return false
1235 }
1236
1237 usagesRemaining := len(usages)
1238
1239
1240
1241
1242
1243 NextCert:
1244 for i := len(chain) - 1; i >= 0; i-- {
1245 cert := chain[i]
1246 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
1247
1248 continue
1249 }
1250
1251 for _, usage := range cert.ExtKeyUsage {
1252 if usage == ExtKeyUsageAny {
1253
1254 continue NextCert
1255 }
1256 }
1257
1258 const invalidUsage ExtKeyUsage = -1
1259
1260 NextRequestedUsage:
1261 for i, requestedUsage := range usages {
1262 if requestedUsage == invalidUsage {
1263 continue
1264 }
1265
1266 for _, usage := range cert.ExtKeyUsage {
1267 if requestedUsage == usage {
1268 continue NextRequestedUsage
1269 }
1270 }
1271
1272 usages[i] = invalidUsage
1273 usagesRemaining--
1274 if usagesRemaining == 0 {
1275 return false
1276 }
1277 }
1278 }
1279
1280 return true
1281 }
1282
1283 func mustNewOIDFromInts(ints []uint64) OID {
1284 oid, err := OIDFromInts(ints)
1285 if err != nil {
1286 panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err))
1287 }
1288 return oid
1289 }
1290
1291 type policyGraphNode struct {
1292 validPolicy OID
1293 expectedPolicySet []OID
1294
1295
1296 parents map[*policyGraphNode]bool
1297 children map[*policyGraphNode]bool
1298 }
1299
1300 func newPolicyGraphNode(valid OID, parents []*policyGraphNode) *policyGraphNode {
1301 n := &policyGraphNode{
1302 validPolicy: valid,
1303 expectedPolicySet: []OID{valid},
1304 children: map[*policyGraphNode]bool{},
1305 parents: map[*policyGraphNode]bool{},
1306 }
1307 for _, p := range parents {
1308 p.children[n] = true
1309 n.parents[p] = true
1310 }
1311 return n
1312 }
1313
1314 type policyGraph struct {
1315 strata []map[string]*policyGraphNode
1316
1317 parentIndex map[string][]*policyGraphNode
1318 depth int
1319 }
1320
1321 var anyPolicyOID = mustNewOIDFromInts([]uint64{2, 5, 29, 32, 0})
1322
1323 func newPolicyGraph() *policyGraph {
1324 root := policyGraphNode{
1325 validPolicy: anyPolicyOID,
1326 expectedPolicySet: []OID{anyPolicyOID},
1327 children: map[*policyGraphNode]bool{},
1328 parents: map[*policyGraphNode]bool{},
1329 }
1330 return &policyGraph{
1331 depth: 0,
1332 strata: []map[string]*policyGraphNode{{string(anyPolicyOID.der): &root}},
1333 }
1334 }
1335
1336 func (pg *policyGraph) insert(n *policyGraphNode) {
1337 pg.strata[pg.depth][string(n.validPolicy.der)] = n
1338 }
1339
1340 func (pg *policyGraph) parentsWithExpected(expected OID) []*policyGraphNode {
1341 if pg.depth == 0 {
1342 return nil
1343 }
1344 return pg.parentIndex[string(expected.der)]
1345 }
1346
1347 func (pg *policyGraph) parentWithAnyPolicy() *policyGraphNode {
1348 if pg.depth == 0 {
1349 return nil
1350 }
1351 return pg.strata[pg.depth-1][string(anyPolicyOID.der)]
1352 }
1353
1354 func (pg *policyGraph) parents() iter.Seq[*policyGraphNode] {
1355 if pg.depth == 0 {
1356 return nil
1357 }
1358 return maps.Values(pg.strata[pg.depth-1])
1359 }
1360
1361 func (pg *policyGraph) leaves() map[string]*policyGraphNode {
1362 return pg.strata[pg.depth]
1363 }
1364
1365 func (pg *policyGraph) leafWithPolicy(policy OID) *policyGraphNode {
1366 return pg.strata[pg.depth][string(policy.der)]
1367 }
1368
1369 func (pg *policyGraph) deleteLeaf(policy OID) {
1370 n := pg.strata[pg.depth][string(policy.der)]
1371 if n == nil {
1372 return
1373 }
1374 for p := range n.parents {
1375 delete(p.children, n)
1376 }
1377 for c := range n.children {
1378 delete(c.parents, n)
1379 }
1380 delete(pg.strata[pg.depth], string(policy.der))
1381 }
1382
1383 func (pg *policyGraph) validPolicyNodes() []*policyGraphNode {
1384 var validNodes []*policyGraphNode
1385 for i := pg.depth; i >= 0; i-- {
1386 for _, n := range pg.strata[i] {
1387 if n.validPolicy.Equal(anyPolicyOID) {
1388 continue
1389 }
1390
1391 if len(n.parents) == 1 {
1392 for p := range n.parents {
1393 if p.validPolicy.Equal(anyPolicyOID) {
1394 validNodes = append(validNodes, n)
1395 }
1396 }
1397 }
1398 }
1399 }
1400 return validNodes
1401 }
1402
1403 func (pg *policyGraph) prune() {
1404 for i := pg.depth - 1; i > 0; i-- {
1405 for _, n := range pg.strata[i] {
1406 if len(n.children) == 0 {
1407 for p := range n.parents {
1408 delete(p.children, n)
1409 }
1410 delete(pg.strata[i], string(n.validPolicy.der))
1411 }
1412 }
1413 }
1414 }
1415
1416 func (pg *policyGraph) incrDepth() {
1417 pg.parentIndex = map[string][]*policyGraphNode{}
1418 for _, n := range pg.strata[pg.depth] {
1419 for _, e := range n.expectedPolicySet {
1420 pg.parentIndex[string(e.der)] = append(pg.parentIndex[string(e.der)], n)
1421 }
1422 }
1423
1424 pg.depth++
1425 pg.strata = append(pg.strata, map[string]*policyGraphNode{})
1426 }
1427
1428 func policiesValid(chain []*Certificate, opts VerifyOptions) bool {
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439 if len(chain) == 1 {
1440 return true
1441 }
1442
1443
1444 n := len(chain) - 1
1445
1446 pg := newPolicyGraph()
1447 var inhibitAnyPolicy, explicitPolicy, policyMapping int
1448 if !opts.inhibitAnyPolicy {
1449 inhibitAnyPolicy = n + 1
1450 }
1451 if !opts.requireExplicitPolicy {
1452 explicitPolicy = n + 1
1453 }
1454 if !opts.inhibitPolicyMapping {
1455 policyMapping = n + 1
1456 }
1457
1458 initialUserPolicySet := map[string]bool{}
1459 for _, p := range opts.CertificatePolicies {
1460 initialUserPolicySet[string(p.der)] = true
1461 }
1462
1463
1464 if len(initialUserPolicySet) == 0 {
1465 initialUserPolicySet[string(anyPolicyOID.der)] = true
1466 }
1467
1468 for i := n - 1; i >= 0; i-- {
1469 cert := chain[i]
1470
1471 isSelfSigned := bytes.Equal(cert.RawIssuer, cert.RawSubject)
1472
1473
1474 if len(cert.Policies) == 0 {
1475 pg = nil
1476 }
1477
1478
1479 if explicitPolicy == 0 && pg == nil {
1480 return false
1481 }
1482
1483 if pg != nil {
1484 pg.incrDepth()
1485
1486 policies := map[string]bool{}
1487
1488
1489 for _, policy := range cert.Policies {
1490 policies[string(policy.der)] = true
1491
1492 if policy.Equal(anyPolicyOID) {
1493 continue
1494 }
1495
1496
1497 parents := pg.parentsWithExpected(policy)
1498 if len(parents) == 0 {
1499
1500 if anyParent := pg.parentWithAnyPolicy(); anyParent != nil {
1501 parents = []*policyGraphNode{anyParent}
1502 }
1503 }
1504 if len(parents) > 0 {
1505 pg.insert(newPolicyGraphNode(policy, parents))
1506 }
1507 }
1508
1509
1510
1511
1512
1513
1514 if policies[string(anyPolicyOID.der)] && (inhibitAnyPolicy > 0 || (n-i < n && isSelfSigned)) {
1515 missing := map[string][]*policyGraphNode{}
1516 leaves := pg.leaves()
1517 for p := range pg.parents() {
1518 for _, expected := range p.expectedPolicySet {
1519 if leaves[string(expected.der)] == nil {
1520 missing[string(expected.der)] = append(missing[string(expected.der)], p)
1521 }
1522 }
1523 }
1524
1525 for oidStr, parents := range missing {
1526 pg.insert(newPolicyGraphNode(OID{der: []byte(oidStr)}, parents))
1527 }
1528 }
1529
1530
1531 pg.prune()
1532
1533 if i != 0 {
1534
1535 if len(cert.PolicyMappings) > 0 {
1536
1537 mappings := map[string][]OID{}
1538
1539 for _, mapping := range cert.PolicyMappings {
1540 if policyMapping > 0 {
1541 if mapping.IssuerDomainPolicy.Equal(anyPolicyOID) || mapping.SubjectDomainPolicy.Equal(anyPolicyOID) {
1542
1543 return false
1544 }
1545 mappings[string(mapping.IssuerDomainPolicy.der)] = append(mappings[string(mapping.IssuerDomainPolicy.der)], mapping.SubjectDomainPolicy)
1546 } else {
1547
1548 pg.deleteLeaf(mapping.IssuerDomainPolicy)
1549
1550
1551 pg.prune()
1552 }
1553 }
1554
1555 for issuerStr, subjectPolicies := range mappings {
1556
1557 if matching := pg.leafWithPolicy(OID{der: []byte(issuerStr)}); matching != nil {
1558 matching.expectedPolicySet = subjectPolicies
1559 } else if matching := pg.leafWithPolicy(anyPolicyOID); matching != nil {
1560
1561 n := newPolicyGraphNode(OID{der: []byte(issuerStr)}, []*policyGraphNode{matching})
1562 n.expectedPolicySet = subjectPolicies
1563 pg.insert(n)
1564 }
1565 }
1566 }
1567 }
1568 }
1569
1570 if i != 0 {
1571
1572 if !isSelfSigned {
1573 if explicitPolicy > 0 {
1574 explicitPolicy--
1575 }
1576 if policyMapping > 0 {
1577 policyMapping--
1578 }
1579 if inhibitAnyPolicy > 0 {
1580 inhibitAnyPolicy--
1581 }
1582 }
1583
1584
1585 if (cert.RequireExplicitPolicy > 0 || cert.RequireExplicitPolicyZero) && cert.RequireExplicitPolicy < explicitPolicy {
1586 explicitPolicy = cert.RequireExplicitPolicy
1587 }
1588 if (cert.InhibitPolicyMapping > 0 || cert.InhibitPolicyMappingZero) && cert.InhibitPolicyMapping < policyMapping {
1589 policyMapping = cert.InhibitPolicyMapping
1590 }
1591
1592 if (cert.InhibitAnyPolicy > 0 || cert.InhibitAnyPolicyZero) && cert.InhibitAnyPolicy < inhibitAnyPolicy {
1593 inhibitAnyPolicy = cert.InhibitAnyPolicy
1594 }
1595 }
1596 }
1597
1598
1599 if explicitPolicy > 0 {
1600 explicitPolicy--
1601 }
1602
1603
1604 if chain[0].RequireExplicitPolicyZero {
1605 explicitPolicy = 0
1606 }
1607
1608
1609 var validPolicyNodeSet []*policyGraphNode
1610
1611 if pg != nil {
1612 validPolicyNodeSet = pg.validPolicyNodes()
1613
1614 if currentAny := pg.leafWithPolicy(anyPolicyOID); currentAny != nil {
1615 validPolicyNodeSet = append(validPolicyNodeSet, currentAny)
1616 }
1617 }
1618
1619
1620 authorityConstrainedPolicySet := map[string]bool{}
1621 for _, n := range validPolicyNodeSet {
1622 authorityConstrainedPolicySet[string(n.validPolicy.der)] = true
1623 }
1624
1625 userConstrainedPolicySet := maps.Clone(authorityConstrainedPolicySet)
1626
1627 if len(initialUserPolicySet) != 1 || !initialUserPolicySet[string(anyPolicyOID.der)] {
1628
1629 for p := range userConstrainedPolicySet {
1630 if !initialUserPolicySet[p] {
1631 delete(userConstrainedPolicySet, p)
1632 }
1633 }
1634
1635 if authorityConstrainedPolicySet[string(anyPolicyOID.der)] {
1636 for policy := range initialUserPolicySet {
1637 userConstrainedPolicySet[policy] = true
1638 }
1639 }
1640 }
1641
1642 if explicitPolicy == 0 && len(userConstrainedPolicySet) == 0 {
1643 return false
1644 }
1645
1646 return true
1647 }
1648
View as plain text