From fb6b3b5ebc995ad04d47f940dbb2bb5c4eb27ee5 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Fri, 13 Oct 2023 14:28:37 +0200 Subject: [PATCH] Add a field for signature format selection in CHECK_TRANSACTION_SIGNATURE command on NG flows --- src/check_tx_signature.c | 49 ++++++++++++++----- src/globals.h | 3 ++ .../apps/exchange_transaction_builder.py | 12 +++-- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/check_tx_signature.c b/src/check_tx_signature.c index 43f1e869..ee9a1f03 100644 --- a/src/check_tx_signature.c +++ b/src/check_tx_signature.c @@ -22,33 +22,60 @@ int check_tx_signature(const command_t *cmd) { // signature uint8_t der_sig[DER_HEADER_SIZE + MAX_DER_INT_SIZE(R_S_INT_SIZE) * 2]; buf_t signature; + bool signature_is_in_R_S_format; + uint16_t offset = 0; - if (cmd->subcommand == SWAP || cmd->subcommand == FUND) { + if (cmd->subcommand == SWAP) { + signature_is_in_R_S_format = false; + } else if (cmd->subcommand == FUND) { + signature_is_in_R_S_format = false; + } else if (cmd->subcommand == SELL) { + signature_is_in_R_S_format = true; + } else { + uint8_t sig_format; + if (!pop_uint8_from_buffer(cmd->data.bytes, cmd->data.size, &sig_format, &offset)) { + PRINTF("Failed to read signature format selector\n"); + return reply_error(INCORRECT_COMMAND_DATA); + } + if (sig_format == DER_FORMAT_SIGNATURE) { + signature_is_in_R_S_format = false; + } else if (sig_format == R_S_FORMAT_SIGNATURE) { + signature_is_in_R_S_format = true; + } else { + PRINTF("Error: Incorrect signature format selector %d\n", sig_format); + return reply_error(INCORRECT_COMMAND_DATA); + } + } + + buf_t remaining_input; + remaining_input.size = cmd->data.size - offset; + remaining_input.bytes = cmd->data.bytes + offset; + if (!signature_is_in_R_S_format) { // We received the signature in DER format, just perform some sanity checks - if (cmd->data.size < MIN_DER_SIGNATURE_LENGTH || - cmd->data.size > MAX_DER_SIGNATURE_LENGTH) { + if (remaining_input.size < MIN_DER_SIGNATURE_LENGTH || + remaining_input.size > MAX_DER_SIGNATURE_LENGTH) { PRINTF("Error: Input buffer length don't correspond to DER length\n"); return reply_error(INCORRECT_COMMAND_DATA); } - uint16_t payload_size = cmd->data.bytes[DER_OFFSET_LENGTH]; - if (payload_size + DER_HEADER_SIZE != cmd->data.size) { + uint16_t payload_size = remaining_input.bytes[DER_OFFSET_LENGTH]; + if (payload_size + DER_HEADER_SIZE != remaining_input.size) { PRINTF("DER signature header advertizes %d bytes, we received %d\n", payload_size, - cmd->data.size); + remaining_input.size); return reply_error(INCORRECT_COMMAND_DATA); } - signature.size = cmd->data.size; - signature.bytes = cmd->data.bytes; + signature.size = remaining_input.size; + signature.bytes = remaining_input.bytes; } else { // We received the signature in (R,S) format, perform some sanity checks then encode in DER - if (cmd->data.size != R_S_INT_SIZE * 2) { + if (remaining_input.size != R_S_INT_SIZE * 2) { PRINTF("Error: Input buffer length don't correspond to (R, S) length\n"); return reply_error(INCORRECT_COMMAND_DATA); } - uint8_t *r = cmd->data.bytes; - uint8_t *s = cmd->data.bytes + R_S_INT_SIZE; + uint8_t *r = remaining_input.bytes; + uint8_t *s = remaining_input.bytes + R_S_INT_SIZE; size_t der_r_len = asn1_get_encoded_integer_size(r, R_S_INT_SIZE); size_t der_s_len = asn1_get_encoded_integer_size(s, R_S_INT_SIZE); size_t size = der_r_len + der_s_len + DER_HEADER_SIZE; diff --git a/src/globals.h b/src/globals.h index 848091bd..afd3a14c 100644 --- a/src/globals.h +++ b/src/globals.h @@ -19,6 +19,9 @@ #define ENCODING_BYTES_ARRAY 0x00 #define ENCODING_BASE_64_URL 0x01 +#define DER_FORMAT_SIGNATURE 0x00 +#define R_S_FORMAT_SIGNATURE 0x01 + #define TICKER_MIN_SIZE_B 2 #define TICKER_MAX_SIZE_B 9 #define APPNAME_MIN_SIZE_B 3 diff --git a/test/python/apps/exchange_transaction_builder.py b/test/python/apps/exchange_transaction_builder.py index f9372fc2..c2fe15e5 100644 --- a/test/python/apps/exchange_transaction_builder.py +++ b/test/python/apps/exchange_transaction_builder.py @@ -71,8 +71,8 @@ def encode_payload(self, raw_transaction: bytes, url_encode: bool) -> bytes: else: return raw_transaction - def encode_signature(self, signature_to_encode: bytes) -> bytes: - if self.signature_encoding == SignatureEncoding.PLAIN_R_S: + def encode_signature(self, signature_to_encode: bytes, r_s_encode: bool) -> bytes: + if r_s_encode == True: r, s = decode_dss_signature(signature_to_encode) signature_to_encode = r.to_bytes(32, "big") + s.to_bytes(32, "big") return signature_to_encode @@ -170,7 +170,13 @@ def encode_transaction_signature(subcommand: SubCommand, signer: SigningAuthorit subcommand_specs = SUBCOMMAND_TO_SPECS[subcommand] formated_transaction = subcommand_specs.format_transaction(tx) signed_transaction = signer.sign(formated_transaction) - return subcommand_specs.encode_signature(signed_transaction) + r_s_encode = True if (subcommand_specs.signature_encoding == SignatureEncoding.PLAIN_R_S) else False + encoded_signature = subcommand_specs.encode_signature(signed_transaction, r_s_encode) + + if subcommand == SubCommand.SWAP_NG or subcommand == SubCommand.SELL_NG or subcommand == SubCommand.FUND_NG: + rs_encode = int.to_bytes(1 if r_s_encode == True else False, 1, byteorder='big') + encoded_signature = rs_encode + encoded_signature + return encoded_signature def craft_transaction(subcommand: SubCommand, transaction: bytes, fees: int) -> bytes: subcommand_specs = SUBCOMMAND_TO_SPECS[subcommand]