lnd: prepare TLS code for extraction

This commit is contained in:
Oliver Gugger 2019-11-14 09:34:47 +01:00
parent e8b306b0ff
commit bfe10376f3
No known key found for this signature in database
GPG Key ID: 8E4256593F177720

96
lnd.go
View File

@ -57,8 +57,10 @@ import (
) )
const ( const (
// Make certificate valid for 14 months. // defaultAutogenCertValidity is the default validity of a self-signed
autogenCertValidity = 14 /*months*/ * 30 /*days*/ * 24 * time.Hour // certificate. The value corresponds to 14 months
// (14 months * 30 days * 24 hours).
defaultAutogenCertValidity = 14 * 30 * 24 * time.Hour
) )
var ( var (
@ -77,7 +79,8 @@ var (
serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128)
/* /*
* These cipher suites fit the following criteria: * tlsCipherSuites is the list of cipher suites we accept for TLS
* connections. These cipher suites fit the following criteria:
* - Don't use outdated algorithms like SHA-1 and 3DES * - Don't use outdated algorithms like SHA-1 and 3DES
* - Don't use ECB mode or other insecure symmetric methods * - Don't use ECB mode or other insecure symmetric methods
* - Included in the TLS v1.2 suite * - Included in the TLS v1.2 suite
@ -661,28 +664,28 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs,
tlsExtraDomains []string, rpcListeners []net.Addr) (*tls.Config, tlsExtraDomains []string, rpcListeners []net.Addr) (*tls.Config,
*credentials.TransportCredentials, string, error) { *credentials.TransportCredentials, string, error) {
// Ensure we create TLS key and certificate if they don't exist // Ensure we create TLS key and certificate if they don't exist.
if !fileExists(tlsCertPath) && !fileExists(tlsKeyPath) { if !fileExists(tlsCertPath) && !fileExists(tlsKeyPath) {
rpcsLog.Infof("Generating TLS certificates...")
err := genCertPair( err := genCertPair(
tlsCertPath, tlsKeyPath, tlsExtraIPs, tlsExtraDomains, "lnd autogenerated cert", tlsCertPath, tlsKeyPath,
tlsExtraIPs, tlsExtraDomains,
defaultAutogenCertValidity,
) )
if err != nil { if err != nil {
return nil, nil, "", err return nil, nil, "", err
} }
rpcsLog.Infof("Done generating TLS certificates")
} }
certData, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath) certData, parsedCert, err := loadCert(tlsCertPath, tlsKeyPath)
if err != nil { if err != nil {
return nil, nil, "", err return nil, nil, "", err
} }
cert, err := x509.ParseCertificate(certData.Certificate[0]) // If the certificate expired, delete it and the TLS key and generate a
if err != nil { // new pair.
return nil, nil, "", err if time.Now().After(parsedCert.NotAfter) {
}
// If the certificate expired, delete it and the TLS key and generate a new pair
if time.Now().After(cert.NotAfter) {
ltndLog.Info("TLS certificate is expired, generating a new one") ltndLog.Info("TLS certificate is expired, generating a new one")
err := os.Remove(tlsCertPath) err := os.Remove(tlsCertPath)
@ -695,21 +698,19 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs,
return nil, nil, "", err return nil, nil, "", err
} }
rpcsLog.Infof("Generating TLS certificates...")
err = genCertPair( err = genCertPair(
tlsCertPath, tlsKeyPath, tlsExtraIPs, tlsExtraDomains, "lnd autogenerated cert", tlsCertPath, tlsKeyPath,
tlsExtraIPs, tlsExtraDomains,
defaultAutogenCertValidity,
) )
if err != nil { if err != nil {
return nil, nil, "", err return nil, nil, "", err
} }
rpcsLog.Infof("Done generating TLS certificates")
}
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{certData},
CipherSuites: tlsCipherSuites,
MinVersion: tls.VersionTLS12,
} }
tlsCfg := tlsConfFromCert(certData)
restCreds, err := credentials.NewClientTLSFromFile(tlsCertPath, "") restCreds, err := credentials.NewClientTLSFromFile(tlsCertPath, "")
if err != nil { if err != nil {
return nil, nil, "", err return nil, nil, "", err
@ -742,6 +743,41 @@ func fileExists(name string) bool {
return true return true
} }
// 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.
func loadCert(certPath, keyPath string) (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.LoadX509KeyPair(certPath, keyPath)
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 {
return &tls.Config{
Certificates: []tls.Certificate{certData},
CipherSuites: tlsCipherSuites,
MinVersion: tls.VersionTLS12,
}
}
// genCertPair generates a key/cert pair to the paths provided. The // genCertPair generates a key/cert pair to the paths provided. The
// auto-generated certificates should *not* be used in production for public // auto-generated certificates should *not* be used in production for public
// access as they're self-signed and don't necessarily contain all of the // access as they're self-signed and don't necessarily contain all of the
@ -750,14 +786,11 @@ func fileExists(name string) bool {
// //
// This function is adapted from https://github.com/btcsuite/btcd and // This function is adapted from https://github.com/btcsuite/btcd and
// https://github.com/btcsuite/btcutil // https://github.com/btcsuite/btcutil
func genCertPair(certFile, keyFile string, tlsExtraIPs, func genCertPair(org, certFile, keyFile string, tlsExtraIPs,
tlsExtraDomains []string) error { tlsExtraDomains []string, certValidity time.Duration) error {
rpcsLog.Infof("Generating TLS certificates...")
org := "lnd autogenerated cert"
now := time.Now() now := time.Now()
validUntil := now.Add(autogenCertValidity) validUntil := now.Add(certValidity)
// Check that the certificate validity isn't past the ASN.1 end of time. // Check that the certificate validity isn't past the ASN.1 end of time.
if validUntil.After(endOfTime) { if validUntil.After(endOfTime) {
@ -776,7 +809,7 @@ func genCertPair(certFile, keyFile string, tlsExtraIPs,
// addIP appends an IP address only if it isn't already in the slice. // addIP appends an IP address only if it isn't already in the slice.
addIP := func(ipAddr net.IP) { addIP := func(ipAddr net.IP) {
for _, ip := range ipAddresses { for _, ip := range ipAddresses {
if bytes.Equal(ip, ipAddr) { if ip.Equal(ipAddr) {
return return
} }
} }
@ -806,8 +839,10 @@ func genCertPair(certFile, keyFile string, tlsExtraIPs,
// Collect the host's names into a slice. // Collect the host's names into a slice.
host, err := os.Hostname() host, err := os.Hostname()
if err != nil { if err != nil {
rpcsLog.Errorf("Failed getting hostname, falling back to "+ // Nothing much we can do here, other than falling back to
"localhost: %v", err) // localhost as fallback. A hostname can still be provided with
// the tlsExtraDomain parameter if the problem persists on a
// system.
host = "localhost" host = "localhost"
} }
@ -879,7 +914,6 @@ func genCertPair(certFile, keyFile string, tlsExtraIPs,
return err return err
} }
rpcsLog.Infof("Done generating TLS certificates")
return nil return nil
} }