mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 23:48:12 +00:00
segwit support for SignMessage, VerifyMessage
This commit is contained in:
parent
d8ad44f60a
commit
b5f9a5738f
@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
#include "crypto.h"
|
||||
#include "sha2.h"
|
||||
#include "ripemd160.h"
|
||||
#include "pbkdf2.h"
|
||||
#include "aes.h"
|
||||
#include "hmac.h"
|
||||
@ -109,7 +110,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin
|
||||
}
|
||||
}
|
||||
|
||||
int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature)
|
||||
int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature)
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
sha256_Init(&ctx);
|
||||
@ -124,34 +125,48 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message
|
||||
uint8_t pby;
|
||||
int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL);
|
||||
if (result == 0) {
|
||||
signature[0] = 27 + pby + 4;
|
||||
switch (script_type) {
|
||||
case InputScriptType_SPENDP2SHWITNESS:
|
||||
// segwit-in-p2sh
|
||||
signature[0] = 35 + pby;
|
||||
break;
|
||||
case InputScriptType_SPENDWITNESS:
|
||||
// segwit
|
||||
signature[0] = 39 + pby;
|
||||
break;
|
||||
default:
|
||||
// p2pkh
|
||||
signature[0] = 31 + pby;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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[MAX_ADDR_RAW_SIZE], hash[32];
|
||||
// check for invalid signature prefix
|
||||
if (signature[0] < 27 || signature[0] > 43) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// calculate hash
|
||||
SHA256_CTX ctx;
|
||||
sha256_Init(&ctx);
|
||||
sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header));
|
||||
uint8_t varint[5];
|
||||
uint32_t l = ser_length(message_len, varint);
|
||||
sha256_Update(&ctx, varint, l);
|
||||
sha256_Update(&ctx, message, message_len);
|
||||
uint8_t hash[32];
|
||||
sha256_Final(&ctx, hash);
|
||||
sha256_Raw(hash, 32, hash);
|
||||
|
||||
uint8_t recid = signature[0] - 27;
|
||||
if (recid >= 8) {
|
||||
return 1;
|
||||
}
|
||||
bool compressed = (recid >= 4);
|
||||
recid &= 3;
|
||||
uint8_t recid = (signature[0] - 27) % 4;
|
||||
bool compressed = signature[0] >= 31;
|
||||
|
||||
// check if signature verifies the digest and recover the public key
|
||||
uint8_t pubkey[65];
|
||||
if (ecdsa_verify_digest_recover(&secp256k1, pubkey, signature + 1, hash, recid) != 0) {
|
||||
return 3;
|
||||
}
|
||||
@ -159,11 +174,35 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes
|
||||
if (compressed) {
|
||||
pubkey[0] = 0x02 | (pubkey[64] & 1);
|
||||
}
|
||||
|
||||
// check if the address is correct
|
||||
uint8_t addr_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) {
|
||||
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) {
|
||||
return 2;
|
||||
}
|
||||
} else
|
||||
// segwit
|
||||
if (signature[0] >= 39 && signature[0] <= 42) {
|
||||
return 2; // not supported yet
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin
|
||||
|
||||
int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature);
|
||||
|
||||
int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature);
|
||||
int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, 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);
|
||||
|
||||
|
@ -795,9 +795,14 @@ void fsm_msgSignMessage(SignMessage *msg)
|
||||
if (!node) return;
|
||||
|
||||
layoutProgressSwipe(_("Signing"), 0);
|
||||
if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) {
|
||||
if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) {
|
||||
resp->has_address = true;
|
||||
hdnode_get_address(node, coin->address_type, resp->address, sizeof(resp->address));
|
||||
hdnode_fill_public_key(node);
|
||||
if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) {
|
||||
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address"));
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
resp->has_signature = true;
|
||||
resp->signature.size = 65;
|
||||
msg_write(MessageType_MessageType_MessageSignature, resp);
|
||||
@ -890,7 +895,7 @@ void fsm_msgSignIdentity(SignIdentity *msg)
|
||||
uint8_t digest[64];
|
||||
sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest);
|
||||
sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32);
|
||||
result = cryptoMessageSign(&(coins[0]), node, digest, 64, resp->signature.bytes);
|
||||
result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes);
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
|
@ -57,12 +57,12 @@ SignMessage.address_n max_count:8
|
||||
SignMessage.message max_size:1024
|
||||
SignMessage.coin_name max_size:17
|
||||
|
||||
VerifyMessage.address max_size:41
|
||||
VerifyMessage.address max_size:60
|
||||
VerifyMessage.signature max_size:65
|
||||
VerifyMessage.message max_size:1024
|
||||
VerifyMessage.coin_name max_size:17
|
||||
|
||||
MessageSignature.address max_size:41
|
||||
MessageSignature.address max_size:60
|
||||
MessageSignature.signature max_size:65
|
||||
|
||||
EthereumSignMessage.address_n max_count:8
|
||||
@ -97,7 +97,7 @@ DecryptMessage skip_message:true
|
||||
|
||||
# deprecated
|
||||
DecryptedMessage skip_message:true
|
||||
# DecryptedMessage.address max_size:41
|
||||
# DecryptedMessage.address max_size:60
|
||||
# DecryptedMessage.message max_size:1024
|
||||
|
||||
CipherKeyValue.address_n max_count:8
|
||||
@ -133,7 +133,7 @@ SignIdentity.challenge_hidden max_size:256
|
||||
SignIdentity.challenge_visual max_size:256
|
||||
SignIdentity.ecdsa_curve_name max_size:32
|
||||
|
||||
SignedIdentity.address max_size:41
|
||||
SignedIdentity.address max_size:60
|
||||
SignedIdentity.public_key max_size:33
|
||||
SignedIdentity.signature max_size:65
|
||||
|
||||
|
@ -595,7 +595,7 @@ typedef struct {
|
||||
|
||||
typedef struct _MessageSignature {
|
||||
bool has_address;
|
||||
char address[41];
|
||||
char address[60];
|
||||
bool has_signature;
|
||||
MessageSignature_signature_t signature;
|
||||
} MessageSignature;
|
||||
@ -729,7 +729,7 @@ typedef struct {
|
||||
|
||||
typedef struct _SignedIdentity {
|
||||
bool has_address;
|
||||
char address[41];
|
||||
char address[60];
|
||||
bool has_public_key;
|
||||
SignedIdentity_public_key_t public_key;
|
||||
bool has_signature;
|
||||
@ -767,7 +767,7 @@ typedef struct {
|
||||
|
||||
typedef struct _VerifyMessage {
|
||||
bool has_address;
|
||||
char address[41];
|
||||
char address[60];
|
||||
bool has_signature;
|
||||
VerifyMessage_signature_t signature;
|
||||
bool has_message;
|
||||
@ -1192,8 +1192,8 @@ extern const pb_field_t DebugLinkFlashErase_fields[2];
|
||||
#define WordRequest_size 6
|
||||
#define WordAck_size 14
|
||||
#define SignMessage_size 1100
|
||||
#define VerifyMessage_size 1156
|
||||
#define MessageSignature_size 110
|
||||
#define VerifyMessage_size 1175
|
||||
#define MessageSignature_size 129
|
||||
#define CipherKeyValue_size 1358
|
||||
#define CipheredKeyValue_size 1027
|
||||
#define SignTx_size 43
|
||||
@ -1206,7 +1206,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2];
|
||||
#define EthereumVerifyMessage_size 1116
|
||||
#define EthereumMessageSignature_size 89
|
||||
#define SignIdentity_size (558 + IdentityType_size)
|
||||
#define SignedIdentity_size 145
|
||||
#define SignedIdentity_size 164
|
||||
#define GetECDHSessionKey_size (107 + IdentityType_size)
|
||||
#define ECDHSessionKey_size 67
|
||||
#define SetU2FCounter_size 6
|
||||
|
@ -124,16 +124,7 @@ bool compute_address(const CoinType *coin,
|
||||
if (!coin->has_address_type_p2sh) {
|
||||
return 0;
|
||||
}
|
||||
prelen = address_prefix_bytes_len(coin->address_type_p2sh);
|
||||
raw[0] = 0; // version byte
|
||||
raw[1] = 20; // push 20 bytes
|
||||
ecdsa_get_pubkeyhash(node->public_key, raw + 2);
|
||||
sha256_Raw(raw, 22, digest);
|
||||
address_write_prefix_bytes(coin->address_type_p2sh, raw);
|
||||
ripemd160(digest, 32, raw + prelen);
|
||||
if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, address, MAX_ADDR_SIZE);
|
||||
} else {
|
||||
ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE);
|
||||
}
|
||||
|
2
vendor/trezor-crypto
vendored
2
vendor/trezor-crypto
vendored
@ -1 +1 @@
|
||||
Subproject commit cfe8f39cd436bf98e864775a9131e81e554e7bf1
|
||||
Subproject commit dfdb4d2d766506e9f54dd2c69c5e664fe4e39304
|
Loading…
Reference in New Issue
Block a user