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