diff --git a/internal/certloader/certloader.go b/internal/certloader/certloader.go index 9f3b7d51..cc17d46e 100644 --- a/internal/certloader/certloader.go +++ b/internal/certloader/certloader.go @@ -159,13 +159,11 @@ func (cl *CertLoader) Close() { cl.cert = nil } -// GetCertificate returns a function that returns the certificate for use in a tls.Config. -func (cl *CertLoader) GetCertificate() func(*tls.ClientHelloInfo) (*tls.Certificate, error) { - return func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { - cl.certMu.RLock() - defer cl.certMu.RUnlock() - return cl.cert, nil - } +// GetCertificate returns the certificate for use in a tls.Config. +func (cl *CertLoader) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { + cl.certMu.RLock() + defer cl.certMu.RUnlock() + return cl.cert, nil } func (cl *CertLoader) watch() { diff --git a/internal/certloader/certloader_test.go b/internal/certloader/certloader_test.go index 81b99a16..a88fc429 100644 --- a/internal/certloader/certloader_test.go +++ b/internal/certloader/certloader_test.go @@ -28,10 +28,7 @@ func TestCertReload(t *testing.T) { require.NoError(t, err) defer loader.Close() - getCert := loader.GetCertificate() - require.NotNil(t, getCert) - - cert, err := getCert(nil) + cert, err := loader.GetCertificate(nil) require.NoError(t, err) require.NotNil(t, cert) require.Equal(t, &testData, cert) @@ -47,7 +44,7 @@ func TestCertReload(t *testing.T) { time.Sleep(1 * time.Second) - cert, err = getCert(nil) + cert, err = loader.GetCertificate(nil) require.NoError(t, err) require.NotNil(t, cert) require.Equal(t, &testData, cert) diff --git a/internal/protocols/httpp/server.go b/internal/protocols/httpp/server.go index 70511ba4..e15adfe5 100644 --- a/internal/protocols/httpp/server.go +++ b/internal/protocols/httpp/server.go @@ -43,6 +43,7 @@ type Server struct { ServerCert string ServerKey string AllowAutoCert bool + GetCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) Handler http.Handler Parent logger.Writer @@ -64,23 +65,31 @@ func (s *Server) Initialize() error { var tlsConfig *tls.Config if s.Encryption { - if s.ServerCert == "" { - return fmt.Errorf("server cert is missing") - } + var getCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) - s.loader = &certloader.CertLoader{ - CertPath: s.ServerCert, - KeyPath: s.ServerKey, - AllowAuto: s.AllowAutoCert, - Parent: s.Parent, - } - err := s.loader.Initialize() - if err != nil { - return err + if s.GetCertificate != nil { + getCertificate = s.GetCertificate + } else { + if s.ServerCert == "" { + return fmt.Errorf("server cert is missing") + } + + s.loader = &certloader.CertLoader{ + CertPath: s.ServerCert, + KeyPath: s.ServerKey, + AllowAuto: s.AllowAutoCert, + Parent: s.Parent, + } + err := s.loader.Initialize() + if err != nil { + return err + } + + getCertificate = s.loader.GetCertificate } tlsConfig = &tls.Config{ - GetCertificate: s.loader.GetCertificate(), + GetCertificate: getCertificate, } } diff --git a/internal/servers/moq/http_server.go b/internal/servers/moq/http_server.go index f7a7f685..0fa140b9 100644 --- a/internal/servers/moq/http_server.go +++ b/internal/servers/moq/http_server.go @@ -104,8 +104,7 @@ type httpServerParent interface { type httpServer struct { http2Address string http3Address string - serverCert string - serverKey string + getCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) allowOrigins []string trustedProxies conf.IPNetworks udpReadBufferSize uint @@ -125,16 +124,14 @@ func (s *httpServer) initialize() error { routerHTTP2.Use(s.onRequestHTTPS2) s.innerHTTP2 = &httpp.Server{ - Address: s.http2Address, - AllowOrigins: s.allowOrigins, - ReadTimeout: time.Duration(s.readTimeout), - WriteTimeout: time.Duration(s.writeTimeout), - Encryption: true, - ServerKey: s.serverKey, - ServerCert: s.serverCert, - AllowAutoCert: true, - Handler: routerHTTP2, - Parent: s, + Address: s.http2Address, + AllowOrigins: s.allowOrigins, + ReadTimeout: time.Duration(s.readTimeout), + WriteTimeout: time.Duration(s.writeTimeout), + Encryption: true, + GetCertificate: s.getCertificate, + Handler: routerHTTP2, + Parent: s, } err := s.innerHTTP2.Initialize() if err != nil { diff --git a/internal/servers/moq/native_listener.go b/internal/servers/moq/native_listener.go index b4c20b86..4b2997e8 100644 --- a/internal/servers/moq/native_listener.go +++ b/internal/servers/moq/native_listener.go @@ -3,7 +3,6 @@ package moq import ( "context" "crypto/tls" - "fmt" "net" "os" "strings" @@ -29,8 +28,7 @@ type nativeListenerParent interface { type nativeListener struct { address string - serverKey string - serverCert string + getCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) udpReadBufferSize uint parent nativeListenerParent @@ -65,16 +63,9 @@ func (s *nativeListener) initialize() error { } } - cert, err := tls.LoadX509KeyPair(s.serverCert, s.serverKey) - if err != nil { - s.ln.Close() - ctxCancel() - return fmt.Errorf("unable to load TLS keypair for native MoQ QUIC listener: %w", err) - } - tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{cert}, - NextProtos: supportedMoqtALPNs, + GetCertificate: s.getCertificate, + NextProtos: supportedMoqtALPNs, } listener, err := quic.Listen(s.ln, tlsConfig, &quic.Config{ diff --git a/internal/servers/moq/server.go b/internal/servers/moq/server.go index 47202858..98f2145a 100644 --- a/internal/servers/moq/server.go +++ b/internal/servers/moq/server.go @@ -10,6 +10,7 @@ import ( "github.com/google/uuid" + "github.com/bluenviron/mediamtx/internal/certloader" "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/defs" "github.com/bluenviron/mediamtx/internal/logger" @@ -95,6 +96,7 @@ type Server struct { ctx context.Context ctxCancel context.CancelFunc + loader *certloader.CertLoader httpServer *httpServer nativeListener *nativeListener sessions map[*session]struct{} @@ -121,11 +123,22 @@ func (s *Server) Initialize() error { s.chAPISessionsKick = make(chan serverAPISessionsKickReq) s.done = make(chan struct{}) + s.loader = &certloader.CertLoader{ + CertPath: s.ServerCert, + KeyPath: s.ServerKey, + AllowAuto: true, + Parent: s, + } + err := s.loader.Initialize() + if err != nil { + ctxCancel() + return err + } + s.httpServer = &httpServer{ http2Address: s.HTTP2Address, http3Address: s.HTTP3Address, - serverKey: s.ServerKey, - serverCert: s.ServerCert, + getCertificate: s.loader.GetCertificate, allowOrigins: s.AllowOrigins, trustedProxies: s.TrustedProxies, udpReadBufferSize: s.UDPReadBufferSize, @@ -134,22 +147,23 @@ func (s *Server) Initialize() error { pathManager: s.PathManager, parent: s, } - err := s.httpServer.initialize() + err = s.httpServer.initialize() if err != nil { + s.loader.Close() ctxCancel() return err } s.nativeListener = &nativeListener{ address: s.QUICAddress, - serverKey: s.ServerKey, - serverCert: s.ServerCert, + getCertificate: s.loader.GetCertificate, udpReadBufferSize: s.UDPReadBufferSize, parent: s, } err = s.nativeListener.initialize() if err != nil { s.httpServer.close() + s.loader.Close() ctxCancel() return err } @@ -268,6 +282,10 @@ outer: s.httpServer.close() + if s.loader != nil { + s.loader.Close() + } + wg.Wait() } diff --git a/internal/servers/rtmp/server.go b/internal/servers/rtmp/server.go index 9d11a253..c1e46e59 100644 --- a/internal/servers/rtmp/server.go +++ b/internal/servers/rtmp/server.go @@ -172,7 +172,7 @@ func (s *Server) Initialize() error { } net, addr := restrictnetwork.Restrict("tcp", s.Address) - s.ln, err = tlsListen(net, addr, &tls.Config{GetCertificate: s.loader.GetCertificate()}) + s.ln, err = tlsListen(net, addr, &tls.Config{GetCertificate: s.loader.GetCertificate}) if err != nil { return err } diff --git a/internal/servers/rtsp/server.go b/internal/servers/rtsp/server.go index 27220bce..6fa40f38 100644 --- a/internal/servers/rtsp/server.go +++ b/internal/servers/rtsp/server.go @@ -166,7 +166,7 @@ func (s *Server) Initialize() error { return err } - s.srv.TLSConfig = &tls.Config{GetCertificate: s.loader.GetCertificate()} + s.srv.TLSConfig = &tls.Config{GetCertificate: s.loader.GetCertificate} } s.srv.Listen = func(network, address string) (net.Listener, error) {