@@ -20,6 +20,9 @@ package rest
2020
2121import (
2222 "context"
23+ "crypto/tls"
24+ "crypto/x509"
25+ "encoding/pem"
2326 "errors"
2427 "fmt"
2528 "net/http"
@@ -79,7 +82,8 @@ func RunServer(config *myconfig.ServerConfig) error {
7982 var httpErr error
8083 if startTLS {
8184 zlog .S .Infof ("starting REST server with TLS on %v ..." , srv .Addr )
82- httpErr = srv .ListenAndServeTLS (config .TLS .CertFile , config .TLS .KeyFile )
85+ loadTLSConfig (config , srv )
86+ httpErr = srv .ListenAndServeTLS ("" , "" )
8387 } else {
8488 zlog .S .Infof ("starting REST server on %v ..." , srv .Addr )
8589 httpErr = srv .ListenAndServe ()
@@ -104,6 +108,94 @@ func RunServer(config *myconfig.ServerConfig) error {
104108 return nil
105109}
106110
111+ // loadTLSConfig loads the TLS config into memory (decrypting if required) and updates the Server config.
112+ func loadTLSConfig (config * myconfig.ServerConfig , srv * http.Server ) {
113+ pemBlocks := loadCertFile (config )
114+ pkey := loadPrivateKey (config )
115+ c , err := tls .X509KeyPair (pem .EncodeToMemory (pemBlocks [0 ]), pkey )
116+ if err != nil {
117+ zlog .S .Panicf ("Failed to load TLS key pair (%v - %v): %v" , config .TLS .KeyFile , config .TLS .CertFile , err )
118+ }
119+ cfg := & tls.Config {
120+ MinVersion : tls .VersionTLS12 ,
121+ CurvePreferences : []tls.CurveID {tls .CurveP521 , tls .CurveP384 , tls .CurveP256 },
122+ CipherSuites : []uint16 {
123+ tls .TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,
124+ },
125+ Certificates : []tls.Certificate {c },
126+ }
127+ // tls.TLS_RSA_WITH_AES_256_CBC_SHA,
128+ // tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
129+ // tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
130+ // tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
131+ // tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
132+ srv .TLSConfig = cfg
133+ srv .TLSNextProto = make (map [string ]func (* http.Server , * tls.Conn , http.Handler ), 0 )
134+ }
135+
136+ // loadCertFile load the certificate file into memory to use for hosting a TLS endpoint.
137+ func loadCertFile (config * myconfig.ServerConfig ) []* pem.Block {
138+ b , err := os .ReadFile (config .TLS .CertFile )
139+ if err != nil {
140+ zlog .S .Panicf ("Failed to load Cert file - %v: %v" , config .TLS .CertFile , err )
141+ }
142+ var pemBlocks []* pem.Block
143+ var v * pem.Block
144+ for {
145+ v , b = pem .Decode (b )
146+ if v == nil {
147+ break
148+ }
149+ if v .Type != "RSA PRIVATE KEY" && v .Type != "PRIVATE KEY" {
150+ pemBlocks = append (pemBlocks , v )
151+ } else {
152+ zlog .S .Warnf ("Unknown certificate type (%v): %v" , config .TLS .CertFile , v .Type )
153+ }
154+ }
155+ return pemBlocks
156+ }
157+
158+ // loadPrivateKey loads the private key from file and attempt to decrypt it (if it's encrypted).
159+ func loadPrivateKey (config * myconfig.ServerConfig ) []byte {
160+ var v * pem.Block
161+ var pkey []byte
162+ b , err := os .ReadFile (config .TLS .KeyFile )
163+ if err != nil {
164+ zlog .S .Panicf ("Failed to load Key file - %v: %v" , config .TLS .KeyFile , err )
165+ }
166+ for {
167+ v , b = pem .Decode (b )
168+ if v == nil {
169+ break
170+ }
171+ if v .Type == "RSA PRIVATE KEY" || v .Type == "PRIVATE KEY" {
172+ zlog .S .Debugf ("Private Key: %v - %v" , v .Type , v .Headers )
173+ // pvt, err := openssl.LoadPrivateKeyFromPEMWithPassword(encryptedPEM, passPhrase)
174+ //nolint:staticcheck
175+ if x509 .IsEncryptedPEMBlock (v ) {
176+ if len (config .TLS .Password ) == 0 {
177+ zlog .S .Panicf ("Need to configure TLS Password to decrypt encrypted Key file: %v" , config .TLS .KeyFile )
178+ }
179+ zlog .S .Infof ("Decrypting key..." )
180+ //nolint:staticcheck
181+ pkey , err = x509 .DecryptPEMBlock (v , []byte (config .TLS .Password ))
182+ if err != nil {
183+ zlog .S .Panicf ("Failed to decrypt Key File (%v): %v" , config .TLS .KeyFile , err )
184+ }
185+ pkey = pem .EncodeToMemory (& pem.Block {
186+ Type : v .Type ,
187+ Bytes : pkey ,
188+ })
189+ } else {
190+ pkey = pem .EncodeToMemory (v )
191+ }
192+ } else {
193+ zlog .S .Warnf ("Unexpected certificate type (%v): %v" , config .TLS .KeyFile , v .Type )
194+ }
195+ }
196+ return pkey
197+ }
198+
107199// checkFile validates if the given file exists or not.
108200func checkFile (filename string ) (bool , error ) {
109201 if len (filename ) == 0 {
0 commit comments