diff --git a/src/constants.h b/src/constants.h index 151d691..1189a82 100644 --- a/src/constants.h +++ b/src/constants.h @@ -68,3 +68,4 @@ #define MESSAGE_SIGNING_KEY "PersonalMessageSigningHash" #define MAX_OUTPUT_COUNT 2 +#define SCRIPT_PUBLIC_KEY_BUFFER_LEN 40 diff --git a/src/transaction/types.h b/src/transaction/types.h index 49eaed2..7b89211 100644 --- a/src/transaction/types.h +++ b/src/transaction/types.h @@ -77,7 +77,7 @@ typedef struct { typedef struct { uint64_t value; - uint8_t script_public_key[40]; // In hex: 20 + public_key_hex + ac (34/35 bytes total) + uint8_t script_public_key[SCRIPT_PUBLIC_KEY_BUFFER_LEN]; // In hex: 20 + public_key_hex + ac (34/35 bytes total) } transaction_output_t; typedef struct { diff --git a/src/transaction/utils.c b/src/transaction/utils.c index 4a56eff..4dca6f0 100644 --- a/src/transaction/utils.c +++ b/src/transaction/utils.c @@ -38,18 +38,33 @@ bool transaction_utils_check_encoding(const uint8_t* memo, uint64_t memo_len) { return true; } -void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_public_key) { +bool script_public_key_to_address(uint8_t* out_address, size_t out_len, uint8_t* in_script_public_key, size_t script_len) { uint8_t public_key[64] = {0}; + + // script public keys are always at least 32 bytes. We'll check this again + // once we know more about the script + if (script_len < 32) { + return false; + } + // public script keys begin with the length, followed by the amount of data size_t first_byte = (size_t) in_script_public_key[0]; address_type_e type = SCHNORR; size_t address_len = SCHNORR_ADDRESS_LEN; if (first_byte == 0xaa) { + // In this case, script len must be at least 35 chars + if (script_len < 35) { + return false; + } type = P2SH; address_len = SCHNORR_ADDRESS_LEN; memmove(public_key, in_script_public_key + 2, 32); } else if (first_byte == 0x21) { + // In this case, script len must be at least 35 chars + if (script_len < 35) { + return false; + } // We're dealing with ECDSA instead: type = ECDSA; address_len = ECDSA_ADDRESS_LEN; @@ -62,10 +77,19 @@ void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_publi // Set the correct parity for the y-coord memset(public_key + 32, parity, 32); } else { + // In this case, script len must be at least 35 chars + if (script_len < 34) { + return false; + } memmove(public_key, in_script_public_key + 1, 32); } - address_from_pubkey(public_key, type, out_address, address_len); + // We need space to write address_len + if (out_len < address_len) { + return false; + } + + return address_from_pubkey(public_key, type, out_address, address_len); } uint64_t calc_fees(transaction_input_t* inputs, diff --git a/src/transaction/utils.h b/src/transaction/utils.h index ccc81aa..3cf88df 100644 --- a/src/transaction/utils.h +++ b/src/transaction/utils.h @@ -46,10 +46,12 @@ bool transaction_utils_check_encoding(const uint8_t* memo, uint64_t memo_len); * * @param[out] out_address * Pointer to the buffer to write the address to + * @param[in] out_len length of output buffer * @param[in] in_script_public_key * Pointer to the buffer to read script_public_key from + * @param[in] script_len length of script output buffer */ -void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_public_key); +void script_public_key_to_address(uint8_t* out_address, size_t out_len, uint8_t* in_script_public_key, size_t script_len); /** * Calculate the fees by checking the difference between inputs and outputs diff --git a/src/ui/bagl_display.c b/src/ui/bagl_display.c index c13fcf7..30e63e9 100644 --- a/src/ui/bagl_display.c +++ b/src/ui/bagl_display.c @@ -216,7 +216,9 @@ int ui_display_transaction() { uint8_t address[ECDSA_ADDRESS_LEN] = {0}; script_public_key_to_address(address, - G_context.tx_info.transaction.tx_outputs[0].script_public_key); + sizeof(address), + G_context.tx_info.transaction.tx_outputs[0].script_public_key, + SCRIPT_PUBLIC_KEY_BUFFER_LEN); snprintf(g_address, sizeof(g_address), "%.*s", ECDSA_ADDRESS_LEN, address); g_validate_callback = &ui_action_validate_transaction; diff --git a/src/ui/nbgl_display_transaction.c b/src/ui/nbgl_display_transaction.c index 36e8083..bbd925a 100755 --- a/src/ui/nbgl_display_transaction.c +++ b/src/ui/nbgl_display_transaction.c @@ -141,7 +141,9 @@ int ui_display_transaction() { uint8_t address[ECDSA_ADDRESS_LEN] = {0}; script_public_key_to_address(address, - G_context.tx_info.transaction.tx_outputs[0].script_public_key); + sizeof(address), + G_context.tx_info.transaction.tx_outputs[0].script_public_key, + SCRIPT_PUBLIC_KEY_BUFFER_LEN); snprintf(g_address, sizeof(g_address), "%.*s", ECDSA_ADDRESS_LEN, address); // Start review diff --git a/unit-tests/test_tx_utils.c b/unit-tests/test_tx_utils.c index 0ef0b46..09b22b2 100644 --- a/unit-tests/test_tx_utils.c +++ b/unit-tests/test_tx_utils.c @@ -57,7 +57,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t schnorr_address[68] = {0}; - script_public_key_to_address(schnorr_address, schnorr_spk); + script_public_key_to_address(schnorr_address, sizeof(schnorr_address), schnorr_spk, sizeof(schnorr_spk)); assert_string_equal((char *) schnorr_address, "kaspa:qrazhptjkcvrv23xz2xm8z8sfmg6jhxvmrscn7wph4k9we5tzxedwfxf0v6f8"); @@ -70,7 +70,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t p2sh_address[68] = {0}; - script_public_key_to_address(p2sh_address, p2sh_spk); + script_public_key_to_address(p2sh_address, sizeof(p2sh_address), p2sh_spk, sizeof(p2sh_spk)); assert_string_equal((char *) p2sh_address, "kaspa:precqv0krj3r6uyyfa36ga7s0u9jct0v4wg8ctsfde2gkrsgwgw8jgxfzfc98"); @@ -85,7 +85,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t ecdsa_even_address[70] = {0}; - script_public_key_to_address(ecdsa_even_address, ecdsa_even_spk); + script_public_key_to_address(ecdsa_even_address, sizeof(ecdsa_even_address), ecdsa_even_spk, sizeof(ecdsa_even_spk)); assert_string_equal((char *) ecdsa_even_address, "kaspa:qypdtlw845g6vhgtheug9lpahjgmtpsarqkueeul0sd7t07npfnhe4s7fd82n0v"); @@ -100,7 +100,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t ecdsa_odd_address[70] = {0}; - script_public_key_to_address(ecdsa_odd_address, ecdsa_odd_spk); + script_public_key_to_address(ecdsa_odd_address, sizeof(ecdsa_odd_address), ecdsa_odd_spk, sizeof(ecdsa_odd_spk)); assert_string_equal((char *) ecdsa_odd_address, "kaspa:qyp7xyqdshh6aylqct7x2je0pse4snep8glallgz8jppyaajz7y7qeq4x79fq4z"); }