diff --git a/firmware/crypto.c b/firmware/crypto.c index 3a8d6ec45a..391410a9e4 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -31,6 +31,8 @@ #include "address.h" #include "macros.h" #include "coins.h" +#include "base58.h" +#include "segwit_addr.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -143,7 +145,7 @@ int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script return result; } -int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature) { // check for invalid signature prefix if (signature[0] < 27 || signature[0] > 43) { @@ -177,30 +179,41 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // check if the address is correct uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + uint8_t recovered_raw[MAX_ADDR_RAW_SIZE]; // p2pkh if (signature[0] >= 27 && signature[0] <= 34) { - if (address_type != coin->address_type) { - return 4; - } - ecdsa_get_address_raw(pubkey, address_type, addr_raw); - if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { + size_t len = base58_decode_check(address, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_raw(pubkey, coin->address_type, recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 + || len != address_prefix_bytes_len(coin->address_type) + 20) { return 2; } } else // segwit-in-p2sh if (signature[0] >= 35 && signature[0] <= 38) { - if (address_type != coin->address_type_p2sh) { - return 4; - } - ecdsa_get_address_segwit_p2sh_raw(pubkey, address_type, addr_raw); - if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { + size_t len = base58_decode_check(address, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 + || len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { return 2; } } else // segwit if (signature[0] >= 39 && signature[0] <= 42) { - return 2; // not supported yet + int witver; + size_t len; + if (!coin->bech32_prefix + || !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { + return 4; + } + ecdsa_get_pubkeyhash(pubkey, addr_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 + || witver != 0 || len != 20) { + return 2; + } + } else { + return 4; } return 0; diff --git a/firmware/crypto.h b/firmware/crypto.h index dbf393db02..e974df26ac 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -40,7 +40,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature); /* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); diff --git a/firmware/fsm.c b/firmware/fsm.c index 4f0011fd1e..f2f9d35389 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -849,14 +849,8 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - uint32_t address_type; - if (!coinExtractAddressType(coin, msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); - return; - } layoutProgressSwipe(_("Verifying"), 0); - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { + if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);