signrpc: parse both KeyDescriptor fields for SignOutputRaw requests

This is meant to handle a quirk in which key descriptors obtained
through walletrpc.DeriveKey don't result in the derived key being
persisted to the wallet's database, unlike with DeriveNextKey. Due to
this and some fallback logic in the wallet with regards to empty key
locators, if a request only specified the compressed public key, the
signature returned would be over a different key, namely the one derived
from (family=0, index=0).
This commit is contained in:
Wilmer Paulino 2020-06-04 17:44:25 -07:00
parent be36776120
commit 98da6c61c1
No known key found for this signature in database
GPG key ID: 6DF57B9F9514972F
4 changed files with 17 additions and 8 deletions

View file

@ -180,6 +180,10 @@ type SignDescriptor struct {
//A descriptor that precisely describes *which* key to use for signing. This //A descriptor that precisely describes *which* key to use for signing. This
//may provide the raw public key directly, or require the Signer to re-derive //may provide the raw public key directly, or require the Signer to re-derive
//the key according to the populated derivation path. //the key according to the populated derivation path.
//
//Note that if the key descriptor was obtained through walletrpc.DeriveKey,
//then the key locator MUST always be provided, since the derived keys are not
//persisted unlike with DeriveNextKey.
KeyDesc *KeyDescriptor `protobuf:"bytes,1,opt,name=key_desc,json=keyDesc,proto3" json:"key_desc,omitempty"` KeyDesc *KeyDescriptor `protobuf:"bytes,1,opt,name=key_desc,json=keyDesc,proto3" json:"key_desc,omitempty"`
// //
//A scalar value that will be added to the private key corresponding to the //A scalar value that will be added to the private key corresponding to the

View file

@ -98,6 +98,10 @@ message SignDescriptor {
A descriptor that precisely describes *which* key to use for signing. This A descriptor that precisely describes *which* key to use for signing. This
may provide the raw public key directly, or require the Signer to re-derive may provide the raw public key directly, or require the Signer to re-derive
the key according to the populated derivation path. the key according to the populated derivation path.
Note that if the key descriptor was obtained through walletrpc.DeriveKey,
then the key locator MUST always be provided, since the derived keys are not
persisted unlike with DeriveNextKey.
*/ */
KeyDescriptor key_desc = 1; KeyDescriptor key_desc = 1;

View file

@ -303,7 +303,7 @@
"properties": { "properties": {
"key_desc": { "key_desc": {
"$ref": "#/definitions/signrpcKeyDescriptor", "$ref": "#/definitions/signrpcKeyDescriptor",
"description": "A descriptor that precisely describes *which* key to use for signing. This\nmay provide the raw public key directly, or require the Signer to re-derive\nthe key according to the populated derivation path." "description": "A descriptor that precisely describes *which* key to use for signing. This\nmay provide the raw public key directly, or require the Signer to re-derive\nthe key according to the populated derivation path.\n\nNote that if the key descriptor was obtained through walletrpc.DeriveKey,\nthen the key locator MUST always be provided, since the derived keys are not\npersisted unlike with DeriveNextKey."
}, },
"single_tweak": { "single_tweak": {
"type": "string", "type": "string",

View file

@ -242,17 +242,17 @@ func (s *Server) SignOutputRaw(ctx context.Context, in *SignReq) (*SignResp, err
keyDesc := signDesc.KeyDesc keyDesc := signDesc.KeyDesc
// The caller can either specify the key using the raw pubkey, // The caller can either specify the key using the raw pubkey,
// or the description of the key. Below we'll feel out the // or the description of the key. We'll still attempt to parse
// oneof field to decide which one we will attempt to parse. // both if both were provided however, to ensure the underlying
// SignOutputRaw has as much information as possible.
var ( var (
targetPubKey *btcec.PublicKey targetPubKey *btcec.PublicKey
keyLoc keychain.KeyLocator keyLoc keychain.KeyLocator
) )
switch {
// If this method doesn't return nil, then we know that user is // If this method doesn't return nil, then we know that user is
// attempting to include a raw serialized pub key. // attempting to include a raw serialized pub key.
case keyDesc.GetRawKeyBytes() != nil: if keyDesc.GetRawKeyBytes() != nil {
rawKeyBytes := keyDesc.GetRawKeyBytes() rawKeyBytes := keyDesc.GetRawKeyBytes()
switch { switch {
@ -275,10 +275,11 @@ func (s *Server) SignOutputRaw(ctx context.Context, in *SignReq) (*SignResp, err
"parse pubkey: %v", err) "parse pubkey: %v", err)
} }
} }
}
// Similarly, if they specified a key locator, then we'll use // Similarly, if they specified a key locator, then we'll parse
// that instead. // that as well.
case keyDesc.GetKeyLoc() != nil: if keyDesc.GetKeyLoc() != nil {
protoLoc := keyDesc.GetKeyLoc() protoLoc := keyDesc.GetKeyLoc()
keyLoc = keychain.KeyLocator{ keyLoc = keychain.KeyLocator{
Family: keychain.KeyFamily( Family: keychain.KeyFamily(