1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-22 22:38:08 +00:00

Add support for multi-byte address prefixes.

This commit is contained in:
Daira Hopwood 2016-10-09 20:38:51 +01:00 committed by Pavol Rusnak
parent 1234ab94d4
commit 69d99d202d
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
8 changed files with 89 additions and 36 deletions

View File

@ -55,7 +55,7 @@ const CoinType *coinByName(const char *name)
return 0;
}
const CoinType *coinByAddressType(uint8_t address_type)
const CoinType *coinByAddressType(uint32_t address_type)
{
int i;
for (i = 0; i < COINS_COUNT; i++) {
@ -65,3 +65,55 @@ const CoinType *coinByAddressType(uint8_t address_type)
}
return 0;
}
size_t prefixBytesByAddressType(uint32_t address_type)
{
if (address_type <= 0xFF) return 1;
if (address_type <= 0xFFFF) return 2;
if (address_type <= 0xFFFFFF) return 3;
return 4;
}
bool addressHasExpectedPrefix(const uint8_t *addr, uint32_t address_type)
{
if (address_type <= 0xFF) {
return address_type == (uint32_t)(addr[0]);
}
if (address_type <= 0xFFFF) {
return address_type == ((uint32_t)(addr[0] << 8) | (uint32_t)(addr[1]));
}
if (address_type <= 0xFFFFFF) {
return address_type == ((uint32_t)(addr[0] << 16) | (uint32_t)(addr[1] << 8) | (uint32_t)(addr[2]));
}
return address_type == ((uint32_t)(addr[0] << 24) | (uint32_t)(addr[1] << 16) | (uint32_t)(addr[2] << 8) | (uint32_t)(addr[3]));
}
void writeAddressPrefix(uint8_t *addr, uint32_t address_type)
{
if (address_type > 0xFFFFFF) *(addr++) = address_type >> 24;
if (address_type > 0xFFFF) *(addr++) = (address_type >> 16) & 0xFF;
if (address_type > 0xFF) *(addr++) = (address_type >> 8) & 0xFF;
*(addr++) = address_type & 0xFF;
}
bool getAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type)
{
if (coin->has_address_type && addressHasExpectedPrefix(addr, coin->address_type)) {
*address_type = coin->address_type;
return true;
}
if (coin->has_address_type_p2sh && addressHasExpectedPrefix(addr, coin->address_type_p2sh)) {
*address_type = coin->address_type_p2sh;
return true;
}
if (coin->has_address_type_p2wpkh && addressHasExpectedPrefix(addr, coin->address_type_p2wpkh)) {
*address_type = coin->address_type_p2wpkh;
return true;
}
if (coin->has_address_type_p2wsh && addressHasExpectedPrefix(addr, coin->address_type_p2wsh)) {
*address_type = coin->address_type_p2wsh;
return true;
}
*address_type = 0;
return false;
}

View File

@ -28,6 +28,10 @@ extern const CoinType coins[COINS_COUNT];
const CoinType *coinByShortcut(const char *shortcut);
const CoinType *coinByName(const char *name);
const CoinType *coinByAddressType(uint8_t address_type);
const CoinType *coinByAddressType(uint32_t address_type);
size_t prefixBytesByAddressType(uint32_t address_type);
bool addressHasExpectedPrefix(const uint8_t *addr, uint32_t address_type);
void writeAddressPrefix(uint8_t *addr, uint32_t address_type);
bool getAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type);
#endif

View File

@ -28,6 +28,7 @@
#include "curves.h"
#include "secp256k1.h"
#include "macros.h"
#include "coins.h"
uint32_t ser_length(uint32_t len, uint8_t *out)
{
@ -140,10 +141,10 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message
return result;
}
int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature)
int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature)
{
SHA256_CTX ctx;
uint8_t pubkey[65], addr_raw[21], hash[32];
uint8_t pubkey[65], addr_raw[MAX_ADDR_RAW_SIZE], hash[32];
// calculate hash
sha256_Init(&ctx);
@ -171,8 +172,8 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes
pubkey[0] = 0x02 | (pubkey[64] & 1);
}
// check if the address is correct
ecdsa_get_address_raw(pubkey, address_raw[0], addr_raw);
if (memcmp(addr_raw, address_raw, 21) != 0) {
ecdsa_get_address_raw(pubkey, address_type, addr_raw);
if (memcmp(addr_raw, address_raw, prefixBytesByAddressType(address_type) + 20) != 0) {
return 2;
}
return 0;
@ -272,9 +273,11 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
uint32_t l, o;
l = deser_length(payload + 1, &o);
if (*signing) {
// FIXME: assumes a raw address is 21 bytes (also below).
if (1 + l + o + 21 + 65 != payload_len) {
return 4;
}
// FIXME: cryptoMessageVerify changed to take the address_type as a parameter.
if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o, payload + 1 + l + o + 21) != 0) {
return 5;
}

View File

@ -42,7 +42,7 @@ int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key,
int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature);
int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature);
int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, 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);

View File

@ -732,9 +732,7 @@ void fsm_msgSignMessage(SignMessage *msg)
layoutProgressSwipe("Signing", 0);
if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) {
resp->has_address = true;
uint8_t addr_raw[21];
hdnode_get_address_raw(node, coin->address_type, addr_raw);
base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address));
hdnode_get_address(node, coin->address_type, resp->address, sizeof(resp->address));
resp->has_signature = true;
resp->signature.size = 65;
msg_write(MessageType_MessageType_MessageSignature, resp);
@ -757,11 +755,13 @@ void fsm_msgVerifyMessage(VerifyMessage *msg)
const CoinType *coin = fsm_getCoin(msg->coin_name);
if (!coin) return;
layoutProgressSwipe("Verifying", 0);
uint8_t addr_raw[21];
if (!ecdsa_address_decode(msg->address, addr_raw)) {
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
uint32_t address_type;
if (!getAddressType(coin, (const uint8_t *) msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) {
fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address");
return;
}
if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) {
if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) {
layoutVerifyAddress(msg->address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled");
@ -845,9 +845,7 @@ void fsm_msgSignIdentity(SignIdentity *msg)
resp->has_address = false;
} else {
resp->has_address = true;
uint8_t addr_raw[21];
hdnode_get_address_raw(node, 0x00, addr_raw); // hardcoded Bitcoin address type
base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address));
hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type
}
resp->has_public_key = true;
resp->public_key.size = 33;
@ -943,7 +941,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg)
RESP_INIT(EncryptedMessage);
const CoinType *coin = 0;
const HDNode *node = 0;
uint8_t address_raw[21];
uint8_t address_raw[MAX_ADDR_RAW_SIZE];
if (signing) {
coin = coinByName(msg->coin_name);
if (!coin) {
@ -1011,7 +1009,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg)
RESP_INIT(DecryptedMessage);
bool display_only = false;
bool signing = false;
uint8_t address_raw[21];
uint8_t address_raw[MAX_ADDR_RAW_SIZE];
if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error decrypting message");
layoutHome();

View File

@ -59,7 +59,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
{
memset(out, 0, sizeof(TxOutputBinType));
out->amount = in->amount;
uint8_t addr_raw[21];
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
if (in->script_type == OutputScriptType_PAYTOADDRESS) {
@ -80,12 +80,10 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
return -1;
}
}
if (!ecdsa_address_decode(in->address, addr_raw)) {
return 0;
}
if (addr_raw[0] != coin->address_type) {
if (!ecdsa_address_decode(in->address, coin->address_type, addr_raw)) {
return 0;
}
} else { // does not have address_n neither address -> error
return 0;
}
@ -93,7 +91,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
out->script_pubkey.bytes[0] = 0x76; // OP_DUP
out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes
memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20);
memcpy(out->script_pubkey.bytes + 3, addr_raw + prefixBytesByAddressType(coin->address_type), 20);
out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
out->script_pubkey.size = 25;
@ -101,10 +99,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
}
if (in->script_type == OutputScriptType_PAYTOSCRIPTHASH) {
if (!in->has_address || !ecdsa_address_decode(in->address, addr_raw)) {
return 0;
}
if (addr_raw[0] != coin->address_type_p2sh) {
if (!in->has_address || !ecdsa_address_decode(in->address, coin->address_type_p2sh, addr_raw)) {
return 0;
}
if (needs_confirm) {
@ -115,7 +110,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
}
out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20);
memcpy(out->script_pubkey.bytes + 2, addr_raw + prefixBytesByAddressType(coin->address_type_p2sh), 20);
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
out->script_pubkey.size = 23;
return 23;
@ -123,16 +118,17 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
if (in->script_type == OutputScriptType_PAYTOMULTISIG) {
uint8_t buf[32];
size_t prefix_bytes = prefixBytesByAddressType(coin->address_type_p2sh);
if (!in->has_multisig) {
return 0;
}
if (compile_script_multisig_hash(&(in->multisig), buf) == 0) {
return 0;
}
addr_raw[0] = coin->address_type_p2sh;
ripemd160(buf, 32, addr_raw + 1);
writeAddressPrefix(addr_raw, coin->address_type_p2sh);
ripemd160(buf, 32, addr_raw + prefix_bytes);
if (needs_confirm) {
base58_encode_check(addr_raw, 21, in->address, sizeof(in->address));
base58_encode_check(addr_raw, prefix_bytes + 20, in->address, sizeof(in->address));
layoutConfirmOutput(coin, in);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return -1;
@ -140,7 +136,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
}
out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20);
memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_bytes, 20);
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
out->script_pubkey.size = 23;
return 23;
@ -159,7 +155,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
return 0;
}
uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out)
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out)
{
if (coinByAddressType(address_type)) { // valid coin type
out[0] = 0x76; // OP_DUP

View File

@ -41,7 +41,7 @@ typedef struct {
SHA256_CTX ctx;
} TxStruct;
uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out);
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out);
uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out);
uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash);
uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out);

@ -1 +1 @@
Subproject commit 157caf3763866c386f9bcc287db3a1a472b5d55e
Subproject commit ad73c0d4e73fe138ebbbc39d6a335167ba7c9923