Skip to content

Commit

Permalink
Improve import and export of optional block PB
Browse files Browse the repository at this point in the history
* During import of optional block PB, validate data field to consist
  only of printable ASCII characters as defined by ANSI X9.143:2021
  section 4.
* During export of optional block PB, generate random characters in the
  ranges of '0'-'9, 'A'-'Z' and 'a'-'Z'. Although optional block PB may
  carry any printable ASCII characters, characters outside the chosen
  ranges are problematic for HSM protocols that may use other printable
  ASCII characters as delimiters.
* Update tests to verify the length of optional block PB but not the
  data field which will now be random
  • Loading branch information
leonlynch committed May 2, 2023
1 parent d687e5e commit bd6e50d
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,15 @@ if(TARGET tr31-tool AND BUILD_TESTING)
)
set_tests_properties(tr31_tool_test16
PROPERTIES
PASS_REGULAR_EXPRESSION "^D0144B1AX00N0200IK141234567890123456PB0C00000000"
PASS_REGULAR_EXPRESSION "^D0144B1AX00N0200IK141234567890123456PB0C" # omit random optional block padding digits
)

add_test(NAME tr31_tool_test17
COMMAND tr31-tool --kbpk 4141414141414141414141414141414141414141414141414141414141414141 --export 1273671EA26AC29AFA4D1084127652A1 --export-header D0000B1AX00N0000 --export-opt-block-IK 1234567890123456
)
set_tests_properties(tr31_tool_test17
PROPERTIES
PASS_REGULAR_EXPRESSION "^D0144B1AX00N0200IK141234567890123456PB0C00000000"
PASS_REGULAR_EXPRESSION "^D0144B1AX00N0200IK141234567890123456PB0C" # omit random optional block padding digits
)

add_test(NAME tr31_tool_test18
Expand Down
78 changes: 73 additions & 5 deletions src/tr31.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ static int hex_to_int(const char* str, size_t str_len);
static void int_to_hex(unsigned int value, char* str, size_t str_len);
static int hex_to_bin(const char* hex, void* bin, size_t bin_len);
static int bin_to_hex(const void* bin, size_t bin_len, char* str, size_t str_len);
static int tr31_format_pa_to_bin(const char* buf, void* bin, size_t bin_len);
static int tr31_opt_block_parse(const struct tr31_opt_blk_t* opt_blk, size_t remaining_len, size_t* opt_block_len, struct tr31_opt_ctx_t* opt_ctx);
static int tr31_opt_block_export(const struct tr31_opt_ctx_t* opt_ctx, size_t remaining_len, size_t* opt_blk_len, struct tr31_opt_blk_t* opt_blk);
static int tr31_opt_block_export_PB(size_t pb_len, struct tr31_opt_blk_t* opt_blk);
static int tr31_tdes_decrypt_verify_variant_binding(struct tr31_ctx_t* ctx, const struct tr31_key_t* kbpk);
static int tr31_tdes_encrypt_sign_variant_binding(struct tr31_ctx_t* ctx, const struct tr31_key_t* kbpk);
static int tr31_tdes_decrypt_verify_derivation_binding(struct tr31_ctx_t* ctx, const struct tr31_key_t* kbpk);
Expand Down Expand Up @@ -225,6 +227,25 @@ static int bin_to_hex(const void* bin, size_t bin_len, char* hex, size_t hex_len
return 0;
}

static int tr31_format_pa_to_bin(const char* buf, void* bin, size_t bin_len)
{
while (bin_len--) {
uint8_t* ptr = bin;

// printable ASCII characters are in the range 0x20 to 0x7E
// see ANSI X9.143:2021, 4
if (*buf < 0x20 || *buf > 0x7E) {
return -1;
}
*ptr = *buf;

++buf;
++bin;
}

return 0;
}

const char* tr31_lib_version_string(void)
{
return TR31_LIB_VERSION_STRING;
Expand Down Expand Up @@ -1141,15 +1162,16 @@ int tr31_export(
}

// populate optional block PB
struct tr31_opt_blk_t* opt_blk = ptr;
opt_blk->id = htons(TR31_OPT_BLOCK_PB);
int_to_hex(pb_len, opt_blk->length, sizeof(opt_blk->length));
memset(opt_blk->data, '0', pb_len - 4);
r = tr31_opt_block_export_PB(pb_len, ptr);
if (r) {
// return error value as-is
return r;
}

// update optional block count in header
int_to_dec(ctx->opt_blocks_count + 1, header->opt_blocks_count, sizeof(header->opt_blocks_count));

// update total block length
// update total optional block length
opt_blk_len_total += pb_len;

// advance current pointer
Expand Down Expand Up @@ -1334,6 +1356,15 @@ static int tr31_opt_block_parse(
}
return 0;

case TR31_OPT_BLOCK_PB:
opt_ctx->data_length = (*opt_blk_len - 4);
opt_ctx->data = calloc(1, opt_ctx->data_length);
r = tr31_format_pa_to_bin(opt_blk->data, opt_ctx->data, opt_ctx->data_length);
if (r) {
return TR31_ERROR_INVALID_OPTIONAL_BLOCK_DATA;
}
return 0;

// copy all other optional blocks, including proprietary ones, verbatim
default:
opt_ctx->data_length = (*opt_blk_len - 4);
Expand Down Expand Up @@ -1410,6 +1441,43 @@ static int tr31_opt_block_export(
}
}

static int tr31_opt_block_export_PB(size_t pb_len, struct tr31_opt_blk_t* opt_blk)
{
opt_blk->id = htons(TR31_OPT_BLOCK_PB);
int_to_hex(pb_len, opt_blk->length, sizeof(opt_blk->length));

// populate with random data and then transpose to the required range
crypto_rand(opt_blk->data, pb_len - 4);

for (size_t i = 0; i < pb_len - 4; ++i) {
// although optional block PB may contain printable ASCII characters in
// the range 0x20 to 0x7E, characters outside the ranges of '0'-'9',
// 'A'-'Z' and 'a'-'Z' are problematic when using HSM protocols that
// may use other printable ASCII characters as delimiters

// use unsigned integers for sanity but cast to uint8_t to fix negative
// char values without setting high order bits due to 2s complement
unsigned int tmp = (uint8_t)opt_blk->data[i];

// clamp range to [0 - 61] for 62 possible characters
tmp = (tmp * 61) / 0xFF;

// split range into ranges of '0'-'9', 'A'-'Z' and 'a'-'Z'
if (tmp < 10) {
opt_blk->data[i] = tmp + '0'; // '0'-'9'
} else if (tmp < 36) {
opt_blk->data[i] = tmp - 10 + 'A'; // 'A'-'Z'
} else if (tmp < 62) {
opt_blk->data[i] = tmp - 36 + 'a'; // 'a'-'Z'
} else {
// This should never happen
return -1;
}
}

return 0;
}

static int tr31_tdes_decrypt_verify_variant_binding(struct tr31_ctx_t* ctx, const struct tr31_key_t* kbpk)
{
int r;
Expand Down
2 changes: 1 addition & 1 deletion test/tr31_export_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ static const struct tr31_key_t test5_key = {
.length = sizeof(test5_key_raw),
.data = (void*)test5_key_raw,
};
static const char test5_tr31_header_verify[] = "D0128M7HC12N0200HM0621PB0A000000";
static const char test5_tr31_header_verify[] = "D0128M7HC12N0200HM0621PB0A"; // omit random optional block padding digits
static const size_t test5_tr31_length_verify =
16 /* header */
+ 6 /* opt block HM */ + 10 /* opt block PB */
Expand Down

0 comments on commit bd6e50d

Please sign in to comment.