1package archesrv
2
3import (
4 "crypto/ecdsa"
5 "crypto/elliptic"
6 "crypto/rand"
7 "crypto/tls"
8 "crypto/x509"
9 "crypto/x509/pkix"
10 "encoding/pem"
11 "fmt"
12 "math/big"
13 "net/http"
14 "time"
15)
16
17func (s *forgeServer) RunMTLS(addr, certFile, keyFile string) error {
18 tlsCfg := tlsConfigMTLS()
19
20 if certFile != "" && keyFile != "" {
21 cert, err := tls.LoadX509KeyPair(certFile, keyFile)
22 if err != nil {
23 return fmt.Errorf("mTLS: load server cert: %w", err)
24 }
25 tlsCfg.Certificates = []tls.Certificate{cert}
26 } else {
27 cert, err := generateEphemeralCert()
28 if err != nil {
29 return fmt.Errorf("mTLS: generate self-signed cert: %w", err)
30 }
31 tlsCfg.Certificates = []tls.Certificate{cert}
32 s.log.Warn("mTLS using ephemeral self-signed cert", "hint", "set tls_cert/tls_key for a stable cert")
33 }
34
35 ln, err := tls.Listen("tcp", addr, tlsCfg)
36 if err != nil {
37 return fmt.Errorf("mTLS listen %s: %w", addr, err)
38 }
39 s.log.Info("mTLS listening", "addr", addr)
40
41 srv := &http.Server{Handler: s.routes()}
42 return srv.Serve(ln)
43}
44
45func generateEphemeralCert() (tls.Certificate, error) {
46 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
47 if err != nil {
48 return tls.Certificate{}, err
49 }
50 tmpl := &x509.Certificate{
51 SerialNumber: big.NewInt(1),
52 Subject: pkix.Name{CommonName: "arche-server"},
53 NotBefore: time.Now().Add(-time.Minute),
54 NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour),
55 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
56 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
57 }
58 certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &priv.PublicKey, priv)
59 if err != nil {
60 return tls.Certificate{}, err
61 }
62 privDER, err := x509.MarshalECPrivateKey(priv)
63 if err != nil {
64 return tls.Certificate{}, err
65 }
66 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
67 keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: privDER})
68 return tls.X509KeyPair(certPEM, keyPEM)
69}