Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
tls: Add custom certificate selection policy
This migrates a feature that was previously reserved for enterprise users, according to https://github.com/caddyserver/caddy/issues/2786. Custom certificate selection policies allow advanced control over which cert is selected when multiple qualify to satisfy a TLS handshake.
Matthew Holt committed
Oct 9, 2019 at 19:41 UTC
85ce15a5ad0c0a0e24ed026b1f06a5a573c74283
1 file changed
+71
modules/caddytls/certselection.go
new
+71
@@ -0,0 +1,71 @@
1
+package caddytls
2
+
3
+import (
4
+ "crypto/tls"
5
+ "crypto/x509"
6
+ "fmt"
7
+ "math/big"
8
+
9
+ "github.com/caddyserver/caddy/v2"
10
+ "github.com/mholt/certmagic"
11
+)
12
+
13
+func init() {
14
+ caddy.RegisterModule(Policy{})
15
+}
16
+
17
+// Policy represents a policy for selecting the certificate used to
18
+// complete a handshake when there may be multiple options. All fields
19
+// specified must match the candidate certificate for it to be chosen.
20
+// This was needed to solve https://github.com/caddyserver/caddy/issues/2588.
21
+type Policy struct {
22
+ SerialNumber *big.Int `json:"serial_number,omitempty"`
23
+ SubjectOrganization string `json:"subject_organization,omitempty"`
24
+ PublicKeyAlgorithm PublicKeyAlgorithm `json:"public_key_algorithm,omitempty"`
25
+ Tag string `json:"tag,omitempty"`
26
+}
27
+
28
+// CaddyModule returns the Caddy module information.
29
+func (Policy) CaddyModule() caddy.ModuleInfo {
30
+ return caddy.ModuleInfo{
31
+ Name: "tls.certificate_selection.custom",
32
+ New: func() caddy.Module { return new(Policy) },
33
+ }
34
+}
35
+
36
+// SelectCertificate implements certmagic.CertificateSelector.
37
+func (p Policy) SelectCertificate(_ *tls.ClientHelloInfo, choices []certmagic.Certificate) (certmagic.Certificate, error) {
38
+ for _, cert := range choices {
39
+ if p.SerialNumber != nil && cert.SerialNumber.Cmp(p.SerialNumber) != 0 {
40
+ continue
41
+ }
42
+
43
+ if p.PublicKeyAlgorithm != PublicKeyAlgorithm(x509.UnknownPublicKeyAlgorithm) &&
44
+ PublicKeyAlgorithm(cert.PublicKeyAlgorithm) != p.PublicKeyAlgorithm {
45
+ continue
46
+ }
47
+
48
+ if p.SubjectOrganization != "" {
49
+ var matchOrg bool
50
+ for _, org := range cert.Subject.Organization {
51
+ if p.SubjectOrganization == org {
52
+ matchOrg = true
53
+ break
54
+ }
55
+ }
56
+ if !matchOrg {
57
+ continue
58
+ }
59
+ }
60
+
61
+ if p.Tag != "" && !cert.HasTag(p.Tag) {
62
+ continue
63
+ }
64
+
65
+ return cert, nil
66
+ }
67
+ return certmagic.Certificate{}, fmt.Errorf("no certificates matched custom selection policy")
68
+}
69
+
70
+// Interface guard
71
+var _ certmagic.CertificateSelector = (*Policy)(nil)