diff --git a/lnd.go b/lnd.go index ed347aac..6a900773 100644 --- a/lnd.go +++ b/lnd.go @@ -557,17 +557,14 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error { } defer towerDB.Close() - towerPrivKey, err := activeChainControl.wallet.DerivePrivKey( - keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamilyTowerID, - Index: 0, - }, + towerKeyDesc, err := activeChainControl.keyRing.DeriveKey( + keychain.KeyLocator{ + Family: keychain.KeyFamilyTowerID, + Index: 0, }, ) if err != nil { - err := fmt.Errorf("unable to derive watchtower "+ - "private key: %v", err) + err := fmt.Errorf("error deriving tower key: %v", err) ltndLog.Error(err) return err } @@ -582,9 +579,11 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error { lnwallet.WitnessPubKey, false, ) }, - NodeKeyECDH: towerPrivKey, - PublishTx: activeChainControl.wallet.PublishTransaction, - ChainHash: *activeNetParams.GenesisHash, + NodeKeyECDH: keychain.NewPubKeyECDH( + towerKeyDesc, activeChainControl.keyRing, + ), + PublishTx: activeChainControl.wallet.PublishTransaction, + ChainHash: *activeNetParams.GenesisHash, } // If there is a tor controller (user wants auto hidden services), then diff --git a/watchtower/config.go b/watchtower/config.go index 2b649dbc..4da7ba30 100644 --- a/watchtower/config.go +++ b/watchtower/config.go @@ -5,10 +5,10 @@ import ( "net" "time" - "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/tor" "github.com/lightningnetwork/lnd/watchtower/lookout" ) @@ -65,7 +65,7 @@ type Config struct { // NodeKeyECDH is the ECDH capable wrapper of the key to be used in // accepting new brontide connections. - NodeKeyECDH *btcec.PrivateKey + NodeKeyECDH keychain.SingleKeyECDH // PublishTx provides the ability to send a signed transaction to the // network. diff --git a/watchtower/standalone.go b/watchtower/standalone.go index 26ebed8c..8e56d962 100644 --- a/watchtower/standalone.go +++ b/watchtower/standalone.go @@ -72,7 +72,7 @@ func New(cfg *Config) (*Standalone, error) { listeners := make([]net.Listener, 0, len(cfg.ListenAddrs)) for _, listenAddr := range cfg.ListenAddrs { listener, err := brontide.NewListener( - nil/*TODO fix in next commit*/, listenAddr.String(), + cfg.NodeKeyECDH, listenAddr.String(), ) if err != nil { return nil, err diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index de58ecc2..e85ea9cd 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -11,6 +11,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/watchtower/wtdb" @@ -337,7 +338,7 @@ func New(config *Config) (*TowerClient, error) { // NOTE: This method should only be used when deserialization of a // ClientSession's Tower and SessionPrivKey fields is desired, otherwise, the // existing ListClientSessions method should be used. -func getClientSessions(db DB, keyRing SecretKeyRing, forTower *wtdb.TowerID, +func getClientSessions(db DB, keyRing ECDHKeyRing, forTower *wtdb.TowerID, passesFilter func(*wtdb.ClientSession) bool) ( map[wtdb.SessionID]*wtdb.ClientSession, error) { @@ -358,11 +359,14 @@ func getClientSessions(db DB, keyRing SecretKeyRing, forTower *wtdb.TowerID, } s.Tower = tower - sessionKey, err := DeriveSessionKey(keyRing, s.KeyIndex) + towerKeyDesc, err := keyRing.DeriveKey(keychain.KeyLocator{ + Family: keychain.KeyFamilyTowerSession, + Index: s.KeyIndex, + }) if err != nil { return nil, err } - s.SessionKeyECDH = sessionKey + s.SessionKeyECDH = keychain.NewPubKeyECDH(towerKeyDesc, keyRing) // If an optional filter was provided, use it to filter out any // undesired sessions. @@ -897,10 +901,10 @@ func (c *TowerClient) taskRejected(task *backupTask, curStatus reserveStatus) { // dial connects the peer at addr using privKey as our secret key for the // connection. The connection will use the configured Net's resolver to resolve // the address for either Tor or clear net connections. -func (c *TowerClient) dial(privKey *btcec.PrivateKey, +func (c *TowerClient) dial(localKey keychain.SingleKeyECDH, addr *lnwire.NetAddress) (wtserver.Peer, error) { - return c.cfg.AuthDial(privKey, addr, c.cfg.Dial) + return c.cfg.AuthDial(localKey, addr, c.cfg.Dial) } // readMessage receives and parses the next message from the given Peer. An diff --git a/watchtower/wtclient/client_test.go b/watchtower/wtclient/client_test.go index fda9c0e2..7210a0a7 100644 --- a/watchtower/wtclient/client_test.go +++ b/watchtower/wtclient/client_test.go @@ -101,10 +101,10 @@ func (m *mockNet) ResolveTCPAddr(network string, address string) (*net.TCPAddr, panic("not implemented") } -func (m *mockNet) AuthDial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress, +func (m *mockNet) AuthDial(local keychain.SingleKeyECDH, netAddr *lnwire.NetAddress, dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error) { - localPk := localPriv.PubKey() + localPk := local.PubKey() localAddr := &net.TCPAddr{ IP: net.IP{0x32, 0x31, 0x30, 0x29}, Port: 36723, @@ -401,6 +401,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { if err != nil { t.Fatalf("Unable to generate tower private key: %v", err) } + privKeyECDH := &keychain.PrivKeyECDH{PrivKey: privKey} towerPubKey := privKey.PubKey() @@ -416,7 +417,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness { DB: serverDB, ReadTimeout: timeout, WriteTimeout: timeout, - NodeKeyECDH: privKey, + NodeKeyECDH: privKeyECDH, NewAddress: func() (btcutil.Address, error) { return addr, nil }, diff --git a/watchtower/wtclient/derivation.go b/watchtower/wtclient/derivation.go deleted file mode 100644 index 0dcb59a1..00000000 --- a/watchtower/wtclient/derivation.go +++ /dev/null @@ -1,24 +0,0 @@ -package wtclient - -import ( - "github.com/btcsuite/btcd/btcec" - "github.com/lightningnetwork/lnd/keychain" -) - -// DeriveSessionKey accepts an session key index for an existing session and -// derives the HD private key to be used to authenticate the brontide transport -// and authenticate requests sent to the tower. The key will use the -// keychain.KeyFamilyTowerSession and the provided index, giving a BIP43 -// derivation path of: -// -// * m/1017'/coinType'/8/0/index -func DeriveSessionKey(keyRing ECDHKeyRing, - index uint32) (*btcec.PrivateKey, error) { - - return keyRing.DerivePrivKey(keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamilyTowerSession, - Index: index, - }, - }) -} diff --git a/watchtower/wtclient/interface.go b/watchtower/wtclient/interface.go index c9da8314..d532ee24 100644 --- a/watchtower/wtclient/interface.go +++ b/watchtower/wtclient/interface.go @@ -102,14 +102,14 @@ type Dial func(net, addr string) (net.Conn, error) // AuthDialer connects to a remote node using an authenticated transport, such as // brontide. The dialer argument is used to specify a resolver, which allows // this method to be used over Tor or clear net connections. -type AuthDialer func(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress, +type AuthDialer func(localKey keychain.SingleKeyECDH, netAddr *lnwire.NetAddress, dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error) // AuthDial is the watchtower client's default method of dialing. -func AuthDial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress, +func AuthDial(localKey keychain.SingleKeyECDH, netAddr *lnwire.NetAddress, dialer func(string, string) (net.Conn, error)) (wtserver.Peer, error) { - return brontide.Dial(nil/*TODO fix in next commit*/, netAddr, dialer) + return brontide.Dial(localKey, netAddr, dialer) } // ECDHKeyRing abstracts the ability to derive shared ECDH keys given a @@ -117,10 +117,6 @@ func AuthDial(localPriv *btcec.PrivateKey, netAddr *lnwire.NetAddress, type ECDHKeyRing interface { keychain.ECDHRing - // DerivePrivKey derives the private key from the root seed using a - // key descriptor specifying the key's derivation path. - DerivePrivKey(loc keychain.KeyDescriptor) (*btcec.PrivateKey, error) - // DeriveKey attempts to derive an arbitrary key specified by the // passed KeyLocator. This may be used in several recovery scenarios, // or when manually rotating something like our current default node diff --git a/watchtower/wtclient/session_negotiator.go b/watchtower/wtclient/session_negotiator.go index f2ed5232..67be526d 100644 --- a/watchtower/wtclient/session_negotiator.go +++ b/watchtower/wtclient/session_negotiator.go @@ -5,8 +5,8 @@ import ( "sync" "time" - "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/watchtower/blob" "github.com/lightningnetwork/lnd/watchtower/wtdb" @@ -58,7 +58,8 @@ type NegotiatorConfig struct { // Dial initiates an outbound brontide connection to the given address // using a specified private key. The peer is returned in the event of a // successful connection. - Dial func(*btcec.PrivateKey, *lnwire.NetAddress) (wtserver.Peer, error) + Dial func(keychain.SingleKeyECDH, *lnwire.NetAddress) (wtserver.Peer, + error) // SendMessage writes a wtwire message to remote peer. SendMessage func(wtserver.Peer, wtwire.Message) error @@ -315,13 +316,21 @@ func (n *sessionNegotiator) createSession(tower *wtdb.Tower, return ErrNoTowerAddrs } - sessionPriv, err := DeriveSessionKey(n.cfg.SecretKeyRing, keyIndex) + sessionKeyDesc, err := n.cfg.SecretKeyRing.DeriveKey( + keychain.KeyLocator{ + Family: keychain.KeyFamilyTowerSession, + Index: keyIndex, + }, + ) if err != nil { return err } + sessionKey := keychain.NewPubKeyECDH( + sessionKeyDesc, n.cfg.SecretKeyRing, + ) for _, lnAddr := range tower.LNAddrs() { - err = n.tryAddress(sessionPriv, keyIndex, tower, lnAddr) + err := n.tryAddress(sessionKey, keyIndex, tower, lnAddr) switch { case err == ErrPermanentTowerFailure: // TODO(conner): report to iterator? can then be reset @@ -346,11 +355,11 @@ func (n *sessionNegotiator) createSession(tower *wtdb.Tower, // The address should belong to the tower's set of addresses. This method only // returns true if all steps succeed and the new session has been persisted, and // fails otherwise. -func (n *sessionNegotiator) tryAddress(privKey *btcec.PrivateKey, +func (n *sessionNegotiator) tryAddress(sessionKey keychain.SingleKeyECDH, keyIndex uint32, tower *wtdb.Tower, lnAddr *lnwire.NetAddress) error { // Connect to the tower address using our generated session key. - conn, err := n.cfg.Dial(privKey, lnAddr) + conn, err := n.cfg.Dial(sessionKey, lnAddr) if err != nil { return err } @@ -417,9 +426,7 @@ func (n *sessionNegotiator) tryAddress(privKey *btcec.PrivateKey, // TODO(conner): validate reward address rewardPkScript := createSessionReply.Data - sessionID := wtdb.NewSessionIDFromPubKey( - privKey.PubKey(), - ) + sessionID := wtdb.NewSessionIDFromPubKey(sessionKey.PubKey()) clientSession := &wtdb.ClientSession{ ClientSessionBody: wtdb.ClientSessionBody{ TowerID: tower.ID, @@ -428,7 +435,7 @@ func (n *sessionNegotiator) tryAddress(privKey *btcec.PrivateKey, RewardPkScript: rewardPkScript, }, Tower: tower, - SessionKeyECDH: privKey, + SessionKeyECDH: sessionKey, ID: sessionID, } diff --git a/watchtower/wtclient/session_queue.go b/watchtower/wtclient/session_queue.go index b383644c..ffc61892 100644 --- a/watchtower/wtclient/session_queue.go +++ b/watchtower/wtclient/session_queue.go @@ -6,9 +6,9 @@ import ( "sync" "time" - "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/watchtower/wtdb" "github.com/lightningnetwork/lnd/watchtower/wtserver" @@ -41,8 +41,8 @@ type sessionQueueConfig struct { // Dial allows the client to dial the tower using it's public key and // net address. - Dial func(*btcec.PrivateKey, - *lnwire.NetAddress) (wtserver.Peer, error) + Dial func(keychain.SingleKeyECDH, *lnwire.NetAddress) (wtserver.Peer, + error) // SendMessage encodes, encrypts, and writes a message to the given peer. SendMessage func(wtserver.Peer, wtwire.Message) error diff --git a/watchtower/wtdb/client_session.go b/watchtower/wtdb/client_session.go index eb76528c..1d3e01f5 100644 --- a/watchtower/wtdb/client_session.go +++ b/watchtower/wtdb/client_session.go @@ -4,7 +4,7 @@ import ( "fmt" "io" - "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/watchtower/blob" "github.com/lightningnetwork/lnd/watchtower/wtpolicy" @@ -65,7 +65,7 @@ type ClientSession struct { // // NOTE: This value is not serialized. It is derived using the KeyIndex // on startup to avoid storing private keys on disk. - SessionKeyECDH *btcec.PrivateKey + SessionKeyECDH keychain.SingleKeyECDH } // ClientSessionBody represents the primary components of a ClientSession that diff --git a/watchtower/wtmock/keyring.go b/watchtower/wtmock/keyring.go index 3d23ea04..dc9eef12 100644 --- a/watchtower/wtmock/keyring.go +++ b/watchtower/wtmock/keyring.go @@ -20,29 +20,6 @@ func NewSecretKeyRing() *SecretKeyRing { } } -// DerivePrivKey derives the private key for a given key descriptor. If -// this method is called twice with the same argument, it will return the same -// private key. -func (m *SecretKeyRing) DerivePrivKey( - desc keychain.KeyDescriptor) (*btcec.PrivateKey, error) { - - m.mu.Lock() - defer m.mu.Unlock() - - if key, ok := m.keys[desc.KeyLocator]; ok { - return key, nil - } - - privKey, err := btcec.NewPrivateKey(btcec.S256()) - if err != nil { - return nil, err - } - - m.keys[desc.KeyLocator] = privKey - - return privKey, nil -} - // DeriveKey attempts to derive an arbitrary key specified by the // passed KeyLocator. This may be used in several recovery scenarios, // or when manually rotating something like our current default node diff --git a/watchtower/wtserver/server.go b/watchtower/wtserver/server.go index 0152839a..faf39819 100644 --- a/watchtower/wtserver/server.go +++ b/watchtower/wtserver/server.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/connmgr" "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/watchtower/wtdb" "github.com/lightningnetwork/lnd/watchtower/wtwire" @@ -35,7 +35,7 @@ type Config struct { // NodeKeyECDH is the the ECDH capable wrapper of the key to be used in // accepting new brontide connections. - NodeKeyECDH *btcec.PrivateKey + NodeKeyECDH keychain.SingleKeyECDH // Listeners specifies which address to which clients may connect. Listeners []net.Listener