159 lines
5.5 KiB
C
159 lines
5.5 KiB
C
/*******************************************************************************
|
|
* Ledger Blue - Bitcoin Wallet
|
|
* (c) 2016 Ledger
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
********************************************************************************/
|
|
|
|
#include "btchip_internal.h"
|
|
#include "btchip_apdu_constants.h"
|
|
|
|
#define SIGHASH_ALL 0x01
|
|
#ifdef COIN_BITCOIN_CASH
|
|
#define SIGHASH_FORKID 0x40
|
|
#endif
|
|
|
|
unsigned short btchip_apdu_hash_sign() {
|
|
unsigned long int lockTime;
|
|
unsigned char sighashType;
|
|
unsigned char dataBuffer[8];
|
|
unsigned char hash1[32];
|
|
unsigned char hash2[32];
|
|
unsigned char authorizationLength;
|
|
unsigned char *parameters = G_io_apdu_buffer + ISO_OFFSET_CDATA;
|
|
btchip_transaction_summary_t
|
|
transactionSummary; // could be removed with a refactor
|
|
unsigned char *authorization;
|
|
unsigned short sw;
|
|
unsigned char keyPath[MAX_BIP32_PATH_LENGTH];
|
|
cx_sha256_t localHash;
|
|
|
|
SB_CHECK(N_btchip.bkp.config.operationMode);
|
|
switch (SB_GET(N_btchip.bkp.config.operationMode)) {
|
|
case BTCHIP_MODE_WALLET:
|
|
case BTCHIP_MODE_RELAXED_WALLET:
|
|
case BTCHIP_MODE_SERVER:
|
|
break;
|
|
default:
|
|
return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED;
|
|
}
|
|
|
|
if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) &&
|
|
(G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) {
|
|
return BTCHIP_SW_INCORRECT_P1_P2;
|
|
}
|
|
|
|
if (G_io_apdu_buffer[ISO_OFFSET_LC] < (1 + 1 + 4 + 1)) {
|
|
return BTCHIP_SW_INCORRECT_LENGTH;
|
|
}
|
|
|
|
// Check state
|
|
BEGIN_TRY {
|
|
TRY {
|
|
btchip_set_check_internal_structure_integrity(0);
|
|
if (btchip_context_D.transactionContext.transactionState !=
|
|
BTCHIP_TRANSACTION_SIGN_READY) {
|
|
L_DEBUG_APP(
|
|
("Invalid transaction state %d\n",
|
|
btchip_context_D.transactionContext.transactionState));
|
|
sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED;
|
|
goto discardTransaction;
|
|
}
|
|
|
|
// Read parameters
|
|
if (G_io_apdu_buffer[ISO_OFFSET_CDATA] > MAX_BIP32_PATH) {
|
|
sw = BTCHIP_SW_INCORRECT_DATA;
|
|
goto discardTransaction;
|
|
}
|
|
os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA,
|
|
MAX_BIP32_PATH_LENGTH);
|
|
parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1;
|
|
authorizationLength = *(parameters++);
|
|
authorization = parameters;
|
|
parameters += authorizationLength;
|
|
lockTime = btchip_read_u32(parameters, 1, 0);
|
|
parameters += 4;
|
|
sighashType = *(parameters++);
|
|
|
|
if (((N_btchip.bkp.config.options &
|
|
BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) {
|
|
#ifdef COIN_BITCOIN_CASH
|
|
if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) {
|
|
sw = BTCHIP_SW_INCORRECT_DATA;
|
|
goto discardTransaction;
|
|
}
|
|
#else
|
|
if (sighashType != SIGHASH_ALL) {
|
|
sw = BTCHIP_SW_INCORRECT_DATA;
|
|
goto discardTransaction;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Read transaction parameters
|
|
// TODO : remove copy
|
|
os_memmove(&transactionSummary,
|
|
&btchip_context_D.transactionSummary,
|
|
sizeof(transactionSummary));
|
|
|
|
// Fetch the private key
|
|
|
|
btchip_private_derive_keypair(keyPath, 0, NULL);
|
|
|
|
// TODO optional : check the public key against the associated non
|
|
// blank input to sign
|
|
|
|
// Finalize the hash
|
|
|
|
btchip_write_u32_le(dataBuffer, lockTime);
|
|
btchip_write_u32_le(dataBuffer + 4, sighashType);
|
|
L_DEBUG_BUF(
|
|
("Finalize hash with\n", dataBuffer, sizeof(dataBuffer)));
|
|
|
|
cx_hash(&btchip_context_D.transactionHashFull.header, CX_LAST,
|
|
dataBuffer, sizeof(dataBuffer), hash1);
|
|
L_DEBUG_BUF(("Hash1\n", hash1, sizeof(hash1)));
|
|
|
|
// Rehash
|
|
cx_sha256_init(&localHash);
|
|
cx_hash(&localHash.header, CX_LAST, hash1, sizeof(hash1), hash2);
|
|
L_DEBUG_BUF(("Hash2\n", hash2, sizeof(hash2)));
|
|
|
|
// Sign
|
|
btchip_signverify_finalhash(
|
|
&btchip_private_key_D, 1, hash2, sizeof(hash2),
|
|
G_io_apdu_buffer, sizeof(G_io_apdu_buffer),
|
|
((N_btchip.bkp.config.options &
|
|
BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0));
|
|
|
|
btchip_context_D.outLength = G_io_apdu_buffer[1] + 2;
|
|
G_io_apdu_buffer[btchip_context_D.outLength++] = sighashType;
|
|
|
|
sw = BTCHIP_SW_OK;
|
|
|
|
// Then discard the transaction and reply
|
|
}
|
|
CATCH_ALL {
|
|
sw = SW_TECHNICAL_DETAILS(0xF);
|
|
discardTransaction:
|
|
btchip_context_D.transactionContext.transactionState =
|
|
BTCHIP_TRANSACTION_NONE;
|
|
}
|
|
FINALLY {
|
|
btchip_set_check_internal_structure_integrity(1);
|
|
return sw;
|
|
}
|
|
}
|
|
END_TRY;
|
|
}
|