rpc: modify SignMessage+VerifyMessage to bind msg to LN context

In this commit, we modify the SignMessage+VerifyMessage slightly in
order to bind the message we're signing to our specific context. We do
this by pre-pending the ascii text "Lightning Signed Message:" to the
msg before we run it through dsha256. Adding this prefix binds the
message to our context in order to avoid accidentally signing a sighash
or the like.
This commit is contained in:
Olaoluwa Osuntokun 2018-04-25 19:45:26 -07:00
parent 86fd9e361e
commit c54a91f44d
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 20 additions and 8 deletions

@ -67,8 +67,9 @@ func (n *nodeSigner) SignDigestCompact(hash []byte) ([]byte, error) {
isCompressedKey := true
// btcec.SignCompact returns a pubkey-recoverable signature
sig, err := btcec.SignCompact(btcec.S256(), n.privKey, hash,
isCompressedKey)
sig, err := btcec.SignCompact(
btcec.S256(), n.privKey, hash, isCompressedKey,
)
if err != nil {
return nil, fmt.Errorf("can't sign the hash: %v", err)
}

@ -520,10 +520,18 @@ func (r *rpcServer) NewWitnessAddress(ctx context.Context,
return &lnrpc.NewAddressResponse{Address: addr.String()}, nil
}
var (
// signedMsgPrefix is a special prefix that we'll prepend to any
// messages we sign/verify. We do this to ensure that we don't
// accidentally sign a sighash, or other sensitive material. By
// prepending this fragment, we mind message signing to our particular
// context.
signedMsgPrefix = []byte("Lightning Signed Message:")
)
// SignMessage signs a message with the resident node's private key. The
// returned signature string is zbase32 encoded and pubkey recoverable,
// meaning that only the message digest and signature are needed for
// verification.
// returned signature string is zbase32 encoded and pubkey recoverable, meaning
// that only the message digest and signature are needed for verification.
func (r *rpcServer) SignMessage(ctx context.Context,
in *lnrpc.SignMessageRequest) (*lnrpc.SignMessageResponse, error) {
@ -531,6 +539,7 @@ func (r *rpcServer) SignMessage(ctx context.Context,
return nil, fmt.Errorf("need a message to sign")
}
in.Msg = append(signedMsgPrefix, in.Msg...)
sigBytes, err := r.server.nodeSigner.SignCompact(in.Msg)
if err != nil {
return nil, err
@ -540,9 +549,9 @@ func (r *rpcServer) SignMessage(ctx context.Context,
return &lnrpc.SignMessageResponse{Signature: sig}, nil
}
// VerifyMessage verifies a signature over a msg. The signature must be
// zbase32 encoded and signed by an active node in the resident node's
// channel database. In addition to returning the validity of the signature,
// VerifyMessage verifies a signature over a msg. The signature must be zbase32
// encoded and signed by an active node in the resident node's channel
// database. In addition to returning the validity of the signature,
// VerifyMessage also returns the recovered pubkey from the signature.
func (r *rpcServer) VerifyMessage(ctx context.Context,
in *lnrpc.VerifyMessageRequest) (*lnrpc.VerifyMessageResponse, error) {
@ -558,6 +567,7 @@ func (r *rpcServer) VerifyMessage(ctx context.Context,
}
// The signature is over the double-sha256 hash of the message.
in.Msg = append(signedMsgPrefix, in.Msg...)
digest := chainhash.DoubleHashB(in.Msg)
// RecoverCompact both recovers the pubkey and validates the signature.
@ -572,6 +582,7 @@ func (r *rpcServer) VerifyMessage(ctx context.Context,
// Query the channel graph to ensure a node in the network with active
// channels signed the message.
//
// TODO(phlip9): Require valid nodes to have capital in active channels.
graph := r.server.chanDB.ChannelGraph()
_, active, err := graph.HasLightningNode(pub)