diff --git a/firmware/crypto.c b/firmware/crypto.c index b9cd878146..45e96c822c 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -85,13 +85,13 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) return 1 + 8; } -int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes return hdnode_sign(node, message, message_len, signature + 1, NULL); } -int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { // GPG should sign a SHA256 digest of the original message. if (message_len != 32) { @@ -120,7 +120,7 @@ int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, return 0; } -int cryptoMessageSign(const CoinType *coin, const 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) { SHA256_CTX ctx; sha256_Init(&ctx); @@ -294,7 +294,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) { if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; static HDNode node; - if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, SECP256K1_NAME, &node) == 0) { + if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, SECP256K1_NAME, &node) == 0) { return 0; } layoutProgressUpdate(true); diff --git a/firmware/crypto.h b/firmware/crypto.h index 8425046360..e6d3c00faf 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -33,14 +33,14 @@ uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); -int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key); -int cryptoMessageSign(const CoinType *coin, const 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 cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index 01049df982..70525c17aa 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -94,7 +94,7 @@ const CoinType *fsm_getCoin(const char *name) return coin; } -const HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) +HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) { static HDNode node; if (!storage_getRootNode(&node, curve, true)) { @@ -298,8 +298,21 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) if (msg->has_ecdsa_curve_name) { curve = msg->ecdsa_curve_name; } - const HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count); - if (!node) return; + uint32_t fpr; + HDNode *node; + if (msg->address_n_count == 0) { + /* get master node */ + fpr = 0; + node = fsm_getDerivedNode(curve, msg->address_n, 0); + } else { + /* get parent node */ + node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count - 1); + if (!node) return; + fpr = hdnode_fingerprint(node); + /* get child */ + hdnode_private_ckd(node, msg->address_n[msg->address_n_count - 1]); + } + hdnode_fill_public_key(node); if (msg->has_show_display && msg->show_display) { layoutPublicKey(node->public_key); @@ -311,7 +324,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) } resp->node.depth = node->depth; - resp->node.fingerprint = node->fingerprint; + resp->node.fingerprint = fpr; resp->node.child_num = node->child_num; resp->node.chain_code.size = 32; memcpy(resp->node.chain_code.bytes, node->chain_code, 32); @@ -319,8 +332,12 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.has_public_key = true; resp->node.public_key.size = 33; memcpy(resp->node.public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->node.public_key.bytes[0] = 0; + } resp->has_xpub = true; - hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub)); + hdnode_serialize_public(node, fpr, resp->xpub, sizeof(resp->xpub)); msg_write(MessageType_MessageType_PublicKey, resp); layoutHome(); } @@ -561,8 +578,9 @@ void fsm_msgGetAddress(GetAddress *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; + hdnode_fill_public_key(node); if (msg->has_multisig) { layoutProgressSwipe("Preparing", 0); @@ -641,14 +659,14 @@ void fsm_msgSignMessage(SignMessage *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; 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]; - ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); + hdnode_get_address_raw(node, coin->address_type, addr_raw); base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); resp->has_signature = true; resp->signature.size = 65; @@ -735,7 +753,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) if (msg->has_ecdsa_curve_name) { curve = msg->ecdsa_curve_name; } - const HDNode *node = fsm_getDerivedNode(curve, address_n, 5); + HDNode *node = fsm_getDerivedNode(curve, address_n, 5); if (!node) return; bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); @@ -755,17 +773,22 @@ void fsm_msgSignIdentity(SignIdentity *msg) } if (result == 0) { + hdnode_fill_public_key(node); if (strcmp(curve, SECP256K1_NAME) != 0) { resp->has_address = false; } else { resp->has_address = true; uint8_t addr_raw[21]; - ecdsa_get_address_raw(node->public_key, 0x00, addr_raw); // hardcoded Bitcoin address type + hdnode_get_address_raw(node, 0x00, addr_raw); // hardcoded Bitcoin address type base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); } resp->has_public_key = true; resp->public_key.size = 33; memcpy(resp->public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->public_key.bytes[0] = 0; + } resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); @@ -859,9 +882,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) } node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; - uint8_t public_key[33]; - ecdsa_get_public_key33(&secp256k1, node->private_key, public_key); - ecdsa_get_address_raw(public_key, coin->address_type, address_raw); + hdnode_get_address_raw(node, coin->address_type, address_raw); } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { diff --git a/firmware/signing.c b/firmware/signing.c index cfc28d6984..e78eec628b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -471,6 +471,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + hdnode_fill_public_key(&node); if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { if (!tx->inputs[0].has_multisig) { fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); diff --git a/firmware/storage.c b/firmware/storage.c index 519443ac38..2cc9204ae5 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -361,7 +361,7 @@ bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) if (!protectPassphrase()) { return false; } - if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, curve, node) == 0) { + if (hdnode_from_xprv(storage.node.depth, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, curve, node) == 0) { return false; } if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { diff --git a/firmware/transaction.c b/firmware/transaction.c index 45b70da2d0..6b0ec88e6c 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -71,7 +71,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return 0; } layoutProgressUpdate(true); - ecdsa_get_address_raw(node.public_key, coin->address_type, addr_raw); + hdnode_get_address_raw(&node, coin->address_type, addr_raw); } else if (in->has_address) { // address provided -> regular output if (needs_confirm) { diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 16f477787d..3390fcf89e 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 16f477787d7e59a37e0f05807182cef8aeb1e2d5 +Subproject commit 3390fcf89e5502d6087a8b0d182fc9db05bbd759