From dbbb169e0668ea4c259e6d65133ab6e32df16f44 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 13 Nov 2019 14:03:10 +0100 Subject: [PATCH] lnd: use TLS code from cert package --- cert/selfsigned.go | 8 +- cert/tls.go | 8 +- lnd.go | 229 ++------------------------------------------- 3 files changed, 17 insertions(+), 228 deletions(-) diff --git a/cert/selfsigned.go b/cert/selfsigned.go index 7e3dbf63..e8bd5710 100644 --- a/cert/selfsigned.go +++ b/cert/selfsigned.go @@ -17,10 +17,10 @@ import ( ) const ( - // defaultAutogenCertValidity is the default validity of a self-signed + // DefaultAutogenValidity is the default validity of a self-signed // certificate. The value corresponds to 14 months // (14 months * 30 days * 24 hours). - defaultAutogenCertValidity = 14 * 30 * 24 * time.Hour + DefaultAutogenValidity = 14 * 30 * 24 * time.Hour ) var ( @@ -31,7 +31,7 @@ var ( serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) ) -// 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 // access as they're self-signed and don't necessarily contain all of the // desired hostnames for the service. For production/public use, consider a @@ -39,7 +39,7 @@ var ( // // This function is adapted from https://github.com/btcsuite/btcd and // https://github.com/btcsuite/btcutil -func genCertPair(org, certFile, keyFile string, tlsExtraIPs, +func GenCertPair(org, certFile, keyFile string, tlsExtraIPs, tlsExtraDomains []string, certValidity time.Duration) error { now := time.Now() diff --git a/cert/tls.go b/cert/tls.go index 49da5f46..a8783158 100644 --- a/cert/tls.go +++ b/cert/tls.go @@ -24,10 +24,10 @@ var ( } ) -// loadCert loads a certificate and its corresponding private key from the PEM +// 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, +func LoadCert(certPath, keyPath string) (tls.Certificate, *x509.Certificate, error) { // The certData returned here is just a wrapper around the PEM blocks @@ -49,9 +49,9 @@ func loadCert(certPath, keyPath string) (tls.Certificate, *x509.Certificate, return certData, x509Cert, nil } -// tLSConfFromCert returns the default TLS configuration used for a server, +// TLSConfFromCert returns the default TLS configuration used for a server, // using the given certificate as identity. -func tlsConfFromCert(certData tls.Certificate) *tls.Config { +func TLSConfFromCert(certData tls.Certificate) *tls.Config { return &tls.Config{ Certificates: []tls.Certificate{certData}, CipherSuites: tlsCipherSuites, diff --git a/lnd.go b/lnd.go index 2d9264aa..06379c1d 100644 --- a/lnd.go +++ b/lnd.go @@ -5,18 +5,10 @@ package lnd import ( - "bytes" "context" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" "fmt" "io/ioutil" - "math/big" "net" "net/http" "os" @@ -42,6 +34,7 @@ import ( "github.com/lightningnetwork/lnd/autopilot" "github.com/lightningnetwork/lnd/build" + "github.com/lightningnetwork/lnd/cert" "github.com/lightningnetwork/lnd/chanacceptor" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" @@ -56,13 +49,6 @@ import ( "github.com/lightningnetwork/lnd/watchtower/wtdb" ) -const ( - // defaultAutogenCertValidity is the default validity of a self-signed - // certificate. The value corresponds to 14 months - // (14 months * 30 days * 24 hours). - defaultAutogenCertValidity = 14 * 30 * 24 * time.Hour -) - var ( cfg *config registeredChains = newChainRegistry() @@ -71,29 +57,6 @@ var ( // network. This path will hold the files related to each different // network. networkDir string - - // End of ASN.1 time. - endOfTime = time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC) - - // Max serial number. - serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) - - /* - * 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 ECB mode or other insecure symmetric methods - * - Included in the TLS v1.2 suite - * - Are available in the Go 1.7.6 standard library (more are - * available in 1.8.3 and will be added after lnd no longer - * supports 1.7, including suites that support CBC mode) - **/ - tlsCipherSuites = []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - } ) // ListenerCfg is a wrapper around custom listeners that can be passed to lnd @@ -667,10 +630,10 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs, // Ensure we create TLS key and certificate if they don't exist. if !fileExists(tlsCertPath) && !fileExists(tlsKeyPath) { rpcsLog.Infof("Generating TLS certificates...") - err := genCertPair( + err := cert.GenCertPair( "lnd autogenerated cert", tlsCertPath, tlsKeyPath, tlsExtraIPs, tlsExtraDomains, - defaultAutogenCertValidity, + cert.DefaultAutogenValidity, ) if err != nil { return nil, nil, "", err @@ -678,7 +641,7 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs, rpcsLog.Infof("Done generating TLS certificates") } - certData, parsedCert, err := loadCert(tlsCertPath, tlsKeyPath) + certData, parsedCert, err := cert.LoadCert(tlsCertPath, tlsKeyPath) if err != nil { return nil, nil, "", err } @@ -698,19 +661,19 @@ func getTLSConfig(tlsCertPath string, tlsKeyPath string, tlsExtraIPs, return nil, nil, "", err } - rpcsLog.Infof("Generating TLS certificates...") - err = genCertPair( + rpcsLog.Infof("Renewing TLS certificates...") + err = cert.GenCertPair( "lnd autogenerated cert", tlsCertPath, tlsKeyPath, tlsExtraIPs, tlsExtraDomains, - defaultAutogenCertValidity, + cert.DefaultAutogenValidity, ) if err != nil { return nil, nil, "", err } - rpcsLog.Infof("Done generating TLS certificates") + rpcsLog.Infof("Done renewing TLS certificates") } - tlsCfg := tlsConfFromCert(certData) + tlsCfg := cert.TLSConfFromCert(certData) restCreds, err := credentials.NewClientTLSFromFile(tlsCertPath, "") if err != nil { return nil, nil, "", err @@ -743,180 +706,6 @@ func fileExists(name string) bool { 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 -// 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 -// desired hostnames for the service. For production/public use, consider a -// real PKI. -// -// This function is adapted from https://github.com/btcsuite/btcd and -// https://github.com/btcsuite/btcutil -func genCertPair(org, certFile, keyFile string, tlsExtraIPs, - tlsExtraDomains []string, certValidity time.Duration) error { - - now := time.Now() - validUntil := now.Add(certValidity) - - // Check that the certificate validity isn't past the ASN.1 end of time. - if validUntil.After(endOfTime) { - validUntil = endOfTime - } - - // Generate a serial number that's below the serialNumberLimit. - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - return fmt.Errorf("failed to generate serial number: %s", err) - } - - // Collect the host's IP addresses, including loopback, in a slice. - ipAddresses := []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")} - - // addIP appends an IP address only if it isn't already in the slice. - addIP := func(ipAddr net.IP) { - for _, ip := range ipAddresses { - if ip.Equal(ipAddr) { - return - } - } - ipAddresses = append(ipAddresses, ipAddr) - } - - // Add all the interface IPs that aren't already in the slice. - addrs, err := net.InterfaceAddrs() - if err != nil { - return err - } - for _, a := range addrs { - ipAddr, _, err := net.ParseCIDR(a.String()) - if err == nil { - addIP(ipAddr) - } - } - - // Add extra IPs to the slice. - for _, ip := range tlsExtraIPs { - ipAddr := net.ParseIP(ip) - if ipAddr != nil { - addIP(ipAddr) - } - } - - // Collect the host's names into a slice. - host, err := os.Hostname() - if err != nil { - // Nothing much we can do here, other than falling back to - // localhost as fallback. A hostname can still be provided with - // the tlsExtraDomain parameter if the problem persists on a - // system. - host = "localhost" - } - - dnsNames := []string{host} - if host != "localhost" { - dnsNames = append(dnsNames, "localhost") - } - dnsNames = append(dnsNames, tlsExtraDomains...) - - // Also add fake hostnames for unix sockets, otherwise hostname - // verification will fail in the client. - dnsNames = append(dnsNames, "unix", "unixpacket") - - // Generate a private key for the certificate. - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return err - } - - // Construct the certificate template. - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{org}, - CommonName: host, - }, - NotBefore: now.Add(-time.Hour * 24), - NotAfter: validUntil, - - KeyUsage: x509.KeyUsageKeyEncipherment | - x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - IsCA: true, // so can sign self. - BasicConstraintsValid: true, - - DNSNames: dnsNames, - IPAddresses: ipAddresses, - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, - &template, &priv.PublicKey, priv) - if err != nil { - return fmt.Errorf("failed to create certificate: %v", err) - } - - certBuf := &bytes.Buffer{} - err = pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", - Bytes: derBytes}) - if err != nil { - return fmt.Errorf("failed to encode certificate: %v", err) - } - - keybytes, err := x509.MarshalECPrivateKey(priv) - if err != nil { - return fmt.Errorf("unable to encode privkey: %v", err) - } - keyBuf := &bytes.Buffer{} - err = pem.Encode(keyBuf, &pem.Block{Type: "EC PRIVATE KEY", - Bytes: keybytes}) - if err != nil { - return fmt.Errorf("failed to encode private key: %v", err) - } - - // Write cert and key files. - if err = ioutil.WriteFile(certFile, certBuf.Bytes(), 0644); err != nil { - return err - } - if err = ioutil.WriteFile(keyFile, keyBuf.Bytes(), 0600); err != nil { - os.Remove(certFile) - return err - } - - return nil -} - // genMacaroons generates three macaroon files; one admin-level, one for // invoice access and one read-only. These can also be used to generate more // granular macaroons.