watchtower: use ECDH interface for watchtower session
This commit is contained in:
parent
535a22c590
commit
f97e7b9951
13
lnd.go
13
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{
|
||||
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,7 +579,9 @@ func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error {
|
||||
lnwallet.WitnessPubKey, false,
|
||||
)
|
||||
},
|
||||
NodeKeyECDH: towerPrivKey,
|
||||
NodeKeyECDH: keychain.NewPubKeyECDH(
|
||||
towerKeyDesc, activeChainControl.keyRing,
|
||||
),
|
||||
PublishTx: activeChainControl.wallet.PublishTransaction,
|
||||
ChainHash: *activeNetParams.GenesisHash,
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
},
|
||||
|
@ -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,
|
||||
},
|
||||
})
|
||||
}
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user