diff --git a/src/commander.c b/src/commander.c
index 19aeedef..8af88348 100644
--- a/src/commander.c
+++ b/src/commander.c
@@ -50,6 +50,11 @@
#include "ecdh.h"
+#if defined(TESTING) && defined(__SAM4S4A__)
+#error TESTING should not be defined for embedded code
+#endif
+
+
#define BRACED(x) (strlens(x) ? (((x[0]) == '{') && ((x[strlens(x) - 1]) == '}')) : 0)
@@ -467,13 +472,11 @@ static void commander_process_seed(yajl_val json_node)
int ret;
const char *key_path[] = { cmd_str(CMD_seed), cmd_str(CMD_key), NULL };
- const char *raw_path[] = { cmd_str(CMD_seed), cmd_str(CMD_raw), NULL };
const char *source_path[] = { cmd_str(CMD_seed), cmd_str(CMD_source), NULL };
const char *entropy_path[] = { cmd_str(CMD_seed), cmd_str(CMD_entropy), NULL };
const char *filename_path[] = { cmd_str(CMD_seed), cmd_str(CMD_filename), NULL };
const char *u2f_counter_path[] = { cmd_str(CMD_seed), cmd_str(CMD_U2F_counter), NULL };
const char *key = YAJL_GET_STRING(yajl_tree_get(json_node, key_path, yajl_t_string));
- const char *raw = YAJL_GET_STRING(yajl_tree_get(json_node, raw_path, yajl_t_string));
const char *source = YAJL_GET_STRING(yajl_tree_get(json_node, source_path,
yajl_t_string));
const char *entropy = YAJL_GET_STRING(yajl_tree_get(json_node, entropy_path,
@@ -510,7 +513,7 @@ static void commander_process_seed(yajl_val json_node)
if (STREQ(source, attr_str(ATTR_create))) {
// Generate a new wallet, optionally with entropy entered via USB
- uint8_t i, add_entropy, entropy_b[MEM_PAGE_LEN];
+ uint8_t i, add_entropy = 1, entropy_b[MEM_PAGE_LEN];
char entropy_c[MEM_PAGE_LEN * 2 + 1];
memset(entropy_b, 0, sizeof(entropy_b));
@@ -521,20 +524,23 @@ static void commander_process_seed(yajl_val json_node)
}
if (strlens(entropy)) {
- if (strlens(entropy) == MEM_PAGE_LEN * 2 && utils_is_hex(entropy)) {
- // Allows recover from a Digital Bitbox backup text entered via USB
- memcpy(entropy_b, utils_hex_to_uint8(entropy), sizeof(entropy_b));
+ if (strlens(entropy) != SHA256_DIGEST_LENGTH * 2) {
+ commander_fill_report(cmd_str(CMD_seed), NULL, DBB_ERR_IO_INVALID_CMD);
+ return;
}
sha256_Raw((const uint8_t *)entropy, strlens(entropy), entropy_b);
}
+#ifdef TESTING
// Add extra entropy from device unless raw is set
- add_entropy = 1;
+ const char *raw_path[] = { cmd_str(CMD_seed), cmd_str(CMD_raw), NULL };
+ const char *raw = YAJL_GET_STRING(yajl_tree_get(json_node, raw_path, yajl_t_string));
if (strlens(entropy) && strlens(raw)) {
if (STREQ(raw, attr_str(ATTR_true))) {
add_entropy = 0;
}
}
+#endif
if (add_entropy) {
uint8_t number[MEM_PAGE_LEN];
@@ -545,6 +551,7 @@ static void commander_process_seed(yajl_val json_node)
for (i = 0; i < MEM_PAGE_LEN; i++) {
entropy_b[i] ^= number[i];
}
+ sha256_Raw(entropy_b, sizeof(entropy_b), entropy_b);
}
snprintf(entropy_c, sizeof(entropy_c), "%s", utils_uint8_to_hex(entropy_b,
diff --git a/src/random.c b/src/random.c
index 566bbe0a..55172202 100644
--- a/src/random.c
+++ b/src/random.c
@@ -89,7 +89,7 @@ int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed)
for (i = 0; i < MIN(len, MEM_PAGE_LEN); i++) {
buf[i] ^= entropy[i];
}
- // Add entropy from usersig
+ // Add entropy from the random number stored in the MCU's 'user signature' memory area
flash_read_user_signature((uint32_t *)usersig, FLASH_USERSIG_SIZE / sizeof(uint32_t));
sha256_Raw(usersig, FLASH_USERSIG_SIZE, entropy);
for (i = 0; i < MIN(len, MEM_PAGE_LEN); i++) {
@@ -105,13 +105,13 @@ int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed)
while (len > n) {
if (update_seed) {
ret = ataes_process(ataes_cmd_up, sizeof(ataes_cmd_up), ataes_ret, sizeof(ataes_ret));
- update_seed = 0;
} else {
ret = ataes_process(ataes_cmd, sizeof(ataes_cmd), ataes_ret, sizeof(ataes_ret));
}
if (ret == DBB_OK && ataes_ret[0] && !ataes_ret[1]) {
- for (i = 0; i < MIN(len - n, ATAES_RAND_LEN); i++) {
- buf[(n + i) % len] ^= ataes_ret[(2 + i) % sizeof(ataes_ret)];
+ sha256_Raw(ataes_ret + 2, ATAES_RAND_LEN, entropy);
+ for (i = 0; i < MIN(len - n, MEM_PAGE_LEN); i++) {
+ buf[(n + i)] ^= entropy[i];
}
} else {
flash_erase_user_signature();
@@ -121,6 +121,11 @@ int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed)
}
n += ATAES_RAND_LEN;
}
+ // Replaces up to the first 32B of the random number with a SHA256 hash
+ // Helps protect against a backdoored HRNG
+ sha256_Raw(buf, len, entropy);
+ memcpy(buf, entropy, MIN(len, MEM_PAGE_LEN));
+ utils_zero(entropy, sizeof(entropy));
#endif
return DBB_OK;
}
diff --git a/src/sha2.c b/src/sha2.c
index ba3853be..c38cee79 100644
--- a/src/sha2.c
+++ b/src/sha2.c
@@ -134,8 +134,13 @@ typedef uint64_t sha2_word64; /* Exactly 8 bytes */
} \
}
-#define MEMSET_BZERO(p,l) memset((p), 0, (l))
#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l))
+static volatile void *MEMSET_BZERO(volatile void *dst, size_t len)
+{
+ volatile char *buf;
+ for (buf = (volatile char *)dst; len; buf[--len] = 0);
+ return dst;
+}
/*** THE SIX LOGICAL FUNCTIONS ****************************************/
/*
diff --git a/src/utils.c b/src/utils.c
index 46fda0a2..70dd72a6 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -43,7 +43,7 @@ static uint8_t utils_buffer[UTILS_BUFFER_LEN];
volatile void *utils_zero(volatile void *dst, size_t len)
{
volatile char *buf;
- for (buf = (volatile char *)dst; len; buf[--len] = 0);
+ for (buf = (volatile char *)dst; len; buf[--len] = 0);
return dst;
}
diff --git a/tests/api.h b/tests/api.h
index de3ba8f0..b2bf8cf0 100644
--- a/tests/api.h
+++ b/tests/api.h
@@ -474,6 +474,30 @@ static const char *api_read_value_depth_2(int cmd, int cmd_2)
}
+static const char *api_read_array_value(int cmd, int cmd_2, int index)
+{
+ const char *path[] = { cmd_str(cmd), NULL };
+ const char *a_path[] = { cmd_str(cmd_2), NULL };
+ static char value[HID_REPORT_SIZE];
+ memset(value, 0, sizeof(value));
+
+ yajl_val json_node = yajl_tree_parse(api_read_decrypted_report(), NULL, 0);
+ if (json_node && YAJL_IS_OBJECT(json_node)) {
+ yajl_val data = yajl_tree_get(json_node, path, yajl_t_array);
+ if (YAJL_IS_ARRAY(data) && data->u.array.len != 0) {
+ yajl_val obj = data->u.array.values[index];
+ const char *a = YAJL_GET_STRING(yajl_tree_get(obj, a_path, yajl_t_string));
+ if (a) {
+ snprintf(value, sizeof(value), "%s", a);
+ }
+ }
+ }
+
+ yajl_tree_free(json_node);
+ return value;
+}
+
+
static char *api_read_value_decrypt(int cmd, uint8_t *key)
{
const char *val = api_read_value(cmd);
diff --git a/tests/tests_api.c b/tests/tests_api.c
index e048909a..d2433cde 100644
--- a/tests/tests_api.c
+++ b/tests/tests_api.c
@@ -33,6 +33,7 @@
#include "ecdh.h"
#include "ecc.h"
#include "sha2.h"
+#include "bip32.h"
#include "utest.h"
#include "utils.h"
#include "flags.h"
@@ -46,6 +47,23 @@
#include "api.h"
#include "hmac_check.h"
+
+#define HASH_DEFAULT "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+#define HASH_INPUT_ONE "c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a"
+#define HASH_INPUT_TWO_1 "c12d791451bb41fd4b5145bcef25f794ca33c0cf4fe9d24f956086c5aa858a9d"
+#define HASH_INPUT_TWO_2 "3dfc3b1ed349e9b361b31c706fbf055ebf46ae725740f6739e2dfa87d2a98790"
+#define KEYPATH_BASE "m/44p"
+#define KEYPATH_ONE "m/44'/0'/0'/1/7"
+#define KEYPATH_TWO "m/44'/0'/0'/1/8"
+#define KEYPATH_THREE "m/44'/0'/0'/0/5"
+#define PUBKEY_INPUT_ONE "025acc8c55e1a786f7b8ca742f725909019c849abe2051b7bc8bc580af3dc17154"
+#define PUBKEY_INPUT_TWO_1 "035e8c69793fd853795759b8ca12229d7b2e7ec2223221dc224885fc9a1e7e1704"
+#define PUBKEY_INPUT_TWO_2 "03cc673784d8dfe97ded72c91ebb1b87a52761e4be20f6229e56fd61fdf28ae3f2"
+#define PUBKEY_ZERO "000000000000000000000000000000000000000000000000000000000000000000"
+#define RECID_01 "01"
+#define RECID_EE "ee"
+
+
int U_TESTS_RUN = 0;
int U_TESTS_FAIL = 0;
@@ -67,7 +85,10 @@ static void tests_seed_xpub_backup(void)
"{\"source\":\"create\", \"filename\":\"seed_create_2.pdf\", \"key\":\"password\"}";
char seed_create_bad[] =
"{\"source\":\"create\", \"filename\":\"../seed_create_bad.pdf\", \"key\":\"password\"}";
- char seed_entropy[] = "entropy9s21ZrQkmL8hdy";
+ char seed_entropy[] = "entropy_>.$#`}0123456789abcdef0123456789abcdef0123456789abcdef";
+ char seed_entropy_short[] = "entropy_tooshort";
+ char seed_entropy_long[] =
+ "entropy_>.$#`0123456789abcdef0123456789abcdef0123456789abcdef_toolong";
snprintf(seed_c, sizeof(seed_c),
"{\"source\":\"%s\", \"filename\":\"%s\", \"key\":\"%s\"}", attr_str(ATTR_create),
@@ -372,6 +393,20 @@ static void tests_seed_xpub_backup(void)
memcpy(xpub0, api_read_value(CMD_xpub), sizeof(xpub0));
u_assert_str_not_eq(xpub0, xpub1);
+ // seed with extra entropy from device (entropy too short)
+ snprintf(seed_usb, sizeof(seed_usb),
+ "{\"source\":\"create\",\"entropy\":\"%s\",\"filename\":\"%s\",\"key\":\"%s\"}",
+ seed_entropy_short, filename2, key);
+ api_format_send_cmd(cmd_str(CMD_seed), seed_usb, KEY_STANDARD);
+ ASSERT_REPORT_HAS(flag_msg(DBB_ERR_IO_INVALID_CMD));
+
+ // seed with extra entropy from device (entropy too long)
+ snprintf(seed_usb, sizeof(seed_usb),
+ "{\"source\":\"create\",\"entropy\":\"%s\",\"filename\":\"%s\",\"key\":\"%s\"}",
+ seed_entropy_long, filename2, key);
+ api_format_send_cmd(cmd_str(CMD_seed), seed_usb, KEY_STANDARD);
+ ASSERT_REPORT_HAS(flag_msg(DBB_ERR_IO_INVALID_CMD));
+
// seed with extra entropy from device
snprintf(seed_usb, sizeof(seed_usb),
"{\"source\":\"create\",\"entropy\":\"%s\",\"filename\":\"%s\",\"key\":\"%s\"}",
@@ -1056,8 +1091,8 @@ static void tests_u2f(void)
if (!TEST_LIVE_DEVICE) {
const char one_input[] =
- "{\"data\":[{\"hash\":\"c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a\", \"keypath\":\"m/44'/0'/0'/1/7\"}]}";
- const char hash_1_input[] =
+ "{\"data\":[{\"hash\":\"" HASH_INPUT_ONE "\", \"keypath\":\"" KEYPATH_ONE "\"}]}";
+ const char sig_1_input[] =
"61e87a12a111987e3bef9dffd4b30a0322f2cc74e65a19aa551a3eaa8f417d0b18305a52f94153980f6e6d4383decc68028764b4f60ecb0d2a28e74359073012";
const char tb_v2_3a[] = "test_backup.pdf";
const char tb_v2_3h[] = "test_backup_hww.pdf";
@@ -1116,11 +1151,11 @@ static void tests_u2f(void)
char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len,
memory_report_aeskey(TFA_SHARED_SECRET), hmac);
u_assert(echo);
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
- ASSERT_REPORT_HAS_NOT(hash_1_input);
+ ASSERT_REPORT_HAS_NOT(sig_1_input);
// recover fn4 u2f success
@@ -1163,11 +1198,11 @@ static void tests_u2f(void)
char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len,
memory_report_aeskey(TFA_SHARED_SECRET), hmac);
u_assert(echo);
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
- ASSERT_REPORT_HAS(hash_1_input);
+ ASSERT_REPORT_HAS(sig_1_input);
// recover fn4 hww success
@@ -1192,11 +1227,11 @@ static void tests_u2f(void)
char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len,
memory_report_aeskey(TFA_SHARED_SECRET), hmac);
u_assert(echo);
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
- ASSERT_REPORT_HAS_NOT(hash_1_input);
+ ASSERT_REPORT_HAS_NOT(sig_1_input);
// recover v23a u2f success
@@ -1245,11 +1280,11 @@ static void tests_u2f(void)
char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len,
memory_report_aeskey(TFA_SHARED_SECRET), hmac);
u_assert(echo);
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
- ASSERT_REPORT_HAS(hash_1_input);
+ ASSERT_REPORT_HAS(sig_1_input);
// recover fn4 hww success
@@ -1274,11 +1309,11 @@ static void tests_u2f(void)
char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len,
memory_report_aeskey(TFA_SHARED_SECRET), hmac);
u_assert(echo);
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
- ASSERT_REPORT_HAS_NOT(hash_1_input);
+ ASSERT_REPORT_HAS_NOT(sig_1_input);
// recover v22 hww success
@@ -1304,11 +1339,11 @@ static void tests_u2f(void)
char *echo = decrypt_and_check_hmac((const unsigned char *)val, strlens(val), &len,
memory_report_aeskey(TFA_SHARED_SECRET), hmac);
u_assert(echo);
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
- ASSERT_REPORT_HAS(hash_1_input);
+ ASSERT_REPORT_HAS(sig_1_input);
}
@@ -1905,11 +1940,14 @@ static void tests_password(void)
static void tests_echo_tfa(void)
{
char hash_sign[] =
- "{\"meta\":\"hash\", \"data\":[{\"keypath\":\"m/44'/0'/0'/1/7\", \"hash\":\"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"}] }";
+ "{\"meta\":\"hash\", \"data\":[{\"keypath\":\"" KEYPATH_ONE "\", \"hash\":\"" HASH_DEFAULT
+ "\"}] }";
char hash_sign2[] =
- "{\"meta\":\"hash\", \"data\":[{\"keypath\":\"m/44'/0'/0'/1/7\", \"hash\":\"ffff456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"}] }";
+ "{\"meta\":\"hash\", \"data\":[{\"keypath\":\"" KEYPATH_ONE
+ "\", \"hash\":\"ffff456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"}] }";
char hash_sign3[] =
- "{\"meta\":\"hash\", \"data\":[{\"keypath\":\"m/44'/0'/0'/1/7\", \"hash\":\"456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"}] }";
+ "{\"meta\":\"hash\", \"data\":[{\"keypath\":\"" KEYPATH_ONE
+ "\", \"hash\":\"456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"}] }";
api_reset_device();
@@ -2066,7 +2104,7 @@ static int recover_public_key_verify_sig(const char *sig, const char *hash,
memcpy(hash_b, utils_hex_to_uint8(hash), 32);
memcpy(sig_b, utils_hex_to_uint8(sig), 64);
memcpy(&recid_b, utils_hex_to_uint8(recid), 1);
- memset(pubkey_33, 0, 33);
+ memset(pubkey_33, 0, public_key_len);
if (!ctx) {
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
@@ -2105,42 +2143,26 @@ static int recover_public_key_verify_sig(const char *sig, const char *hash,
}
-// hash_1_input is normalized (low-S). The non-normalized value is "61e87a12a111987e3bef9dffd4b30a0322f2cc74e65a19aa551a3eaa8f417d0be7cfa5ad06beac67f09192bc7c213396b8277831b939d52e95a97749772f112f"
-const char hash_1_input[] =
+// sig_1_input is normalized (low-S). The non-normalized value is "61e87a12a111987e3bef9dffd4b30a0322f2cc74e65a19aa551a3eaa8f417d0be7cfa5ad06beac67f09192bc7c213396b8277831b939d52e95a97749772f112f"
+const char sig_1_input[] =
"61e87a12a111987e3bef9dffd4b30a0322f2cc74e65a19aa551a3eaa8f417d0b18305a52f94153980f6e6d4383decc68028764b4f60ecb0d2a28e74359073012";
-const char hash_2_input_1[] =
+const char sig_2_input_1[] =
"e26c9b19c927d7e6e374d7f1734dd0a4e1ee266a164b2f282d95a0d07dbf04f0486594e9d853cbfab1cc556e76e8212d2db6c871c8c775876525d20acc478439";
-const char hash_2_input_2[] =
+const char sig_2_input_2[] =
"529e01807f073dd80a0c9c2b3cc9130a06b88c033577ccc426a383eaadac5b7201923aef70ded7509adfa6282fcb6ff9f0fba16f87c82d5c9810c3da3029cc7d";
static void tests_sign(void)
{
int i, res;
- char one_input_msg[] = "c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a";
- char one_input[] =
- "{\"meta\":\"_meta_data_\", \"data\":[{\"hash\":\"c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a\", \"keypath\":\"m/44'/0'/0'/1/7\"}]}";
- char pubkey_1_input[] =
- "025acc8c55e1a786f7b8ca742f725909019c849abe2051b7bc8bc580af3dc17154";
- char recid_1_input[] = "01";
-
- char two_input_msg_1[] =
- "c12d791451bb41fd4b5145bcef25f794ca33c0cf4fe9d24f956086c5aa858a9d";
- char two_input_msg_2[] =
- "3dfc3b1ed349e9b361b31c706fbf055ebf46ae725740f6739e2dfa87d2a98790";
- char two_inputs[] =
- "{\"meta\":\"_meta_data_\", \"data\":[{\"hash\":\"c12d791451bb41fd4b5145bcef25f794ca33c0cf4fe9d24f956086c5aa858a9d\", \"keypath\":\"m/44'/0'/0'/1/8\"},{\"hash\":\"3dfc3b1ed349e9b361b31c706fbf055ebf46ae725740f6739e2dfa87d2a98790\", \"keypath\":\"m/44'/0'/0'/0/5\"}]}";
- char pubkey_2_input_1[] =
- "035e8c69793fd853795759b8ca12229d7b2e7ec2223221dc224885fc9a1e7e1704";
- char pubkey_2_input_2[] =
- "03cc673784d8dfe97ded72c91ebb1b87a52761e4be20f6229e56fd61fdf28ae3f2";
- char recid_2_input_1[] = "01";
- char recid_2_input_2[] = "01";
-
- char hashstr[] =
- "{\"hash\":\"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\", \"keypath\":\"m/44p/0p/0p/0/9999\"}";
- char hashstart[] =
- "{\"meta\":\"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\", \"checkpub\":[{\"pubkey\":\"000000000000000000000000000000000000000000000000000000000000000000\", \"keypath\":\"m/44p/0p/0p/1/9999\"}], \"data\": [";
+ char one_input[] = "{\"meta\":\"_meta_data_\", \"data\":[{\"hash\":\"" HASH_INPUT_ONE
+ "\", \"keypath\":\"" KEYPATH_ONE "\"}]}";
+ char two_inputs[] = "{\"meta\":\"_meta_data_\", \"data\":[{\"hash\":\"" HASH_INPUT_TWO_1
+ "\", \"keypath\":\"" KEYPATH_TWO "\"},{\"hash\":\"" HASH_INPUT_TWO_2 "\", \"keypath\":\""
+ KEYPATH_THREE "\"}]}";
+ char hashstr[] = "{\"hash\":\"" HASH_DEFAULT "\", \"keypath\":\"m/44p/0p/0p/0/9999\"}";
+ char hashstart[] = "{\"meta\":\"" HASH_DEFAULT "\", \"checkpub\":[{\"pubkey\":\""
+ PUBKEY_ZERO "\", \"keypath\":\"m/44p/0p/0p/1/9999\"}], \"data\": [";
char maxhashes[COMMANDER_REPORT_SIZE];
char hashoverflow[COMMANDER_REPORT_SIZE];
@@ -2164,16 +2186,16 @@ static void tests_sign(void)
u_assert_int_eq(i >= COMMANDER_NUM_SIG_MIN, 1);
- char checkpub_msg_1[] =
- "c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a";
- char checkpub_msg_2[] =
- "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
char checkpub[] =
- "{\"meta\":\"<>\", \"data\": [{\"hash\":\"c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a\", \"keypath\":\"m/44p\"},{\"hash\":\"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\", \"keypath\":\"m/44p\"}], \"checkpub\":[{\"pubkey\":\"000000000000000000000000000000000000000000000000000000000000000000\", \"keypath\":\"m/44p/0p/0p/1/8\"},{\"pubkey\":\"035e8c69793fd853795759b8ca12229d7b2e7ec2223221dc224885fc9a1e7e1704\", \"keypath\":\"m/44p/0p/0p/1/8\"}]}";
+ "{\"meta\":\"<>\", \"data\": [{\"hash\":\"" HASH_INPUT_ONE
+ "\", \"keypath\":\"" KEYPATH_BASE "\"},{\"hash\":\"" HASH_DEFAULT "\", \"keypath\":\""
+ KEYPATH_BASE "\"}], \"checkpub\":[{\"pubkey\":\"" PUBKEY_ZERO "\", \"keypath\":\""
+ KEYPATH_TWO "\"},{\"pubkey\":\"" PUBKEY_INPUT_TWO_1 "\", \"keypath\":\""
+ KEYPATH_TWO"\"}]}";
char check_1[] =
- "\"pubkey\":\"000000000000000000000000000000000000000000000000000000000000000000\", \"present\":false";
+ "\"pubkey\":\"" PUBKEY_ZERO "\", \"present\":false";
char check_2[] =
- "\"pubkey\":\"035e8c69793fd853795759b8ca12229d7b2e7ec2223221dc224885fc9a1e7e1704\", \"present\":true";
+ "\"pubkey\":\"" PUBKEY_INPUT_TWO_1 "\", \"present\":true";
// check_sig_1 is normalized (low-S). The non-normalized value is "2a756acd456b732e779cd7e7f05ae2855ee3128bca75cb8fc805bba8c6fbabba924e51ccac655024165bb302d00174d842e5960cde8c448a6a900d26fe342fe9"
char check_sig_1[] =
"2a756acd456b732e779cd7e7f05ae2855ee3128bca75cb8fc805bba8c6fbabba6db1ae33539aafdbe9a44cfd2ffe8b2677c946d9d0bc5bb155425165d2021158";
@@ -2181,14 +2203,26 @@ static void tests_sign(void)
"3323b353e9974ab1eb452eca19e1dc4dad0556dba668089c8c1214ca09b58ad12c82da6671a65f9b3803c1fe7a14f35d885caebce701f972641748738275782b";
char check_pubkey[] =
"02df86355b162c942b89e297c1e919f40943834d448b0b6b4538556e805ea4e18c";
- char check_recid_1[] = "01";
- char check_recid_2[] = "01";
char checkpub_wrong_addr_len[] =
- "{\"meta\":\"<>\", \"data\": [{\"hash\":\"c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a\", \"keypath\":\"m/44p\"},{\"hash\":\"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\", \"keypath\":\"m/44p\"}], \"checkpub\":[{\"pubkey\":\"00\", \"keypath\":\"m/44p/0p/0p/1/8\"},{\"pubkey\":\"035e8c69793fd853795759b8ca12229d7b2e7ec2223221dc224885fc9a1e7e1704\", \"keypath\":\"m/44p/0p/0p/1/8\"}]}";
+ "{\"meta\":\"<>\", \"data\": [{\"hash\":\"" HASH_INPUT_ONE
+ "\", \"keypath\":\"" KEYPATH_BASE "\"},{\"hash\":\"" HASH_DEFAULT "\", \"keypath\":\""
+ KEYPATH_BASE "\"}], \"checkpub\":[{\"pubkey\":\"00\", \"keypath\":\"" KEYPATH_TWO
+ "\"},{\"pubkey\":\"" PUBKEY_INPUT_TWO_1 "\", \"keypath\":\"" KEYPATH_TWO "\"}]}";
char checkpub_missing_parameter[] =
- "{\"meta\":\"<>\", \"data\": [{\"hash\":\"c6fa4c236f59020ec8ffde22f85a78e7f256e94cd975eb5199a4a5cc73e26e4a\", \"keypath\":\"m/44p\"},{\"hash\":\"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\", \"keypath\":\"m/44p\"}], \"checkpub\":[{\"pubkey\":\"035e8c69793fd853795759b8ca12229d7b2e7ec2223221dc224885fc9a1e7e1704\"}]}";
+ "{\"meta\":\"<>\", \"data\": [{\"hash\":\"" HASH_INPUT_ONE
+ "\", \"keypath\":\"" KEYPATH_BASE "\"},{\"hash\":\"" HASH_DEFAULT "\", \"keypath\":\""
+ KEYPATH_BASE "\"}], \"checkpub\":[{\"pubkey\":\"" PUBKEY_INPUT_TWO_1 "\"}]}";
+
+ char sig_device_1[64 * 2 + 1];
+ char sig_device_2[64 * 2 + 1];
+ char recid_device_1[2 + 1];
+ char recid_device_2[2 + 1];
+ char pubkey_device_1[33 * 2 + 1];
+ char pubkey_device_2[33 * 2 + 1];
+ HDNode node;
+ memset(&node, 0, sizeof(HDNode));
api_reset_device();
@@ -2200,9 +2234,14 @@ static void tests_sign(void)
api_format_send_cmd(cmd_str(CMD_backup), attr_str(ATTR_erase), KEY_STANDARD);
ASSERT_SUCCESS;
- // seed
- char seed[] =
- "{\"key\":\"key\", \"source\":\"create\", \"entropy\":\"entropy_rawH13ucR3\", \"raw\":\"true\", \"filename\":\"s.pdf\"}";
+ // copy test sd_files to sd card directory
+ int ret = system("cp ../tests/sd_files/*.pdf tests/digitalbitbox/");
+ u_assert(ret == 0);
+
+ // seed from backup file
+ char seed[512];
+ snprintf(seed, sizeof(seed), "{\"source\":\"%s\", \"filename\":\"%s\", \"key\":\"key\"}",
+ attr_str(ATTR_backup), "test_backup.pdf");
api_format_send_cmd(cmd_str(CMD_seed), seed, KEY_STANDARD);
ASSERT_REPORT_HAS_NOT(attr_str(ATTR_error));
@@ -2257,6 +2296,11 @@ static void tests_sign(void)
ASSERT_REPORT_HAS(flag_msg(DBB_ERR_IO_INVALID_CMD));
// sign using one input
+ api_format_send_cmd(cmd_str(CMD_xpub), KEYPATH_ONE, KEY_STANDARD);
+ hdnode_deserialize(api_read_value(CMD_xpub), &node);
+ snprintf(pubkey_device_1, sizeof(pubkey_device_1), "%s",
+ utils_uint8_to_hex(node.public_key, 33));
+
api_format_send_cmd(cmd_str(CMD_sign), one_input, KEY_STANDARD);
ASSERT_REPORT_HAS(cmd_str(CMD_echo));
if (!TEST_LIVE_DEVICE) {
@@ -2268,18 +2312,48 @@ static void tests_sign(void)
u_assert(echo);
u_assert_str_has_not(echo, cmd_str(CMD_recid));
u_assert_str_has(echo, "_meta_data_");
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
ASSERT_REPORT_HAS(cmd_str(CMD_recid));
- ASSERT_REPORT_HAS(hash_1_input);
- res = recover_public_key_verify_sig(hash_1_input, one_input_msg, recid_1_input,
- pubkey_1_input);
- u_assert_int_eq(res, 0);
+
+ memcpy(sig_device_1, api_read_array_value(CMD_sign, CMD_sig, 0), sizeof(sig_device_1));
+ memcpy(recid_device_1, api_read_array_value(CMD_sign, CMD_recid, 0),
+ sizeof(recid_device_1));
+
+ u_assert_int_eq(0, recover_public_key_verify_sig(sig_device_1, HASH_INPUT_ONE,
+ recid_device_1, pubkey_device_1));
+
+ if (!TEST_LIVE_DEVICE) {
+ // If TESTING, a deterministic seed is loaded when 'raw' is specified
+ ASSERT_REPORT_HAS(sig_1_input);
+ u_assert_str_eq(sig_device_1, sig_1_input);
+ u_assert_str_eq(pubkey_device_1, PUBKEY_INPUT_ONE);
+#ifdef ECC_USE_SECP256K1_LIB
+ u_assert_str_eq(recid_device_1, RECID_01);
+#else
+ u_assert_str_eq(recid_device_1, RECID_EE);
+#endif
+ } else {
+ // Random seed generated on device
+ ASSERT_REPORT_HAS_NOT(sig_1_input);
+ u_assert_str_not_eq(sig_device_1, sig_1_input);
+ u_assert_str_not_eq(pubkey_device_1, PUBKEY_INPUT_ONE);
+ }
// sign using two inputs
+ api_format_send_cmd(cmd_str(CMD_xpub), KEYPATH_TWO, KEY_STANDARD);
+ hdnode_deserialize(api_read_value(CMD_xpub), &node);
+ snprintf(pubkey_device_1, sizeof(pubkey_device_1), "%s",
+ utils_uint8_to_hex(node.public_key, 33));
+
+ api_format_send_cmd(cmd_str(CMD_xpub), KEYPATH_THREE, KEY_STANDARD);
+ hdnode_deserialize(api_read_value(CMD_xpub), &node);
+ snprintf(pubkey_device_2, sizeof(pubkey_device_2), "%s",
+ utils_uint8_to_hex(node.public_key, 33));
+
api_format_send_cmd(cmd_str(CMD_sign), two_inputs, KEY_STANDARD);
ASSERT_REPORT_HAS(cmd_str(CMD_echo));
if (!TEST_LIVE_DEVICE) {
@@ -2291,24 +2365,60 @@ static void tests_sign(void)
u_assert(echo);
u_assert_str_has_not(echo, cmd_str(CMD_recid));
u_assert_str_has(echo, "_meta_data_");
- u_assert_str_has(echo, "m/44'/0'/0'/1/8");
+ u_assert_str_has(echo, KEYPATH_TWO);
free(echo);
}
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
ASSERT_REPORT_HAS(cmd_str(CMD_sign));
- ASSERT_REPORT_HAS(hash_2_input_1);
- ASSERT_REPORT_HAS(hash_2_input_2);
- ASSERT_REPORT_HAS(cmd_str(CMD_recid));
- res = recover_public_key_verify_sig(hash_2_input_1, two_input_msg_1, recid_2_input_1,
- pubkey_2_input_1);
- u_assert_int_eq(res, 0);
- res = recover_public_key_verify_sig(hash_2_input_2, two_input_msg_2, recid_2_input_2,
- pubkey_2_input_2);
- u_assert_int_eq(res, 0);
+ memcpy(sig_device_1, api_read_array_value(CMD_sign, CMD_sig, 0), sizeof(sig_device_1));
+ memcpy(sig_device_2, api_read_array_value(CMD_sign, CMD_sig, 1), sizeof(sig_device_2));
+ memcpy(recid_device_1, api_read_array_value(CMD_sign, CMD_recid, 0),
+ sizeof(recid_device_1));
+ memcpy(recid_device_2, api_read_array_value(CMD_sign, CMD_recid, 1),
+ sizeof(recid_device_2));
+
+ u_assert_int_eq(0, recover_public_key_verify_sig(sig_device_1, HASH_INPUT_TWO_1,
+ recid_device_1, pubkey_device_1));
+ u_assert_int_eq(0, recover_public_key_verify_sig(sig_device_2, HASH_INPUT_TWO_2,
+ recid_device_2, pubkey_device_2));
+
+ if (!TEST_LIVE_DEVICE) {
+ // If TESTING, a deterministic seed is loaded when 'raw' is specified
+ ASSERT_REPORT_HAS(sig_2_input_1);
+ ASSERT_REPORT_HAS(sig_2_input_2);
+ ASSERT_REPORT_HAS(cmd_str(CMD_recid));
+ u_assert_str_eq(sig_device_1, sig_2_input_1);
+ u_assert_str_eq(sig_device_2, sig_2_input_2);
+ u_assert_str_eq(pubkey_device_1, PUBKEY_INPUT_TWO_1);
+ u_assert_str_eq(pubkey_device_2, PUBKEY_INPUT_TWO_2);
+#ifdef ECC_USE_SECP256K1_LIB
+ u_assert_str_eq(recid_device_1, RECID_01);
+ u_assert_str_eq(recid_device_2, RECID_01);
+#else
+ u_assert_str_eq(recid_device_1, RECID_EE);
+ u_assert_str_eq(recid_device_2, RECID_EE);
+#endif
+ } else {
+ // Random seed generated on device
+ ASSERT_REPORT_HAS_NOT(sig_2_input_1);
+ ASSERT_REPORT_HAS_NOT(sig_2_input_2);
+ ASSERT_REPORT_HAS(cmd_str(CMD_recid));
+ u_assert_str_not_eq(sig_device_1, sig_2_input_1);
+ u_assert_str_not_eq(sig_device_2, sig_2_input_2);
+ u_assert_str_not_eq(pubkey_device_1, PUBKEY_INPUT_TWO_1);
+ u_assert_str_not_eq(pubkey_device_2, PUBKEY_INPUT_TWO_2);
+ }
// test checkpub
+ api_format_send_cmd(cmd_str(CMD_xpub), KEYPATH_BASE, KEY_STANDARD);
+ hdnode_deserialize(api_read_value(CMD_xpub), &node);
+ snprintf(pubkey_device_1, sizeof(pubkey_device_1), "%s",
+ utils_uint8_to_hex(node.public_key, 33));
+ snprintf(pubkey_device_2, sizeof(pubkey_device_2), "%s",
+ utils_uint8_to_hex(node.public_key, 33));
+
api_format_send_cmd(cmd_str(CMD_sign), checkpub, KEY_STANDARD);
ASSERT_REPORT_HAS(cmd_str(CMD_echo));
if (!TEST_LIVE_DEVICE) {
@@ -2327,14 +2437,41 @@ static void tests_sign(void)
api_format_send_cmd(cmd_str(CMD_sign), "", KEY_STANDARD);
ASSERT_REPORT_HAS(cmd_str(CMD_sign));
- ASSERT_REPORT_HAS(check_sig_1);
- ASSERT_REPORT_HAS(check_sig_2);
- res = recover_public_key_verify_sig(check_sig_1, checkpub_msg_1, check_recid_1,
- check_pubkey);
- u_assert_int_eq(res, 0);
- res = recover_public_key_verify_sig(check_sig_2, checkpub_msg_2, check_recid_2,
- check_pubkey);
- u_assert_int_eq(res, 0);
+
+ memcpy(sig_device_1, api_read_array_value(CMD_sign, CMD_sig, 0), sizeof(sig_device_1));
+ memcpy(sig_device_2, api_read_array_value(CMD_sign, CMD_sig, 1), sizeof(sig_device_2));
+ memcpy(recid_device_1, api_read_array_value(CMD_sign, CMD_recid, 0),
+ sizeof(recid_device_1));
+ memcpy(recid_device_2, api_read_array_value(CMD_sign, CMD_recid, 1),
+ sizeof(recid_device_1));
+
+ u_assert_int_eq(0, recover_public_key_verify_sig(sig_device_1, HASH_INPUT_ONE,
+ recid_device_1, pubkey_device_1));
+ u_assert_int_eq(0, recover_public_key_verify_sig(sig_device_2, HASH_DEFAULT,
+ recid_device_2, pubkey_device_2));
+
+ if (!TEST_LIVE_DEVICE) {
+ // If TESTING, a deterministic seed is loaded when 'raw' is specified
+ ASSERT_REPORT_HAS(check_sig_1);
+ ASSERT_REPORT_HAS(check_sig_2);
+ u_assert_str_eq(sig_device_1, check_sig_1);
+ u_assert_str_eq(sig_device_2, check_sig_2);
+ u_assert_str_eq(pubkey_device_1, check_pubkey);
+#ifdef ECC_USE_SECP256K1_LIB
+ u_assert_str_eq(recid_device_1, RECID_01);
+ u_assert_str_eq(recid_device_2, RECID_01);
+#else
+ u_assert_str_eq(recid_device_1, RECID_EE);
+ u_assert_str_eq(recid_device_2, RECID_EE);
+#endif
+ } else {
+ // Random seed generated on device
+ ASSERT_REPORT_HAS_NOT(check_sig_1);
+ ASSERT_REPORT_HAS_NOT(check_sig_2);
+ u_assert_str_not_eq(sig_device_1, check_sig_1);
+ u_assert_str_not_eq(sig_device_2, check_sig_2);
+ u_assert_str_not_eq(pubkey_device_1, check_pubkey);
+ }
api_format_send_cmd(cmd_str(CMD_sign), checkpub_wrong_addr_len, KEY_STANDARD);
ASSERT_REPORT_HAS(flag_msg(DBB_ERR_SIGN_PUBKEY_LEN));
@@ -2360,7 +2497,7 @@ static void tests_sign(void)
u_assert(echo);
u_assert_str_has_not(echo, cmd_str(CMD_recid));
u_assert_str_has(echo, "_meta_data_");
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
u_assert_str_has(echo, cmd_str(CMD_pin));
free(echo);
}
@@ -2384,7 +2521,7 @@ static void tests_sign(void)
u_assert(echo);
u_assert_str_has_not(echo, cmd_str(CMD_recid));
u_assert_str_has(echo, "_meta_data_");
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
u_assert_str_has(echo, cmd_str(CMD_pin));
free(echo);
}
@@ -2404,7 +2541,7 @@ static void tests_sign(void)
u_assert(echo);
u_assert_str_has_not(echo, cmd_str(CMD_recid));
u_assert_str_has(echo, "_meta_data_");
- u_assert_str_has(echo, "m/44'/0'/0'/1/7");
+ u_assert_str_has(echo, KEYPATH_ONE);
u_assert_str_has(echo, cmd_str(CMD_pin));
free(echo);
} else {
@@ -2415,10 +2552,10 @@ static void tests_sign(void)
if (!TEST_LIVE_DEVICE) {
ASSERT_REPORT_HAS_NOT(attr_str(ATTR_error));
ASSERT_REPORT_HAS(cmd_str(CMD_sign));
- ASSERT_REPORT_HAS(hash_1_input);
+ ASSERT_REPORT_HAS(sig_1_input);
ASSERT_REPORT_HAS(cmd_str(CMD_recid));
- res = recover_public_key_verify_sig(hash_1_input, one_input_msg, recid_1_input,
- pubkey_1_input);
+ res = recover_public_key_verify_sig(sig_1_input, HASH_INPUT_ONE, RECID_01,
+ PUBKEY_INPUT_ONE);
u_assert_int_eq(res, 0);
} else {
pin_err_count++;
@@ -2437,7 +2574,7 @@ static void tests_sign(void)
u_assert(echo);
u_assert_str_has_not(echo, cmd_str(CMD_recid));
u_assert_str_has(echo, "_meta_data_");
- u_assert_str_has(echo, "m/44'/0'/0'/1/8");
+ u_assert_str_has(echo, KEYPATH_TWO);
free(echo);
}
@@ -2446,14 +2583,14 @@ static void tests_sign(void)
if (!TEST_LIVE_DEVICE) {
ASSERT_REPORT_HAS_NOT(attr_str(ATTR_error));
ASSERT_REPORT_HAS(cmd_str(CMD_sign));
- ASSERT_REPORT_HAS(hash_2_input_1);
- ASSERT_REPORT_HAS(hash_2_input_2);
+ ASSERT_REPORT_HAS(sig_2_input_1);
+ ASSERT_REPORT_HAS(sig_2_input_2);
ASSERT_REPORT_HAS(cmd_str(CMD_recid));
- res = recover_public_key_verify_sig(hash_2_input_1, two_input_msg_1, recid_2_input_1,
- pubkey_2_input_1);
+ res = recover_public_key_verify_sig(sig_2_input_1, HASH_INPUT_TWO_1, RECID_01,
+ PUBKEY_INPUT_TWO_1);
u_assert_int_eq(res, 0);
- res = recover_public_key_verify_sig(hash_2_input_2, two_input_msg_2, recid_2_input_2,
- pubkey_2_input_2);
+ res = recover_public_key_verify_sig(sig_2_input_2, HASH_INPUT_TWO_2, RECID_01,
+ PUBKEY_INPUT_TWO_2);
u_assert_int_eq(res, 0);
} else {
pin_err_count++;