Skip to content

Commit

Permalink
Implement key algorithms H, I and J for ISO 20038
Browse files Browse the repository at this point in the history
Note that ANSI X9.143 and ISO 20038 share key algorithm H but use it for
slightly different purposes. In both cases it indicates HMAC, but ISO
20038 also associates the HMAC digest with the specific key algorithm
value, while ANSI X9.143 requires optional block HM to specify the HMAC
digest. This distinction requires tr31_key_algorithm_get_desc() to take
the TR-31 context object as an optional parameter to consider the
optional blocks when determining the description for key algorithm H.
  • Loading branch information
leonlynch committed Nov 25, 2023
1 parent 720c683 commit 5ec2582
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 28 deletions.
32 changes: 32 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ if(TARGET tr31-tool AND BUILD_TESTING)
PASS_REGULAR_EXPRESSION ${tr31_tool_test32_regex}
)

# test HMAC key for ANSI X9.143
add_test(NAME tr31_tool_test33
COMMAND tr31-tool --kbpk 88E1AB2A2E3DD38C1FA039A536500CC8A87AB9D62DC92C01058FA79F44657DE6 --export 3F419E1CB7079442AA37474C2EFBF8B8 --export-header D0000M7HG00N0000 --export-opt-block-HM 21
)
Expand All @@ -580,6 +581,7 @@ if(TARGET tr31-tool AND BUILD_TESTING)
PASS_REGULAR_EXPRESSION "^D0128M7HG00N0200HM0621PB0A"
)

# test HMAC key for ANSI X9.143
add_test(NAME tr31_tool_test34
COMMAND tr31-tool --kbpk 88E1AB2A2E3DD38C1FA039A536500CC8A87AB9D62DC92C01058FA79F44657DE6 --import D0128M7HG00N0200HM0621PB0A5V5E8F634619D84C6040EAC3C1CA6A5FE60C5292E778FC95ABBECE94C3AD060C5F4C128796A100FF035A4BFB16C36449550131
)
Expand Down Expand Up @@ -837,4 +839,34 @@ if(TARGET tr31-tool AND BUILD_TESTING)
PROPERTIES
PASS_REGULAR_EXPRESSION "^B0096B1TX00N0020[A-Z0-9]*[\r\n]"
)

# test HMAC key ISO 20038
add_test(NAME tr31_tool_test51
COMMAND tr31-tool --kbpk 88E1AB2A2E3DD38C1FA039A536500CC8A87AB9D62DC92C01058FA79F44657DE6 --export 3F419E1CB7079442AA37474C2EFBF8B8 --export-header D0000M7JG00N0000
)
set_tests_properties(tr31_tool_test51
PROPERTIES
PASS_REGULAR_EXPRESSION "^D0112M7JG00N0000"
)

# test HMAC key ISO 20038
add_test(NAME tr31_tool_test52
COMMAND tr31-tool --kbpk 88E1AB2A2E3DD38C1FA039A536500CC8A87AB9D62DC92C01058FA79F44657DE6 --import D0112M7HG00N00000AD79E1883C16BCF2C980A087A348173A8F1326B9B1F6239738773BAA348FBFD0C0EC5AFD14A1A4BE2C4444215F2B823
)
string(CONCAT tr31_tool_test52_regex
"^Key block format version: D[\r\n]"
"Key block length: 112 bytes[\r\n]"
"Key usage: \\[M7\\] HMAC Key[\r\n]"
"Key algorithm: \\[H\\] HMAC-SHA-1 \\(ISO 20038\\)[\r\n]"
"Key mode of use: \\[G\\] MAC Generate Only[\r\n]"
"Key version: Unused[\r\n]"
"Key exportability: \\[N\\] Not exportable[\r\n]"
"Key context: \\[0\\] Determined by wrapping key[\r\n]"
"Key length: 16[\r\n]"
"Key value: 3F419E1CB7079442AA37474C2EFBF8B8[\r\n]"
)
set_tests_properties(tr31_tool_test52
PROPERTIES
PASS_REGULAR_EXPRESSION ${tr31_tool_test52_regex}
)
endif()
29 changes: 13 additions & 16 deletions src/tr31-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ static int do_tr31_import(const struct tr31_tool_options_t* options)
);
printf("Key algorithm: [%c] %s\n",
tr31_ctx.key.algorithm,
tr31_key_algorithm_get_desc(tr31_ctx.key.algorithm)
tr31_key_algorithm_get_desc(&tr31_ctx, tr31_ctx.key.algorithm)
);
printf("Key mode of use: [%c] %s\n",
tr31_ctx.key.mode_of_use,
Expand Down Expand Up @@ -1211,7 +1211,7 @@ static int populate_opt_blocks(const struct tr31_tool_options_t* options, struct
if (tr31_ctx->key.usage != TR31_KEY_USAGE_HMAC ||
tr31_ctx->key.algorithm != TR31_KEY_ALGORITHM_HMAC
) {
fprintf(stderr, "Export optional block HM is only allowed for HMAC keys (key usage M7, algorithm H)\n");
fprintf(stderr, "Export optional block HM is only allowed for ANSI X9.143 HMAC keys (key usage M7, algorithm H)\n");
return 1;
}

Expand All @@ -1220,20 +1220,17 @@ static int populate_opt_blocks(const struct tr31_tool_options_t* options, struct
fprintf(stderr, "Failed to add optional block HM; error %d: %s\n", r, tr31_get_error_string(r));
return 1;
}
} else if (tr31_ctx->key.usage == TR31_KEY_USAGE_HMAC ||
tr31_ctx->key.algorithm == TR31_KEY_ALGORITHM_HMAC
) {
// look for existing optional block HM because it may have been
// provided by --export-header
bool opt_block_HM_found = false;
for (size_t i = 0; i < tr31_ctx->opt_blocks_count; ++i) {
if (tr31_ctx->opt_blocks[i].id == TR31_OPT_BLOCK_HM) {
opt_block_HM_found = true;
break;
}
}
if (!opt_block_HM_found) {
fprintf(stderr, "HMAC keys (key usage M7, algorithm H) must specify the hash algorithm using optional block HM (--export-opt-block-HM)\n");
}

// look for existing optional block HM because it may have been
// provided by --export-header
if (tr31_opt_block_find(tr31_ctx, TR31_OPT_BLOCK_HM)) {
// disallow usage of optional block HM for non-HMAC key usage as well
// as for key algorithms I and J (because ISO 20038)
if (tr31_ctx->key.usage != TR31_KEY_USAGE_HMAC ||
tr31_ctx->key.algorithm != TR31_KEY_ALGORITHM_HMAC
) {
fprintf(stderr, "Export optional block HM is only allowed for ANSI X9.143 HMAC keys (key usage M7, algorithm H)\n");
return 1;
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/tr31.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@ int tr31_key_init(
case TR31_KEY_ALGORITHM_DES:
case TR31_KEY_ALGORITHM_EC:
case TR31_KEY_ALGORITHM_HMAC:
//case TR31_KEY_ALGORITHM_HMAC_SHA1: // same value as TR31_KEY_ALGORITHM_HMAC
case TR31_KEY_ALGORITHM_HMAC_SHA2:
case TR31_KEY_ALGORITHM_HMAC_SHA3:
case TR31_KEY_ALGORITHM_RSA:
case TR31_KEY_ALGORITHM_DSA:
case TR31_KEY_ALGORITHM_TDES:
Expand Down
7 changes: 5 additions & 2 deletions src/tr31.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,14 @@ enum tr31_version_t {
#define TR31_KEY_USAGE_PVK_X9_132_ALG_2 (0x5634) ///< Key Usage V4: PIN Verification Key (ANSI X9.132 algorithm 2)
#define TR31_KEY_USAGE_PVK_X9_132_ALG_3 (0x5635) ///< Key Usage V5: PIN Verification Key (ANSI X9.132 algorithm 3)

// TR-31 algorithm (see ANSI X9.143:2021, 6.3.2, table 3)
// TR-31 algorithm (see ANSI X9.143:2021, 6.3.2, table 3 and ISO 20038:2017, Annex A.2.4, table A.4)
#define TR31_KEY_ALGORITHM_AES ('A') ///< Key Algorithm A: AES
#define TR31_KEY_ALGORITHM_DES ('D') ///< Key Algorithm D: DES
#define TR31_KEY_ALGORITHM_EC ('E') ///< Key Algorithm E: Elliptic Curve
#define TR31_KEY_ALGORITHM_HMAC ('H') ///< Key Algorithm H: HMAC
#define TR31_KEY_ALGORITHM_HMAC ('H') ///< Key Algorithm H for ANSI X9.143: HMAC
#define TR31_KEY_ALGORITHM_HMAC_SHA1 ('H') ///< Key Algorithm H for ISO 20038: HMAC-SHA1
#define TR31_KEY_ALGORITHM_HMAC_SHA2 ('I') ///< Key Algorithm I for ISO 20038: HMAC-SHA2
#define TR31_KEY_ALGORITHM_HMAC_SHA3 ('J') ///< Key Algorithm J for ISO 20038: HMAC-SHA3
#define TR31_KEY_ALGORITHM_RSA ('R') ///< Key Algorithm R: RSA
#define TR31_KEY_ALGORITHM_DSA ('S') ///< Key Algorithm S: DSA
#define TR31_KEY_ALGORITHM_TDES ('T') ///< Key Algorithm T: Triple DES
Expand Down
26 changes: 18 additions & 8 deletions src/tr31_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,27 @@ const char* tr31_key_usage_get_desc(unsigned int usage)
return "Unknown key usage value";
}

const char* tr31_key_algorithm_get_desc(unsigned int algorithm)
const char* tr31_key_algorithm_get_desc(const struct tr31_ctx_t* ctx, unsigned int algorithm)
{
// See ANSI X9.143:2021, 6.3.2, table 3
// See ISO 20038:2017, Annex A.2.4, table A.4
switch (algorithm) {
case TR31_KEY_ALGORITHM_AES: return "AES";
case TR31_KEY_ALGORITHM_DES: return "DES";
case TR31_KEY_ALGORITHM_EC: return "Elliptic Curve";
case TR31_KEY_ALGORITHM_HMAC: return "HMAC";
case TR31_KEY_ALGORITHM_RSA: return "RSA";
case TR31_KEY_ALGORITHM_DSA: return "DSA";
case TR31_KEY_ALGORITHM_TDES: return "TDES";
case TR31_KEY_ALGORITHM_AES: return "AES";
case TR31_KEY_ALGORITHM_DES: return "DES";
case TR31_KEY_ALGORITHM_EC: return "Elliptic Curve";
case TR31_KEY_ALGORITHM_HMAC:
if (tr31_opt_block_find((struct tr31_ctx_t*)ctx, TR31_OPT_BLOCK_HM)) {
// ANSI X9.143 requires optional block HM for key algorithm HMAC
return "HMAC";
} else {
// ISO 20038 associates the HMAC digest to the key algorithm
return "HMAC-SHA-1 (ISO 20038)";
}
case TR31_KEY_ALGORITHM_HMAC_SHA2: return "HMAC-SHA-2 (ISO 20038)";
case TR31_KEY_ALGORITHM_HMAC_SHA3: return "HMAC-SHA-3 (ISO 20038)";
case TR31_KEY_ALGORITHM_RSA: return "RSA";
case TR31_KEY_ALGORITHM_DSA: return "DSA";
case TR31_KEY_ALGORITHM_TDES: return "TDES";
}

return "Unknown key algorithm value";
Expand Down
9 changes: 7 additions & 2 deletions src/tr31_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
__BEGIN_DECLS

// Forward declarations
struct tr31_ctx_t;
struct tr31_opt_ctx_t;

/**
Expand All @@ -49,12 +50,16 @@ const char* tr31_key_usage_get_ascii(unsigned int usage, char* ascii, size_t asc
const char* tr31_key_usage_get_desc(unsigned int usage);

/**
* Retrieve human readable description associated with key algorithm value
* Retrieve human readable description associated with key algorithm value.
*
* If the TR-31 context object is provided, this function may consider
* the optional blocks when determining the description.
*
* @param ctx TR-31 context object. Optional and may be NULL.
* @param algorithm Key algorithm value
* @return Pointer to null-terminated string. Do not free.
*/
const char* tr31_key_algorithm_get_desc(unsigned int algorithm);
const char* tr31_key_algorithm_get_desc(const struct tr31_ctx_t* ctx, unsigned int algorithm);

/**
* Retrieve human readable description associated with key mode of use value
Expand Down

0 comments on commit 5ec2582

Please sign in to comment.