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:
parent
1234ab94d4
commit
69d99d202d
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
2
vendor/trezor-crypto
vendored
2
vendor/trezor-crypto
vendored
@ -1 +1 @@
|
||||
Subproject commit 157caf3763866c386f9bcc287db3a1a472b5d55e
|
||||
Subproject commit ad73c0d4e73fe138ebbbc39d6a335167ba7c9923
|
Loading…
Reference in New Issue
Block a user