Perform signature verifiction when generating addresses.

This change adds an additional check when creating a new wallet or
extending the keypool.  All public and private keypairs are parsed
from their serialized forms, and an ecdsa signature is created and
verified using the keypairs.  If the verifiction fails at any point,
the wallet creation or keypool extension is aborted to prevent any
errors where an address is returned to a user, but any funds send to
that address are unspendable due to a mismatched keypair.
This commit is contained in:
Josh Rickmar 2013-12-03 12:33:37 -05:00
parent eeb72db8b5
commit c54af23849
3 changed files with 46 additions and 3 deletions

View file

@ -444,7 +444,6 @@ func (a *Account) ActivePaymentAddresses() map[string]struct{} {
// NewAddress returns a new payment address for an account.
func (a *Account) NewAddress() (string, error) {
a.mtx.Lock()
defer a.mtx.Unlock()
// Get current block's height and hash.
bs, err := GetCurBlock()
@ -460,6 +459,7 @@ func (a *Account) NewAddress() (string, error) {
// Write updated wallet to disk.
a.dirty = true
a.mtx.Unlock()
if err = a.writeDirtyToDisk(); err != nil {
log.Errorf("cannot sync dirty wallet: %v", err)
}
@ -467,6 +467,8 @@ func (a *Account) NewAddress() (string, error) {
// Request updates from btcd for new transactions sent to this address.
a.ReqNewTxsForAddress(addr)
fmt.Println("after")
return addr, nil
}

3
cmd.go
View file

@ -207,8 +207,7 @@ func main() {
// Open default account
err = accountstore.OpenAccount("", cfg)
if err != nil {
log.Errorf("cannot open account: %v", err)
os.Exit(1)
log.Warnf("cannot open default account: %v", err)
}
// Read CA file to verify a btcd TLS connection.

View file

@ -402,6 +402,11 @@ func NewWallet(name, desc string, passphrase []byte, net btcwire.BitcoinNet,
return nil, err
}
// Verify root address keypairs.
if err := root.verifyKeypairs(); err != nil {
return nil, err
}
// Compute AES key and encrypt root address.
kdfp, err := computeKdfParameters(defaultKdfComputeTime, defaultKdfMaxMem)
if err != nil {
@ -754,6 +759,9 @@ func (w *Wallet) extendKeypool(n uint, aeskey []byte, bs *BlockStamp) error {
if err != nil {
return err
}
if err := newaddr.verifyKeypairs(); err != nil {
return err
}
if err = newaddr.encrypt(aeskey); err != nil {
return err
}
@ -1238,6 +1246,40 @@ func newRootBtcAddress(privKey, iv, chaincode []byte,
return addr, err
}
// verifyKeypairs creates a signature using the parsed private key and
// verifies the signature with the parsed public key. If either of these
// steps fail, the keypair generation failed and any funds sent to this
// address will be unspendable. This step requires an unencrypted or
// unlocked btcAddress.
func (a *btcAddress) verifyKeypairs() error {
// Parse public key.
pubkey, err := btcec.ParsePubKey(a.pubKey, btcec.S256())
if err != nil {
return err
}
if len(a.privKeyCT.key) != 32 {
return errors.New("private key unavailable")
}
privkey := &ecdsa.PrivateKey{
PublicKey: *pubkey,
D: new(big.Int).SetBytes(a.privKeyCT.key),
}
data := "String to sign."
r, s, err := ecdsa.Sign(rand.Reader, privkey, []byte(data))
if err != nil {
return err
}
ok := ecdsa.Verify(&privkey.PublicKey, []byte(data), r, s)
if !ok {
return errors.New("ecdsa verification failed")
}
return nil
}
// ReadFrom reads an encrypted address from an io.Reader.
func (a *btcAddress) ReadFrom(r io.Reader) (n int64, err error) {
var read int64