cert: add TLS reloader and return bytes from GenCert
Co-authored-by: gkrizek <graham@krizek.io>
This commit is contained in:
5 files changed
+239
-40
No files matched your search
+91
@@ -3,6 +3,8 @@ package cert
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -24,6 +26,22 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// GetCertBytesFromPath reads the TLS certificate and key files at the given
|
||||
// certPath and keyPath and returns the file bytes.
|
||||
func GetCertBytesFromPath(certPath, keyPath string) (certBytes,
|
||||
keyBytes []byte, err error) {
|
||||
|
||||
certBytes, err = ioutil.ReadFile(certPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyBytes, err = ioutil.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return certBytes, keyBytes, nil
|
||||
}
|
||||
|
||||
// LoadCert loads a certificate and its corresponding private key from the PEM
|
||||
// files indicated and returns the certificate in the two formats it is most
|
||||
// commonly used.
|
||||
@@ -49,6 +67,31 @@ func LoadCert(certPath, keyPath string) (tls.Certificate, *x509.Certificate,
|
||||
return certData, x509Cert, nil
|
||||
}
|
||||
|
||||
// LoadCertFromBytes loads a certificate and its corresponding private key from
|
||||
// the PEM bytes indicated and returns the certificate in the two formats it is
|
||||
// most commonly used.
|
||||
func LoadCertFromBytes(certBytes, keyBytes []byte) (tls.Certificate,
|
||||
*x509.Certificate, error) {
|
||||
|
||||
// The certData returned here is just a wrapper around the PEM blocks
|
||||
// loaded from the file. The PEM is not yet fully parsed but a basic
|
||||
// check is performed that the certificate and private key actually
|
||||
// belong together.
|
||||
certData, err := tls.X509KeyPair(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
|
||||
// Now parse the the PEM block of the certificate into its x509 data
|
||||
// structure so it can be examined in more detail.
|
||||
x509Cert, err := x509.ParseCertificate(certData.Certificate[0])
|
||||
if err != nil {
|
||||
return tls.Certificate{}, nil, err
|
||||
}
|
||||
|
||||
return certData, x509Cert, nil
|
||||
}
|
||||
|
||||
// TLSConfFromCert returns the default TLS configuration used for a server,
|
||||
// using the given certificate as identity.
|
||||
func TLSConfFromCert(certData tls.Certificate) *tls.Config {
|
||||
@@ -58,3 +101,51 @@ func TLSConfFromCert(certData tls.Certificate) *tls.Config {
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
}
|
||||
|
||||
// TLSReloader updates the TLS certificate without restarting the server.
|
||||
type TLSReloader struct {
|
||||
certMu sync.RWMutex
|
||||
cert *tls.Certificate
|
||||
}
|
||||
|
||||
// NewTLSReloader is used to create a new TLS Reloader that will be used
|
||||
// to update the TLS certificate without restarting the server.
|
||||
func NewTLSReloader(certBytes, keyBytes []byte) (*TLSReloader, error) {
|
||||
cert, _, err := LoadCertFromBytes(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TLSReloader{
|
||||
cert: &cert,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AttemptReload will make an attempt to update the TLS certificate
|
||||
// and key used by the server.
|
||||
func (t *TLSReloader) AttemptReload(certBytes, keyBytes []byte) error {
|
||||
newCert, _, err := LoadCertFromBytes(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.certMu.Lock()
|
||||
t.cert = &newCert
|
||||
t.certMu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCertificateFunc is used in the server's TLS configuration to
|
||||
// determine the correct TLS certificate to server on a request.
|
||||
func (t *TLSReloader) GetCertificateFunc() func(*tls.ClientHelloInfo) (
|
||||
*tls.Certificate, error) {
|
||||
|
||||
return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||
error) {
|
||||
|
||||
t.certMu.RLock()
|
||||
defer t.certMu.RUnlock()
|
||||
|
||||
return t.cert, nil
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user