From f90fb4934faaf9f92c5cc6c2f23b7a840c1fa0ae Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 31 Aug 2016 16:06:32 +0930 Subject: [PATCH] close_shutdown: make sure script_pubkey is standard. As per BOLT update 9c3f150d2a44af6ee2c3be03acd6ef80ea184f4e. Signed-off-by: Rusty Russell --- bitcoin/script.c | 28 ++++++++++++++++++++++++++++ bitcoin/script.h | 6 ++++++ daemon/packets.c | 22 ++++++++++++++++++++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/bitcoin/script.c b/bitcoin/script.c index 7e07d76e6..6a2e968ec 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -454,6 +454,23 @@ u8 *p2wpkh_scriptcode(const tal_t *ctx, return script; } +bool is_p2pkh(const u8 *script, size_t script_len) +{ + if (script_len != 25) + return false; + if (script[0] != OP_DUP) + return false; + if (script[1] != OP_HASH160) + return false; + if (script[2] != OP_PUSHBYTES(20)) + return false; + if (script[23] != OP_EQUALVERIFY) + return false; + if (script[24] != OP_CHECKSIG) + return false; + return true; +} + bool is_p2sh(const u8 *script, size_t script_len) { if (script_len != 23) @@ -478,6 +495,17 @@ bool is_p2wsh(const u8 *script, size_t script_len) return true; } +bool is_p2wpkh(const u8 *script, size_t script_len) +{ + if (script_len != 1 + 1 + sizeof(struct ripemd160)) + return false; + if (script[0] != OP_0) + return false; + if (script[1] != OP_PUSHBYTES(sizeof(struct ripemd160))) + return false; + return true; +} + /* A common script pattern: A can have it with secret, or B can have * it after delay. */ u8 *bitcoin_redeem_secret_or_delay(const tal_t *ctx, diff --git a/bitcoin/script.h b/bitcoin/script.h index ea677a35c..fef0da3af 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -109,12 +109,18 @@ u8 **bitcoin_witness_htlc(const tal_t *ctx, const struct bitcoin_signature *sig, const u8 *witnessscript); +/* Is this a pay to pubkeu hash? */ +bool is_p2pkh(const u8 *script, size_t script_len); + /* Is this a pay to script hash? */ bool is_p2sh(const u8 *script, size_t script_len); /* Is this (version 0) pay to witness script hash? */ bool is_p2wsh(const u8 *script, size_t script_len); +/* Is this (version 0) pay to witness pubkey hash? */ +bool is_p2wpkh(const u8 *script, size_t script_len); + /* Are these two scripts equal? */ bool scripteq(const u8 *s1, size_t s1len, const u8 *s2, size_t s2len); diff --git a/daemon/packets.c b/daemon/packets.c index c2e361aaa..1eaccd34f 100644 --- a/daemon/packets.c +++ b/daemon/packets.c @@ -567,10 +567,28 @@ Pkt *accept_pkt_close_shutdown(struct peer *peer, const Pkt *pkt) { const CloseShutdown *c = pkt->close_shutdown; - /* FIXME: Filter for non-standardness? */ + /* BOLT #2: + * + * 1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG` + * (pay to pubkey hash), OR + * 2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR + * 3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey), OR + * 4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash) + * + * A node receiving `close_shutdown` SHOULD fail the connection + * `script_pubkey` is not one of those forms. + */ + if (!is_p2pkh(c->scriptpubkey.data, c->scriptpubkey.len) + && !is_p2sh(c->scriptpubkey.data, c->scriptpubkey.len) + && !is_p2wpkh(c->scriptpubkey.data, c->scriptpubkey.len) + && !is_p2wsh(c->scriptpubkey.data, c->scriptpubkey.len)) { + log_broken_blob(peer->log, "Bad script_pubkey %s", + c->scriptpubkey.data, c->scriptpubkey.len); + return pkt_err(peer, "Bad script_pubkey"); + } + peer->closing.their_script = tal_dup_arr(peer, u8, c->scriptpubkey.data, c->scriptpubkey.len, 0); - return NULL; }