Skip to content

Fixup borked PSBT signing + finalize - #203

Merged
greenaddress merged 3 commits into
ElementsProject:masterfrom
niftynei:nifty/fix-borked-psbt-sigs
Jun 22, 2020
Merged

Fixup borked PSBT signing + finalize#203
greenaddress merged 3 commits into
ElementsProject:masterfrom
niftynei:nifty/fix-borked-psbt-sigs

Conversation

@niftynei

@niftynei niftynei commented Jun 5, 2020

Copy link
Copy Markdown
Contributor

Found two three problems with the PSBT sign + finalize code; this PR contains suggested fixes for them and tests.

  • Disallow creating a second partial_sig if there's already a sig for that pubkey attached to an input. Creating PSBTs with duplicate key'd partial_sig maps fails to decode from b64.
  • Fixup the out-script logic for finalize; as written fails to properly detect p2sh-p2wpkh outputs
  • Populate p2sh-p2wpkh script-sig from the provided redeemscript

Note: disallowing duplicate key'd partial_sigs made the invalid_sigs tests start to pass since the existing test already had partial_sig data populated for the given key; we revert them to 'failing' by removing the existing partial_sig data from the test case.

Comment thread src/psbt.c Outdated
if (input->partial_sigs) {
for (j = 0; j < input->partial_sigs->num_items; j++) {
struct wally_partial_sigs_item *item = &input->partial_sigs->items[j];
if ((item->pubkey[0] == 0x04

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 6f6f30d "psbt: dont sign inputs we've already got a sig for"

I don't think it's necessary to check whether it is compressed or uncompressed. item->pubkey is a fixed size of EC_PUBLIC_KEY_UNCOMPRESSED_LEN so you can just always do a memcmp on that. It should still check both sizes as compressed keys could have garbage at the end of the buffer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but that's specifically to check for compressed-ness which we don't need here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should still check both sizes as compressed keys could have garbage at the end of the buffer.

i'm not sure i understand what you're suggesting here. given the quoted comment, i think you're saying i should drop the pubkey[0] == 0x04 check. is this correct?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Comment thread src/psbt.c Outdated
unsigned char *out_script = NULL; /* Script that determines how we should finalize this input, typically output script */
size_t out_script_len, type;
/* Expanded script, only applicable for P2SH variants. Used for determining if is multisig */
unsigned char *script = NULL;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 036db5a "psbt: fix signing for p2sh-p2wpkh and test"

It's not clear to me why script is necessary here. It's just replacing a few places where out_script is being checked that AFAICT, could still be out_script if it were updated in the correct places.

@niftynei niftynei Jun 10, 2020

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not 'scriptly necessary' -- i added it so as not to re-use out_script. the intention of having a second placeholder for the 'definitely the script' is to simplify the various 'levels' of scripts that out_script could possibly represent, as that seemed to be part of the root cause of the problems in the first place.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO keeping it out_script makes it more readable as out_script is supposed to be the scriptcode and scriptcode is what matters, regardless of the 'levels'. It seems like the root cause is setting out_script in the wrong order.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm going to agree to disagree with you here. if reusing out_script is necessary to get this PR approved, i will update it to reuse out-script.

@niftynei
niftynei force-pushed the nifty/fix-borked-psbt-sigs branch 2 times, most recently from 8adbee0 to 24a1720 Compare June 12, 2020 20:44
@niftynei

Copy link
Copy Markdown
Contributor Author

hey @achow101 i've made the changes you requested, would you mind taking another look? this is currently blocking some other work.

@achow101 achow101 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 24a1720

Needs squash.

Hmm. I thought I ack'd this earlier.

Comment thread src/psbt.c
out_script_len = input->witness_script_len;
witness = true;
}
if (input->redeem_script) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if block can be swapped with the one above. Then the if (type == WALLY_SCRIPT_TYPE_P2WSH...) block can be dropped.

Comment thread src/psbt.c

/* Note that if we patch libwally to supply the non-witness utxo tx field (tx) for
* witness inputs also, we'll need a different way to signal p2wpkh scripts */
* witness inputs also, we'll need a different way to signal p2sh-p2wpkh scripts */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out uncrustify wants it this way, so reverted this suggested change.

if we sign an input twice, it'll marshal to b64 correctly but blow up on
the unmarshal. rather than creating invalid psbts, we simply refuse to
sign an input that's already been signed by the given pubkey
@niftynei
niftynei force-pushed the nifty/fix-borked-psbt-sigs branch from 24a1720 to f727cbe Compare June 18, 2020 00:35
@niftynei

Copy link
Copy Markdown
Contributor Author

squashed + updated

@achow101

Copy link
Copy Markdown
Contributor

ACK f727cbe

niftynei added 2 commits June 18, 2020 17:28
as implemented, we don't properly sign for p2sh-p2wpkh inputs; here we
fix the issue and add a new test case to cover both p2sh-p2wpkh and
p2wpkh signature generation
prior to this patch, p2sh-p2wpkh doesn't finalize correctly -- it omits
filling in the scriptSig with the redeem-script data

fixing this matches bitcoind's `finalizepsbt` behavior
@niftynei
niftynei force-pushed the nifty/fix-borked-psbt-sigs branch from f727cbe to e0d0634 Compare June 18, 2020 22:28
@achow101

Copy link
Copy Markdown
Contributor

ACK e0d0634

Comment thread src/psbt.c
if (input->redeem_script) {
/* P2SH wrapped witness requires final scriptsig of pushing the redeemScript */
script_sig_len = varint_get_length(input->redeem_script_len) + input->redeem_script_len;
input->final_script_sig = wally_malloc(script_sig_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be worth explicitly checking the value returned by wally_malloc for null and returning WALLY_ENOMEM

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is copied from https://github.com/ElementsProject/libwally-core/blob/master/src/psbt.c#L2860-L2868, which will also need to be cleaned up

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the interest of getting my PRs in c-lightning unblocked, we should merge this PR and clean up the malloc problems in a second fixup

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i went through and updated all wally_alloc calls in psbt.c that were missing a NULL check, see #204

@greenaddress
greenaddress merged commit e0d0634 into ElementsProject:master Jun 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants