diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index 2921278b3..570d9dba2 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -358,6 +358,11 @@ #error "MBEDTLS_LMS_C requires MBEDTLS_PSA_CRYPTO_C" #endif +#if defined(MBEDTLS_LMS_PRIVATE) && \ + ( !defined(MBEDTLS_LMS_C) ) +#error "MBEDTLS_LMS_PRIVATE requires MBEDTLS_LMS_C" +#endif + #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \ ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) #error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites" diff --git a/include/mbedtls/lms.h b/include/mbedtls/lms.h index c463b2abb..65b1b7e0e 100644 --- a/include/mbedtls/lms.h +++ b/include/mbedtls/lms.h @@ -106,6 +106,7 @@ typedef struct { } mbedtls_lms_public_t; +#ifdef MBEDTLS_LMS_PRIVATE /** LMS private context structure. * * A LMS private key is a set of LMOTS private keys, an index to the next usable @@ -133,6 +134,7 @@ typedef struct { unsigned char MBEDTLS_PRIVATE(have_private_key); /*!< Whether the context contains a private key. Boolean values only. */ } mbedtls_lms_private_t; +#endif /* MBEDTLS_LMS_PRIVATE */ /** * \brief This function initializes an LMS public context @@ -196,6 +198,7 @@ int mbedtls_lms_verify( const mbedtls_lms_public_t *ctx, const unsigned char *msg, size_t msg_size, const unsigned char *sig, size_t sig_size ); +#ifdef MBEDTLS_LMS_PRIVATE /** * \brief This function initializes an LMS private context * @@ -328,6 +331,7 @@ int mbedtls_lms_sign( mbedtls_lms_private_t *ctx, int (*f_rng)(void *, unsigned char *, size_t), void* p_rng, unsigned char *msg, unsigned int msg_size, unsigned char *sig, size_t sig_size, size_t *sig_len); +#endif /* MBEDTLS_LMS_PRIVATE */ #ifdef __cplusplus } diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h index 8c833b1cf..c0caf7562 100644 --- a/include/mbedtls/mbedtls_config.h +++ b/include/mbedtls/mbedtls_config.h @@ -2469,12 +2469,24 @@ * Module: library/lms.c * Caller: * - * Requires: MBEDTLS_MD_C + * Requires: MBEDTLS_PSA_CRYPTO_C * - * Uncomment to enable the LMS signature algorithm. + * Uncomment to enable the LMS verification algorithm and public key operations. */ #define MBEDTLS_LMS_C +/** + * \def MBEDTLS_LMS_PRIVATE + * + * Enable LMS private-key operations and signing code. Functions enabled by this + * option are experimental, and should not be used in production. + * + * Requires: MBEDTLS_LMS_C + * + * Uncomment to enable the LMS signature algorithm and private key operations. + */ +// #define MBEDTLS_LMS_PRIVATE + /** * \def MBEDTLS_NIST_KW_C * diff --git a/library/lmots.c b/library/lmots.c index d92d38525..bf6644935 100644 --- a/library/lmots.c +++ b/library/lmots.c @@ -455,6 +455,8 @@ int mbedtls_lmots_verify( mbedtls_lmots_public_t *ctx, const unsigned char *msg, return( 0 ); } +#ifdef MBEDTLS_LMS_PRIVATE + void mbedtls_lmots_init_private( mbedtls_lmots_private_t *ctx ) { mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_private_t ) ) ; @@ -716,4 +718,5 @@ int mbedtls_lmots_sign( mbedtls_lmots_private_t *ctx, return( 0 ); } +#endif /* MBEDTLS_LMS_PRIVATE */ #endif /* MBEDTLS_LMS_C */ diff --git a/library/lmots.h b/library/lmots.h index ca7d4bf34..e784bf586 100644 --- a/library/lmots.h +++ b/library/lmots.h @@ -101,6 +101,7 @@ typedef struct { Boolean values only. */ } mbedtls_lmots_public_t; +#ifdef MBEDTLS_LMS_PRIVATE /** LMOTS private context structure. * * A LMOTS private key is one hash output for each of digit of the digest + @@ -124,6 +125,7 @@ typedef struct { unsigned char MBEDTLS_PRIVATE(have_private_key); /*!< Whether the context contains a private key. Boolean values only. */ } mbedtls_lmots_private_t; +#endif /* MBEDTLS_LMS_PRIVATE */ /** * \brief This function converts an unsigned int into a @@ -256,6 +258,8 @@ int mbedtls_lmots_verify( mbedtls_lmots_public_t *ctx, const unsigned char *msg, size_t msg_size, const unsigned char *sig, size_t sig_size ); +#ifdef MBEDTLS_LMS_PRIVATE + /** * \brief This function initializes a private LMOTS context * @@ -375,6 +379,7 @@ int mbedtls_lmots_sign( mbedtls_lmots_private_t *ctx, void *p_rng, const unsigned char *msg, size_t msg_size, unsigned char *sig, size_t sig_size, size_t* sig_len ); +#endif /* MBEDTLS_LMS_PRIVATE */ #ifdef __cplusplus } diff --git a/library/lms.c b/library/lms.c index 44d4c7902..cb56cb31c 100644 --- a/library/lms.c +++ b/library/lms.c @@ -177,74 +177,6 @@ exit: return ret; } -static int calculate_merkle_tree( mbedtls_lms_private_t *ctx, - unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES] ) -{ - unsigned int priv_key_idx; - unsigned int r_node_idx; - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - /* First create the leaf nodes, in ascending order */ - for( priv_key_idx = 0; priv_key_idx < MERKLE_TREE_INTERNAL_NODE_AM; - priv_key_idx++ ) - { - r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM + priv_key_idx; - - ret = create_merkle_leaf_value( - ctx->params.I_key_identifier, - ctx->ots_public_keys[priv_key_idx].public_key, - r_node_idx, tree[r_node_idx] ); - if( ret ) - { - return( ret ); - } - } - - /* Then the internal nodes, in reverse order so that we can guarantee the - * parent has been created */ - for( r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM - 1; r_node_idx > 0; - r_node_idx-- ) - { - ret = create_merkle_internal_value( - ctx->params.I_key_identifier, - tree[(r_node_idx * 2)], tree[(r_node_idx * 2 + 1)], r_node_idx, tree[r_node_idx] ); - if( ret ) - { - return( ret ); - } - } - - return( 0 ); -} - -static int get_merkle_path( mbedtls_lms_private_t *ctx, - unsigned int leaf_node_id, - unsigned char path[MBEDTLS_LMS_H_TREE_HEIGHT][MBEDTLS_LMS_M_NODE_BYTES] ) -{ - unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES]; - unsigned int curr_node_id = leaf_node_id; - unsigned int adjacent_node_id; - unsigned int height; - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - ret = calculate_merkle_tree( ctx, tree); - if( ret ) - { - return( ret ); - } - - for( height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT; height++ ) - { - adjacent_node_id = curr_node_id ^ 1; - - memcpy( &path[height], &tree[adjacent_node_id], MBEDTLS_LMOTS_N_HASH_LEN ); - - curr_node_id >>=1; - } - - return( 0 ); -} - void mbedtls_lms_init_public( mbedtls_lms_public_t *ctx ) { mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) ) ; @@ -409,6 +341,76 @@ int mbedtls_lms_verify( const mbedtls_lms_public_t *ctx, return( 0 ); } +#ifdef MBEDTLS_LMS_PRIVATE + +static int calculate_merkle_tree( mbedtls_lms_private_t *ctx, + unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES] ) +{ + unsigned int priv_key_idx; + unsigned int r_node_idx; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + /* First create the leaf nodes, in ascending order */ + for( priv_key_idx = 0; priv_key_idx < MERKLE_TREE_INTERNAL_NODE_AM; + priv_key_idx++ ) + { + r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM + priv_key_idx; + + ret = create_merkle_leaf_value( + ctx->params.I_key_identifier, + ctx->ots_public_keys[priv_key_idx].public_key, + r_node_idx, tree[r_node_idx] ); + if( ret ) + { + return( ret ); + } + } + + /* Then the internal nodes, in reverse order so that we can guarantee the + * parent has been created */ + for( r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM - 1; r_node_idx > 0; + r_node_idx-- ) + { + ret = create_merkle_internal_value( + ctx->params.I_key_identifier, + tree[(r_node_idx * 2)], tree[(r_node_idx * 2 + 1)], r_node_idx, tree[r_node_idx] ); + if( ret ) + { + return( ret ); + } + } + + return( 0 ); +} + +static int get_merkle_path( mbedtls_lms_private_t *ctx, + unsigned int leaf_node_id, + unsigned char path[MBEDTLS_LMS_H_TREE_HEIGHT][MBEDTLS_LMS_M_NODE_BYTES] ) +{ + unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES]; + unsigned int curr_node_id = leaf_node_id; + unsigned int adjacent_node_id; + unsigned int height; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + ret = calculate_merkle_tree( ctx, tree); + if( ret ) + { + return( ret ); + } + + for( height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT; height++ ) + { + adjacent_node_id = curr_node_id ^ 1; + + memcpy( &path[height], &tree[adjacent_node_id], MBEDTLS_LMOTS_N_HASH_LEN ); + + curr_node_id >>=1; + } + + return( 0 ); +} + void mbedtls_lms_init_private( mbedtls_lms_private_t *ctx ) { mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) ) ; @@ -668,4 +670,5 @@ int mbedtls_lms_sign( mbedtls_lms_private_t *ctx, return( 0 ); } +#endif /* MBEDTLS_LMS_PRIVATE */ #endif /* MBEDTLS_LMS_C */ diff --git a/tests/suites/test_suite_lmots.function b/tests/suites/test_suite_lmots.function index 4492daaae..73c9aff09 100644 --- a/tests/suites/test_suite_lmots.function +++ b/tests/suites/test_suite_lmots.function @@ -8,7 +8,7 @@ /* END_HEADER */ /* BEGIN_DEPENDENCIES - * depends_on:MBEDTLS_LMS_C:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_CTR_DRBG_C + * depends_on:MBEDTLS_LMS_C:MBEDTLS_LMS_PRIVATE:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_CTR_DRBG_C * END_DEPENDENCIES */ diff --git a/tests/suites/test_suite_lms.function b/tests/suites/test_suite_lms.function index 64ea900f1..22c8eb5a1 100644 --- a/tests/suites/test_suite_lms.function +++ b/tests/suites/test_suite_lms.function @@ -6,7 +6,7 @@ /* END_HEADER */ /* BEGIN_DEPENDENCIES - * depends_on:MBEDTLS_LMS_C:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_CTR_DRBG_C + * depends_on:MBEDTLS_LMS_C:MBEDTLS_LMS_PRIVATE:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_CTR_DRBG_C * END_DEPENDENCIES */