@@ -3,6 +3,7 @@ package tls
3
3
import (
4
4
"context"
5
5
"crypto/tls"
6
+ "crypto/x509"
6
7
"net"
7
8
"os"
8
9
"strings"
@@ -22,16 +23,17 @@ import (
22
23
var errInsecureUnused = E .New ("tls: insecure unused" )
23
24
24
25
type STDServerConfig struct {
25
- access sync.RWMutex
26
- config * tls.Config
27
- logger log.Logger
28
- acmeService adapter.SimpleLifecycle
29
- certificate []byte
30
- key []byte
31
- certificatePath string
32
- keyPath string
33
- echKeyPath string
34
- watcher * fswatch.Watcher
26
+ access sync.RWMutex
27
+ config * tls.Config
28
+ logger log.Logger
29
+ acmeService adapter.SimpleLifecycle
30
+ certificate []byte
31
+ key []byte
32
+ certificatePath string
33
+ keyPath string
34
+ clientCertificatePath []string
35
+ echKeyPath string
36
+ watcher * fswatch.Watcher
35
37
}
36
38
37
39
func (c * STDServerConfig ) ServerName () string {
@@ -111,6 +113,9 @@ func (c *STDServerConfig) startWatcher() error {
111
113
if c .echKeyPath != "" {
112
114
watchPath = append (watchPath , c .echKeyPath )
113
115
}
116
+ if len (c .clientCertificatePath ) > 0 {
117
+ watchPath = append (watchPath , c .clientCertificatePath ... )
118
+ }
114
119
if len (watchPath ) == 0 {
115
120
return nil
116
121
}
@@ -159,6 +164,30 @@ func (c *STDServerConfig) certificateUpdated(path string) error {
159
164
c .config = config
160
165
c .access .Unlock ()
161
166
c .logger .Info ("reloaded TLS certificate" )
167
+ } else if common .Contains (c .clientCertificatePath , path ) {
168
+ clientCertificateCA := x509 .NewCertPool ()
169
+ var reloaded bool
170
+ for _ , certPath := range c .clientCertificatePath {
171
+ content , err := os .ReadFile (certPath )
172
+ if err != nil {
173
+ c .logger .Error (E .Cause (err , "reload certificate from " , c .clientCertificatePath ))
174
+ continue
175
+ }
176
+ if ! clientCertificateCA .AppendCertsFromPEM (content ) {
177
+ c .logger .Error (E .New ("invalid client certificate file: " , certPath ))
178
+ continue
179
+ }
180
+ reloaded = true
181
+ }
182
+ if ! reloaded {
183
+ return E .New ("client certificates is empty" )
184
+ }
185
+ c .access .Lock ()
186
+ config := c .config .Clone ()
187
+ config .ClientCAs = clientCertificateCA
188
+ c .config = config
189
+ c .access .Unlock ()
190
+ c .logger .Info ("reloaded client certificates" )
162
191
} else if path == c .echKeyPath {
163
192
echKey , err := os .ReadFile (c .echKeyPath )
164
193
if err != nil {
@@ -235,8 +264,14 @@ func NewSTDServer(ctx context.Context, logger log.ContextLogger, options option.
235
264
return nil , E .New ("unknown cipher_suite: " , cipherSuite )
236
265
}
237
266
}
238
- var certificate []byte
239
- var key []byte
267
+ for _ , curveID := range options .CurvePreferences {
268
+ tlsConfig .CurvePreferences = append (tlsConfig .CurvePreferences , tls .CurveID (curveID ))
269
+ }
270
+ tlsConfig .ClientAuth = tls .ClientAuthType (options .ClientAuthentication )
271
+ var (
272
+ certificate []byte
273
+ key []byte
274
+ )
240
275
if acmeService == nil {
241
276
if len (options .Certificate ) > 0 {
242
277
certificate = []byte (strings .Join (options .Certificate , "\n " ))
@@ -278,6 +313,43 @@ func NewSTDServer(ctx context.Context, logger log.ContextLogger, options option.
278
313
tlsConfig .Certificates = []tls.Certificate {keyPair }
279
314
}
280
315
}
316
+ if len (options .ClientCertificate ) > 0 || len (options .ClientCertificatePath ) > 0 {
317
+ if tlsConfig .ClientAuth == tls .NoClientCert {
318
+ tlsConfig .ClientAuth = tls .RequireAndVerifyClientCert
319
+ }
320
+ }
321
+ if tlsConfig .ClientAuth == tls .VerifyClientCertIfGiven || tlsConfig .ClientAuth == tls .RequireAndVerifyClientCert {
322
+ if len (options .ClientCertificate ) > 0 {
323
+ clientCertificateCA := x509 .NewCertPool ()
324
+ if ! clientCertificateCA .AppendCertsFromPEM ([]byte (strings .Join (options .ClientCertificate , "\n " ))) {
325
+ return nil , E .New ("invalid client certificate strings" )
326
+ }
327
+ tlsConfig .ClientCAs = clientCertificateCA
328
+ } else if len (options .ClientCertificatePath ) > 0 {
329
+ clientCertificateCA := x509 .NewCertPool ()
330
+ for _ , path := range options .ClientCertificatePath {
331
+ content , err := os .ReadFile (path )
332
+ if err != nil {
333
+ return nil , E .Cause (err , "read client certificate from " , path )
334
+ }
335
+ if ! clientCertificateCA .AppendCertsFromPEM (content ) {
336
+ return nil , E .New ("invalid client certificate file: " , path )
337
+ }
338
+ }
339
+ tlsConfig .ClientCAs = clientCertificateCA
340
+ } else if len (options .ClientCertificatePublicKeySHA256 ) > 0 {
341
+ if tlsConfig .ClientAuth == tls .RequireAndVerifyClientCert {
342
+ tlsConfig .ClientAuth = tls .RequireAnyClientCert
343
+ } else if tlsConfig .ClientAuth == tls .VerifyClientCertIfGiven {
344
+ tlsConfig .ClientAuth = tls .RequestClientCert
345
+ }
346
+ tlsConfig .VerifyPeerCertificate = func (rawCerts [][]byte , verifiedChains [][]* x509.Certificate ) error {
347
+ return verifyPublicKeySHA256 (options .ClientCertificatePublicKeySHA256 , rawCerts , tlsConfig .Time )
348
+ }
349
+ } else {
350
+ return nil , E .New ("missing client_certificate, client_certificate_path or client_certificate_public_key_sha256 for client authentication" )
351
+ }
352
+ }
281
353
var echKeyPath string
282
354
if options .ECH != nil && options .ECH .Enabled {
283
355
err = parseECHServerConfig (ctx , options , tlsConfig , & echKeyPath )
@@ -286,14 +358,15 @@ func NewSTDServer(ctx context.Context, logger log.ContextLogger, options option.
286
358
}
287
359
}
288
360
serverConfig := & STDServerConfig {
289
- config : tlsConfig ,
290
- logger : logger ,
291
- acmeService : acmeService ,
292
- certificate : certificate ,
293
- key : key ,
294
- certificatePath : options .CertificatePath ,
295
- keyPath : options .KeyPath ,
296
- echKeyPath : echKeyPath ,
361
+ config : tlsConfig ,
362
+ logger : logger ,
363
+ acmeService : acmeService ,
364
+ certificate : certificate ,
365
+ key : key ,
366
+ certificatePath : options .CertificatePath ,
367
+ clientCertificatePath : options .ClientCertificatePath ,
368
+ keyPath : options .KeyPath ,
369
+ echKeyPath : echKeyPath ,
297
370
}
298
371
serverConfig .config .GetConfigForClient = func (info * tls.ClientHelloInfo ) (* tls.Config , error ) {
299
372
serverConfig .access .Lock ()
0 commit comments