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