|
|
|
@ -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.
|
|
|
|
|