|
15 | 15 | package caddytls
|
16 | 16 |
|
17 | 17 | import (
|
| 18 | + "context" |
18 | 19 | "crypto/tls"
|
19 | 20 | "crypto/x509"
|
20 | 21 | "encoding/base64"
|
@@ -77,6 +78,14 @@ func (cp ConnectionPolicies) Provision(ctx caddy.Context) error {
|
77 | 78 | cp[i].ClientAuthentication.verifiers = append(cp[i].ClientAuthentication.verifiers, validator.(ClientCertificateVerifier))
|
78 | 79 | }
|
79 | 80 | }
|
| 81 | + |
| 82 | + if len(pol.HandshakeContextRaw) > 0 { |
| 83 | + modIface, err := ctx.LoadModule(pol, "HandshakeContextRaw") |
| 84 | + if err != nil { |
| 85 | + return fmt.Errorf("loading handshake context module: %v", err) |
| 86 | + } |
| 87 | + cp[i].handshakeContext = modIface.(HandshakeContext) |
| 88 | + } |
80 | 89 | }
|
81 | 90 |
|
82 | 91 | return nil
|
@@ -136,6 +145,7 @@ type ConnectionPolicy struct {
|
136 | 145 | // How to match this policy with a TLS ClientHello. If
|
137 | 146 | // this policy is the first to match, it will be used.
|
138 | 147 | MatchersRaw caddy.ModuleMap `json:"match,omitempty" caddy:"namespace=tls.handshake_match"`
|
| 148 | + matchers []ConnectionMatcher |
139 | 149 |
|
140 | 150 | // How to choose a certificate if more than one matched
|
141 | 151 | // the given ServerName (SNI) value.
|
@@ -191,15 +201,28 @@ type ConnectionPolicy struct {
|
191 | 201 | // This feature is EXPERIMENTAL and subject to change or removal.
|
192 | 202 | InsecureSecretsLog string `json:"insecure_secrets_log,omitempty"`
|
193 | 203 |
|
| 204 | + // A module that can manipulate the context passed into CertMagic's |
| 205 | + // certificate management functions during TLS handshakes. |
| 206 | + // EXPERIMENTAL - subject to change or removal. |
| 207 | + HandshakeContextRaw json.RawMessage `json:"handshake_context,omitempty" caddy:"namespace=tls.context"` |
| 208 | + handshakeContext HandshakeContext |
| 209 | + |
194 | 210 | // TLSConfig is the fully-formed, standard lib TLS config
|
195 | 211 | // used to serve TLS connections. Provision all
|
196 | 212 | // ConnectionPolicies to populate this. It is exported only
|
197 | 213 | // so it can be minimally adjusted after provisioning
|
198 | 214 | // if necessary (like to adjust NextProtos to disable HTTP/2),
|
199 | 215 | // and may be unexported in the future.
|
200 | 216 | TLSConfig *tls.Config `json:"-"`
|
| 217 | +} |
201 | 218 |
|
202 |
| - matchers []ConnectionMatcher |
| 219 | +type HandshakeContext interface { |
| 220 | + // HandshakeContext returns a context to pass into CertMagic's |
| 221 | + // GetCertificate function used to serve, load, and manage certs |
| 222 | + // during TLS handshakes. Generally you'll start with the context |
| 223 | + // from the ClientHelloInfo, but you may use other information |
| 224 | + // from it as well. Return an error to abort the handshake. |
| 225 | + HandshakeContext(*tls.ClientHelloInfo) (context.Context, error) |
203 | 226 | }
|
204 | 227 |
|
205 | 228 | func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
|
@@ -239,7 +262,18 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
|
239 | 262 | }
|
240 | 263 | cfg.DefaultServerName = p.DefaultSNI
|
241 | 264 | cfg.FallbackServerName = p.FallbackSNI
|
242 |
| - return cfg.GetCertificate(hello) |
| 265 | + |
| 266 | + // TODO: experimental: if a handshake context module is configured, allow it |
| 267 | + // to modify the context before passing it into CertMagic's GetCertificate |
| 268 | + ctx := hello.Context() |
| 269 | + if p.handshakeContext != nil { |
| 270 | + ctx, err = p.handshakeContext.HandshakeContext(hello) |
| 271 | + if err != nil { |
| 272 | + return nil, fmt.Errorf("handshake context: %v", err) |
| 273 | + } |
| 274 | + } |
| 275 | + |
| 276 | + return cfg.GetCertificateWithContext(ctx, hello) |
243 | 277 | },
|
244 | 278 | MinVersion: tls.VersionTLS12,
|
245 | 279 | MaxVersion: tls.VersionTLS13,
|
|
0 commit comments