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

segwit support for SignMessage, VerifyMessage

This commit is contained in:
Pavol Rusnak 2017-07-24 17:40:46 +02:00
parent d8ad44f60a
commit b5f9a5738f
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
7 changed files with 73 additions and 38 deletions

View File

@ -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
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;
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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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);
}

@ -1 +1 @@
Subproject commit cfe8f39cd436bf98e864775a9131e81e554e7bf1
Subproject commit dfdb4d2d766506e9f54dd2c69c5e664fe4e39304