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 if len(opts.KeyUsages) == 0 {
845 opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
846 }
847
848 for _, eku := range opts.KeyUsages {
849 if eku == ExtKeyUsageAny {
850
851
852 return candidateChains, nil
853 }
854 }
855
856 chains = make([][]*Certificate, 0, len(candidateChains))
857 var incompatibleKeyUsageChains, invalidPoliciesChains int
858 for _, candidate := range candidateChains {
859 if !checkChainForKeyUsage(candidate, opts.KeyUsages) {
860 incompatibleKeyUsageChains++
861 continue
862 }
863 if !policiesValid(candidate, opts) {
864 invalidPoliciesChains++
865 continue
866 }
867 chains = append(chains, candidate)
868 }
869 if len(chains) == 0 {
870 var details []string
871 if incompatibleKeyUsageChains > 0 {
872 if invalidPoliciesChains == 0 {
873 return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
874 }
875 details = append(details, fmt.Sprintf("%d chains with incompatible key usage", incompatibleKeyUsageChains))
876 }
877 if invalidPoliciesChains > 0 {
878 details = append(details, fmt.Sprintf("%d chains with invalid policies", invalidPoliciesChains))
879 }
880 err = CertificateInvalidError{c, NoValidChains, strings.Join(details, ", ")}
881 return nil, err
882 }
883
884 return chains, nil
885 }
886
887 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
888 n := make([]*Certificate, len(chain)+1)
889 copy(n, chain)
890 n[len(chain)] = cert
891 return n
892 }
893
894
895
896
897
898
899 func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
900 type pubKeyEqual interface {
901 Equal(crypto.PublicKey) bool
902 }
903
904 var candidateSAN *pkix.Extension
905 for _, ext := range candidate.Extensions {
906 if ext.Id.Equal(oidExtensionSubjectAltName) {
907 candidateSAN = &ext
908 break
909 }
910 }
911
912 for _, cert := range chain {
913 if !bytes.Equal(candidate.RawSubject, cert.RawSubject) {
914 continue
915 }
916 if !candidate.PublicKey.(pubKeyEqual).Equal(cert.PublicKey) {
917 continue
918 }
919 var certSAN *pkix.Extension
920 for _, ext := range cert.Extensions {
921 if ext.Id.Equal(oidExtensionSubjectAltName) {
922 certSAN = &ext
923 break
924 }
925 }
926 if candidateSAN == nil && certSAN == nil {
927 return true
928 } else if candidateSAN == nil || certSAN == nil {
929 return false
930 }
931 if bytes.Equal(candidateSAN.Value, certSAN.Value) {
932 return true
933 }
934 }
935 return false
936 }
937
938
939
940
941
942 const maxChainSignatureChecks = 100
943
944 func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
945 var (
946 hintErr error
947 hintCert *Certificate
948 )
949
950 considerCandidate := func(certType int, candidate potentialParent) {
951 if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) {
952 return
953 }
954
955 if sigChecks == nil {
956 sigChecks = new(int)
957 }
958 *sigChecks++
959 if *sigChecks > maxChainSignatureChecks {
960 err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
961 return
962 }
963
964 if err := c.CheckSignatureFrom(candidate.cert); err != nil {
965 if hintErr == nil {
966 hintErr = err
967 hintCert = candidate.cert
968 }
969 return
970 }
971
972 err = candidate.cert.isValid(certType, currentChain, opts)
973 if err != nil {
974 if hintErr == nil {
975 hintErr = err
976 hintCert = candidate.cert
977 }
978 return
979 }
980
981 if candidate.constraint != nil {
982 if err := candidate.constraint(currentChain); err != nil {
983 if hintErr == nil {
984 hintErr = err
985 hintCert = candidate.cert
986 }
987 return
988 }
989 }
990
991 switch certType {
992 case rootCertificate:
993 chains = append(chains, appendToFreshChain(currentChain, candidate.cert))
994 case intermediateCertificate:
995 var childChains [][]*Certificate
996 childChains, err = candidate.cert.buildChains(appendToFreshChain(currentChain, candidate.cert), sigChecks, opts)
997 chains = append(chains, childChains...)
998 }
999 }
1000
1001 for _, root := range opts.Roots.findPotentialParents(c) {
1002 considerCandidate(rootCertificate, root)
1003 }
1004 for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
1005 considerCandidate(intermediateCertificate, intermediate)
1006 }
1007
1008 if len(chains) > 0 {
1009 err = nil
1010 }
1011 if len(chains) == 0 && err == nil {
1012 err = UnknownAuthorityError{c, hintErr, hintCert}
1013 }
1014
1015 return
1016 }
1017
1018 func validHostnamePattern(host string) bool { return validHostname(host, true) }
1019 func validHostnameInput(host string) bool { return validHostname(host, false) }
1020
1021
1022
1023
1024 func validHostname(host string, isPattern bool) bool {
1025 if !isPattern {
1026 host = strings.TrimSuffix(host, ".")
1027 }
1028 if len(host) == 0 {
1029 return false
1030 }
1031 if host == "*" {
1032
1033
1034 return false
1035 }
1036
1037 for i, part := range strings.Split(host, ".") {
1038 if part == "" {
1039
1040 return false
1041 }
1042 if isPattern && i == 0 && part == "*" {
1043
1044
1045
1046 continue
1047 }
1048 for j, c := range part {
1049 if 'a' <= c && c <= 'z' {
1050 continue
1051 }
1052 if '0' <= c && c <= '9' {
1053 continue
1054 }
1055 if 'A' <= c && c <= 'Z' {
1056 continue
1057 }
1058 if c == '-' && j != 0 {
1059 continue
1060 }
1061 if c == '_' {
1062
1063
1064 continue
1065 }
1066 return false
1067 }
1068 }
1069
1070 return true
1071 }
1072
1073 func matchExactly(hostA, hostB string) bool {
1074 if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
1075 return false
1076 }
1077 return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
1078 }
1079
1080 func matchHostnames(pattern, host string) bool {
1081 pattern = toLowerCaseASCII(pattern)
1082 host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
1083
1084 if len(pattern) == 0 || len(host) == 0 {
1085 return false
1086 }
1087
1088 patternParts := strings.Split(pattern, ".")
1089 hostParts := strings.Split(host, ".")
1090
1091 if len(patternParts) != len(hostParts) {
1092 return false
1093 }
1094
1095 for i, patternPart := range patternParts {
1096 if i == 0 && patternPart == "*" {
1097 continue
1098 }
1099 if patternPart != hostParts[i] {
1100 return false
1101 }
1102 }
1103
1104 return true
1105 }
1106
1107
1108
1109
1110 func toLowerCaseASCII(in string) string {
1111
1112 isAlreadyLowerCase := true
1113 for _, c := range in {
1114 if c == utf8.RuneError {
1115
1116
1117 isAlreadyLowerCase = false
1118 break
1119 }
1120 if 'A' <= c && c <= 'Z' {
1121 isAlreadyLowerCase = false
1122 break
1123 }
1124 }
1125
1126 if isAlreadyLowerCase {
1127 return in
1128 }
1129
1130 out := []byte(in)
1131 for i, c := range out {
1132 if 'A' <= c && c <= 'Z' {
1133 out[i] += 'a' - 'A'
1134 }
1135 }
1136 return string(out)
1137 }
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148 func (c *Certificate) VerifyHostname(h string) error {
1149
1150 candidateIP := h
1151 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
1152 candidateIP = h[1 : len(h)-1]
1153 }
1154 if ip := net.ParseIP(candidateIP); ip != nil {
1155
1156
1157 for _, candidate := range c.IPAddresses {
1158 if ip.Equal(candidate) {
1159 return nil
1160 }
1161 }
1162 return HostnameError{c, candidateIP}
1163 }
1164
1165 candidateName := toLowerCaseASCII(h)
1166 validCandidateName := validHostnameInput(candidateName)
1167
1168 for _, match := range c.DNSNames {
1169
1170
1171
1172
1173
1174 if validCandidateName && validHostnamePattern(match) {
1175 if matchHostnames(match, candidateName) {
1176 return nil
1177 }
1178 } else {
1179 if matchExactly(match, candidateName) {
1180 return nil
1181 }
1182 }
1183 }
1184
1185 return HostnameError{c, h}
1186 }
1187
1188 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
1189 usages := make([]ExtKeyUsage, len(keyUsages))
1190 copy(usages, keyUsages)
1191
1192 if len(chain) == 0 {
1193 return false
1194 }
1195
1196 usagesRemaining := len(usages)
1197
1198
1199
1200
1201
1202 NextCert:
1203 for i := len(chain) - 1; i >= 0; i-- {
1204 cert := chain[i]
1205 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
1206
1207 continue
1208 }
1209
1210 for _, usage := range cert.ExtKeyUsage {
1211 if usage == ExtKeyUsageAny {
1212
1213 continue NextCert
1214 }
1215 }
1216
1217 const invalidUsage ExtKeyUsage = -1
1218
1219 NextRequestedUsage:
1220 for i, requestedUsage := range usages {
1221 if requestedUsage == invalidUsage {
1222 continue
1223 }
1224
1225 for _, usage := range cert.ExtKeyUsage {
1226 if requestedUsage == usage {
1227 continue NextRequestedUsage
1228 }
1229 }
1230
1231 usages[i] = invalidUsage
1232 usagesRemaining--
1233 if usagesRemaining == 0 {
1234 return false
1235 }
1236 }
1237 }
1238
1239 return true
1240 }
1241
1242 func mustNewOIDFromInts(ints []uint64) OID {
1243 oid, err := OIDFromInts(ints)
1244 if err != nil {
1245 panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err))
1246 }
1247 return oid
1248 }
1249
1250 type policyGraphNode struct {
1251 validPolicy OID
1252 expectedPolicySet []OID
1253
1254
1255 parents map[*policyGraphNode]bool
1256 children map[*policyGraphNode]bool
1257 }
1258
1259 func newPolicyGraphNode(valid OID, parents []*policyGraphNode) *policyGraphNode {
1260 n := &policyGraphNode{
1261 validPolicy: valid,
1262 expectedPolicySet: []OID{valid},
1263 children: map[*policyGraphNode]bool{},
1264 parents: map[*policyGraphNode]bool{},
1265 }
1266 for _, p := range parents {
1267 p.children[n] = true
1268 n.parents[p] = true
1269 }
1270 return n
1271 }
1272
1273 type policyGraph struct {
1274 strata []map[string]*policyGraphNode
1275
1276 parentIndex map[string][]*policyGraphNode
1277 depth int
1278 }
1279
1280 var anyPolicyOID = mustNewOIDFromInts([]uint64{2, 5, 29, 32, 0})
1281
1282 func newPolicyGraph() *policyGraph {
1283 root := policyGraphNode{
1284 validPolicy: anyPolicyOID,
1285 expectedPolicySet: []OID{anyPolicyOID},
1286 children: map[*policyGraphNode]bool{},
1287 parents: map[*policyGraphNode]bool{},
1288 }
1289 return &policyGraph{
1290 depth: 0,
1291 strata: []map[string]*policyGraphNode{{string(anyPolicyOID.der): &root}},
1292 }
1293 }
1294
1295 func (pg *policyGraph) insert(n *policyGraphNode) {
1296 pg.strata[pg.depth][string(n.validPolicy.der)] = n
1297 }
1298
1299 func (pg *policyGraph) parentsWithExpected(expected OID) []*policyGraphNode {
1300 if pg.depth == 0 {
1301 return nil
1302 }
1303 return pg.parentIndex[string(expected.der)]
1304 }
1305
1306 func (pg *policyGraph) parentWithAnyPolicy() *policyGraphNode {
1307 if pg.depth == 0 {
1308 return nil
1309 }
1310 return pg.strata[pg.depth-1][string(anyPolicyOID.der)]
1311 }
1312
1313 func (pg *policyGraph) parents() iter.Seq[*policyGraphNode] {
1314 if pg.depth == 0 {
1315 return nil
1316 }
1317 return maps.Values(pg.strata[pg.depth-1])
1318 }
1319
1320 func (pg *policyGraph) leaves() map[string]*policyGraphNode {
1321 return pg.strata[pg.depth]
1322 }
1323
1324 func (pg *policyGraph) leafWithPolicy(policy OID) *policyGraphNode {
1325 return pg.strata[pg.depth][string(policy.der)]
1326 }
1327
1328 func (pg *policyGraph) deleteLeaf(policy OID) {
1329 n := pg.strata[pg.depth][string(policy.der)]
1330 if n == nil {
1331 return
1332 }
1333 for p := range n.parents {
1334 delete(p.children, n)
1335 }
1336 for c := range n.children {
1337 delete(c.parents, n)
1338 }
1339 delete(pg.strata[pg.depth], string(policy.der))
1340 }
1341
1342 func (pg *policyGraph) validPolicyNodes() []*policyGraphNode {
1343 var validNodes []*policyGraphNode
1344 for i := pg.depth; i >= 0; i-- {
1345 for _, n := range pg.strata[i] {
1346 if n.validPolicy.Equal(anyPolicyOID) {
1347 continue
1348 }
1349
1350 if len(n.parents) == 1 {
1351 for p := range n.parents {
1352 if p.validPolicy.Equal(anyPolicyOID) {
1353 validNodes = append(validNodes, n)
1354 }
1355 }
1356 }
1357 }
1358 }
1359 return validNodes
1360 }
1361
1362 func (pg *policyGraph) prune() {
1363 for i := pg.depth - 1; i > 0; i-- {
1364 for _, n := range pg.strata[i] {
1365 if len(n.children) == 0 {
1366 for p := range n.parents {
1367 delete(p.children, n)
1368 }
1369 delete(pg.strata[i], string(n.validPolicy.der))
1370 }
1371 }
1372 }
1373 }
1374
1375 func (pg *policyGraph) incrDepth() {
1376 pg.parentIndex = map[string][]*policyGraphNode{}
1377 for _, n := range pg.strata[pg.depth] {
1378 for _, e := range n.expectedPolicySet {
1379 pg.parentIndex[string(e.der)] = append(pg.parentIndex[string(e.der)], n)
1380 }
1381 }
1382
1383 pg.depth++
1384 pg.strata = append(pg.strata, map[string]*policyGraphNode{})
1385 }
1386
1387 func policiesValid(chain []*Certificate, opts VerifyOptions) bool {
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398 if len(chain) == 1 {
1399 return true
1400 }
1401
1402
1403 n := len(chain) - 1
1404
1405 pg := newPolicyGraph()
1406 var inhibitAnyPolicy, explicitPolicy, policyMapping int
1407 if !opts.inhibitAnyPolicy {
1408 inhibitAnyPolicy = n + 1
1409 }
1410 if !opts.requireExplicitPolicy {
1411 explicitPolicy = n + 1
1412 }
1413 if !opts.inhibitPolicyMapping {
1414 policyMapping = n + 1
1415 }
1416
1417 initialUserPolicySet := map[string]bool{}
1418 for _, p := range opts.CertificatePolicies {
1419 initialUserPolicySet[string(p.der)] = true
1420 }
1421
1422
1423 if len(initialUserPolicySet) == 0 {
1424 initialUserPolicySet[string(anyPolicyOID.der)] = true
1425 }
1426
1427 for i := n - 1; i >= 0; i-- {
1428 cert := chain[i]
1429
1430 isSelfSigned := bytes.Equal(cert.RawIssuer, cert.RawSubject)
1431
1432
1433 if len(cert.Policies) == 0 {
1434 pg = nil
1435 }
1436
1437
1438 if explicitPolicy == 0 && pg == nil {
1439 return false
1440 }
1441
1442 if pg != nil {
1443 pg.incrDepth()
1444
1445 policies := map[string]bool{}
1446
1447
1448 for _, policy := range cert.Policies {
1449 policies[string(policy.der)] = true
1450
1451 if policy.Equal(anyPolicyOID) {
1452 continue
1453 }
1454
1455
1456 parents := pg.parentsWithExpected(policy)
1457 if len(parents) == 0 {
1458
1459 if anyParent := pg.parentWithAnyPolicy(); anyParent != nil {
1460 parents = []*policyGraphNode{anyParent}
1461 }
1462 }
1463 if len(parents) > 0 {
1464 pg.insert(newPolicyGraphNode(policy, parents))
1465 }
1466 }
1467
1468
1469
1470
1471
1472
1473 if policies[string(anyPolicyOID.der)] && (inhibitAnyPolicy > 0 || (n-i < n && isSelfSigned)) {
1474 missing := map[string][]*policyGraphNode{}
1475 leaves := pg.leaves()
1476 for p := range pg.parents() {
1477 for _, expected := range p.expectedPolicySet {
1478 if leaves[string(expected.der)] == nil {
1479 missing[string(expected.der)] = append(missing[string(expected.der)], p)
1480 }
1481 }
1482 }
1483
1484 for oidStr, parents := range missing {
1485 pg.insert(newPolicyGraphNode(OID{der: []byte(oidStr)}, parents))
1486 }
1487 }
1488
1489
1490 pg.prune()
1491
1492 if i != 0 {
1493
1494 if len(cert.PolicyMappings) > 0 {
1495
1496 mappings := map[string][]OID{}
1497
1498 for _, mapping := range cert.PolicyMappings {
1499 if policyMapping > 0 {
1500 if mapping.IssuerDomainPolicy.Equal(anyPolicyOID) || mapping.SubjectDomainPolicy.Equal(anyPolicyOID) {
1501
1502 return false
1503 }
1504 mappings[string(mapping.IssuerDomainPolicy.der)] = append(mappings[string(mapping.IssuerDomainPolicy.der)], mapping.SubjectDomainPolicy)
1505 } else {
1506
1507 pg.deleteLeaf(mapping.IssuerDomainPolicy)
1508
1509
1510 pg.prune()
1511 }
1512 }
1513
1514 for issuerStr, subjectPolicies := range mappings {
1515
1516 if matching := pg.leafWithPolicy(OID{der: []byte(issuerStr)}); matching != nil {
1517 matching.expectedPolicySet = subjectPolicies
1518 } else if matching := pg.leafWithPolicy(anyPolicyOID); matching != nil {
1519
1520 n := newPolicyGraphNode(OID{der: []byte(issuerStr)}, []*policyGraphNode{matching})
1521 n.expectedPolicySet = subjectPolicies
1522 pg.insert(n)
1523 }
1524 }
1525 }
1526 }
1527 }
1528
1529 if i != 0 {
1530
1531 if !isSelfSigned {
1532 if explicitPolicy > 0 {
1533 explicitPolicy--
1534 }
1535 if policyMapping > 0 {
1536 policyMapping--
1537 }
1538 if inhibitAnyPolicy > 0 {
1539 inhibitAnyPolicy--
1540 }
1541 }
1542
1543
1544 if (cert.RequireExplicitPolicy > 0 || cert.RequireExplicitPolicyZero) && cert.RequireExplicitPolicy < explicitPolicy {
1545 explicitPolicy = cert.RequireExplicitPolicy
1546 }
1547 if (cert.InhibitPolicyMapping > 0 || cert.InhibitPolicyMappingZero) && cert.InhibitPolicyMapping < policyMapping {
1548 policyMapping = cert.InhibitPolicyMapping
1549 }
1550
1551 if (cert.InhibitAnyPolicy > 0 || cert.InhibitAnyPolicyZero) && cert.InhibitAnyPolicy < inhibitAnyPolicy {
1552 inhibitAnyPolicy = cert.InhibitAnyPolicy
1553 }
1554 }
1555 }
1556
1557
1558 if explicitPolicy > 0 {
1559 explicitPolicy--
1560 }
1561
1562
1563 if chain[0].RequireExplicitPolicyZero {
1564 explicitPolicy = 0
1565 }
1566
1567
1568 var validPolicyNodeSet []*policyGraphNode
1569
1570 if pg != nil {
1571 validPolicyNodeSet = pg.validPolicyNodes()
1572
1573 if currentAny := pg.leafWithPolicy(anyPolicyOID); currentAny != nil {
1574 validPolicyNodeSet = append(validPolicyNodeSet, currentAny)
1575 }
1576 }
1577
1578
1579 authorityConstrainedPolicySet := map[string]bool{}
1580 for _, n := range validPolicyNodeSet {
1581 authorityConstrainedPolicySet[string(n.validPolicy.der)] = true
1582 }
1583
1584 userConstrainedPolicySet := maps.Clone(authorityConstrainedPolicySet)
1585
1586 if len(initialUserPolicySet) != 1 || !initialUserPolicySet[string(anyPolicyOID.der)] {
1587
1588 for p := range userConstrainedPolicySet {
1589 if !initialUserPolicySet[p] {
1590 delete(userConstrainedPolicySet, p)
1591 }
1592 }
1593
1594 if authorityConstrainedPolicySet[string(anyPolicyOID.der)] {
1595 for policy := range initialUserPolicySet {
1596 userConstrainedPolicySet[policy] = true
1597 }
1598 }
1599 }
1600
1601 if explicitPolicy == 0 && len(userConstrainedPolicySet) == 0 {
1602 return false
1603 }
1604
1605 return true
1606 }
1607
View as plain text