Update LMS and LMOTS api

Fix function names and parameters. Move macros to be more private.
Update implementation.

Signed-off-by: Raef Coles <raef.coles@arm.com>
This commit is contained in:
Raef Coles 2022-08-31 15:55:00 +01:00
parent c8f9604d7b
commit 01c71a17b3
No known key found for this signature in database
GPG Key ID: 1AAF1B43DF2086F4
6 changed files with 1238 additions and 1219 deletions

View File

@ -32,33 +32,24 @@
#include "lmots.h" #include "lmots.h"
#include "mbedtls/private_access.h" #include "mbedtls/build_info.h"
#define MBEDTLS_ERR_LMS_BAD_INPUT_DATA -0x0011 /**< Bad data has been input to an LMS function */ #define MBEDTLS_ERR_LMS_BAD_INPUT_DATA -0x0011 /**< Bad data has been input to an LMS function */
#define MBEDTLS_ERR_LMS_OUT_OF_PRIV_KEYS -0x0013 /**< Specified LMS key has utilised all of its private keys */ #define MBEDTLS_ERR_LMS_OUT_OF_PRIVATE_KEYS -0x0013 /**< Specified LMS key has utilised all of its private keys */
#define MBEDTLS_ERR_LMS_VERIFY_FAILED -0x0015 /**< LMS signature verification failed */ #define MBEDTLS_ERR_LMS_VERIFY_FAILED -0x0015 /**< LMS signature verification failed */
#define MBEDTLS_ERR_LMS_ALLOC_FAILED -0x0017 /**< LMS failed to allocate space for a private key */ #define MBEDTLS_ERR_LMS_ALLOC_FAILED -0x0017 /**< LMS failed to allocate space for a private key */
#define MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL -0x0019 /**< Input/output buffer is too small to contain requited data */ #define MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL -0x0019 /**< Input/output buffer is too small to contain requited data */
#define MBEDTLS_LMS_TYPE_LEN (4)
#define MBEDTLS_LMS_H_TREE_HEIGHT (10)
#define MBEDTLS_LMS_M_NODE_BYTES (32) /* The length of a hash output, 32 for SHA256 */ #define MBEDTLS_LMS_M_NODE_BYTES (32) /* The length of a hash output, 32 for SHA256 */
#define MBEDTLS_LMS_TYPE_LEN (4)
#define MBEDTLS_LMS_H_TREE_HEIGHT (10u)
#define MBEDTLS_LMS_SIG_LEN (MBEDTLS_LMOTS_Q_LEAF_ID_LEN + MBEDTLS_LMOTS_SIG_LEN + \ #define MBEDTLS_LMS_SIG_LEN (MBEDTLS_LMOTS_Q_LEAF_ID_LEN + MBEDTLS_LMOTS_SIG_LEN + \
MBEDTLS_LMS_TYPE_LEN + MBEDTLS_LMS_H_TREE_HEIGHT * MBEDTLS_LMS_M_NODE_BYTES) MBEDTLS_LMS_TYPE_LEN + MBEDTLS_LMS_H_TREE_HEIGHT * MBEDTLS_LMS_M_NODE_BYTES)
#define MBEDTLS_LMS_PUBKEY_LEN (MBEDTLS_LMS_TYPE_LEN + MBEDTLS_LMOTS_TYPE_LEN + \ #define MBEDTLS_LMS_PUBLIC_KEY_LEN (MBEDTLS_LMS_TYPE_LEN + MBEDTLS_LMOTS_TYPE_LEN + \
MBEDTLS_LMOTS_I_KEY_ID_LEN + MBEDTLS_LMS_M_NODE_BYTES) MBEDTLS_LMOTS_I_KEY_ID_LEN + MBEDTLS_LMS_M_NODE_BYTES)
#define MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET (0)
#define MBEDTLS_LMS_SIG_OTS_SIG_OFFSET (MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET + MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
#define MBEDTLS_LMS_SIG_TYPE_OFFSET (MBEDTLS_LMS_SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_SIG_LEN)
#define MBEDTLS_LMS_SIG_PATH_OFFSET (MBEDTLS_LMS_SIG_TYPE_OFFSET + MBEDTLS_LMS_TYPE_LEN)
#define MBEDTLS_LMS_PUBKEY_TYPE_OFFSET (0)
#define MBEDTLS_LMS_PUBKEY_OTSTYPE_OFFSET (MBEDTLS_LMS_PUBKEY_TYPE_OFFSET + MBEDTLS_LMS_TYPE_LEN)
#define MBEDTLS_LMS_PUBKEY_I_KEY_ID_OFFSET (MBEDTLS_LMS_PUBKEY_OTSTYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN)
#define MBEDTLS_LMS_PUBKEY_ROOT_NODE_OFFSET (MBEDTLS_LMS_PUBKEY_I_KEY_ID_OFFSET + MBEDTLS_LMOTS_I_KEY_ID_LEN)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -72,85 +63,234 @@ typedef enum {
} mbedtls_lms_algorithm_type_t; } mbedtls_lms_algorithm_type_t;
/** LMS context structure. /** LMS parameters structure.
*
* This contains the metadata associated with an LMS key, detailing the
* algorithm type, the type of the underlying OTS algorithm, and the key ID.
*/
typedef struct {
unsigned char MBEDTLS_PRIVATE(I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN]); /*!< The key
identifier. */
mbedtls_lmots_algorithm_type_t MBEDTLS_PRIVATE(otstype); /*!< The LM-OTS key type identifier as
per IANA. Only SHA256_N32_W8 is
currently supported. */
mbedtls_lms_algorithm_type_t MBEDTLS_PRIVATE(type); /*!< The LMS key type identifier as per
IANA. Only SHA256_M32_H10 is currently
supported. */
} mbedtls_lms_parameters_t;
/** LMS public context structure.
*
*A LMS public key is the hash output that is the root of the merkle tree, and
* the applicable parameter set
* *
* The context must be initialized before it is used. A public key must either * The context must be initialized before it is used. A public key must either
* be imported, or an algorithm type set, a private key generated and the public * be imported or generated from a private context.
* key calculated from it. A context that does not contain a public key cannot
* verify, and a context that does not contain a private key cannot sign.
* *
* \dot * \dot
* digraph lmots { * digraph lms_public_t {
* UNINITIALIZED -> INIT [label="init"]; * UNINITIALIZED -> INIT [label="init"];
* TYPE_SET -> INIT [label="free"]; * HAVE_PUBLIC_KEY -> INIT [label="free"];
* PRIVATE -> INIT [label="free"]; * INIT -> HAVE_PUBLIC_KEY [label="import_public_key"];
* PUBLIC -> INIT [label="free"]; * INIT -> HAVE_PUBLIC_KEY [label="calculate_public_key from private key"];
* "PRIVATE+PUBLIC" -> INIT [label="free"]; * HAVE_PUBLIC_KEY -> HAVE_PUBLIC_KEY [label="export_public_key"];
* INIT -> TYPE_SET [label="set_algorithm_type"];
* INIT -> PUBLIC [label="import_public"];
* PUBLIC -> PUBLIC [label="export_pubkey"];
* "PRIVATE+PUBLIC" -> "PRIVATE+PUBLIC" [label="export_pubkey"];
* PRIVATE -> "PRIVATE+PUBLIC" [label="gen_pubkey"];
* TYPE_SET -> PRIVATE [label="gen_privkey"];
* } * }
* \enddot * \enddot
*/ */
typedef struct { typedef struct {
unsigned char MBEDTLS_PRIVATE(have_privkey); /*!< Whether the context contains a private key. mbedtls_lms_parameters_t MBEDTLS_PRIVATE(params);
Boolean values only. */
unsigned char MBEDTLS_PRIVATE(have_pubkey); /*!< Whether the context contains a public key.
Boolean values only. */
unsigned char MBEDTLS_PRIVATE(I_key_identifier)[MBEDTLS_LMOTS_I_KEY_ID_LEN]; /*!< The key
identifier. */
mbedtls_lms_algorithm_type_t MBEDTLS_PRIVATE(type); /*!< The LMS key type identifier as per
IANA. Only SHA256_M32_H10 is currently
supported. */
mbedtls_lmots_algorithm_type_t MBEDTLS_PRIVATE(otstype); /*!< The LM-OTS key type identifier as
per IANA. Only SHA256_N32_W8 is currently
supported. */
unsigned int MBEDTLS_PRIVATE(q_next_usable_key); /*!< The index of the next OTS key that has not
been used. */
mbedtls_lmots_context *MBEDTLS_PRIVATE(priv_keys); /*!< The private key material. One OTS key
for each leaf node in the merkle tree. */
unsigned char MBEDTLS_PRIVATE(T_1_pub_key)[MBEDTLS_LMS_M_NODE_BYTES]; /*!< The public key, in unsigned char MBEDTLS_PRIVATE(T_1_pub_key)[MBEDTLS_LMS_M_NODE_BYTES]; /*!< The public key, in
the form of the merkle tree root node. */ the form of the merkle tree root node. */
} mbedtls_lms_context; unsigned char MBEDTLS_PRIVATE(have_public_key); /*!< Whether the context contains a public key.
Boolean values only. */
} mbedtls_lms_public_t;
/** LMS private context structure.
*
* A LMS private key is a set of LMOTS private keys, an index to the next usable
* key, and the applicable parameter set.
*
* The context must be initialized before it is used. A public key must either
* be imported or generated from a private context.
*
* \dot
* digraph lms_public_t {
* UNINITIALIZED -> INIT [label="init"];
* HAVE_PRIVATE_KEY -> INIT [label="free"];
* INIT -> HAVE_PRIVATE_KEY [label="generate_private_key"];
* }
* \enddot
*/
typedef struct {
mbedtls_lms_parameters_t MBEDTLS_PRIVATE(params);
uint32_t MBEDTLS_PRIVATE(q_next_usable_key); /*!< The index of the next OTS key that has not
been used. */
mbedtls_lmots_private_t *MBEDTLS_PRIVATE(ots_private_keys); /*!< The private key material. One OTS key
for each leaf node in the merkle tree. */
mbedtls_lmots_public_t *MBEDTLS_PRIVATE(ots_public_keys); /*!< The OTS key public keys, used to
build the merkle tree. */
unsigned char MBEDTLS_PRIVATE(have_private_key); /*!< Whether the context contains a private key.
Boolean values only. */
} mbedtls_lms_private_t;
/** /**
* \brief This function initializes an LMS context * \brief This function initializes an LMS public context
* *
* \param ctx The uninitialized LMS context that will then be * \param ctx The uninitialized LMS context that will then be
* initialized. * initialized.
*/ */
void mbedtls_lms_init( mbedtls_lms_context *ctx ); void mbedtls_lms_init_public( mbedtls_lms_public_t *ctx );
/** /**
* \brief This function uninitializes an LMS context * \brief This function uninitializes an LMS public context
* *
* \param ctx The initialized LMS context that will then be * \param ctx The initialized LMS context that will then be
* uninitialized. * uninitialized.
*/ */
void mbedtls_lms_free( mbedtls_lms_context *ctx ); void mbedtls_lms_free_public( mbedtls_lms_public_t *ctx );
/** /**
* \brief This function sets the type of an LMS context * \brief This function imports an LMS public key into a
* public LMS context.
* *
* \note The parameter set in the context will then be used * \note Before this function is called, the context must
* for keygen operations etc. * have been initialized.
* *
* \param ctx The initialized LMS context. * \note See IETF RFC8554 for details of the encoding of
* \param type The type that will be set in the context. * this public key.
* \param otstype The type of the LMOTS implementation used by this *
* context. * \param ctx The initialized LMS context store the key in.
* \param key The buffer from which the key will be read.
* #MBEDTLS_LMS_PUBLIC_KEY_LEN bytes will be read from
* this.
* \param key_size The size of the key being imported.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/ */
int mbedtls_lms_set_algorithm_type( mbedtls_lms_context *ctx, int mbedtls_lms_import_public_key( mbedtls_lms_public_t *ctx,
mbedtls_lms_algorithm_type_t type, const unsigned char *key, size_t key_size );
mbedtls_lmots_algorithm_type_t otstype);
/**
* \brief This function verifies a LMS signature, using a
* LMS context that contains a public key.
*
* \note Before this function is called, the context must
* have been initialized and must contain a public key
* (either by import or generation).
*
* \param ctx The initialized LMS public context from which the
* public key will be read.
* \param msg The buffer from which the message will be read.
* \param msg_size The size of the message that will be read.
* \param sig The buf from which the signature will be read.
* #MBEDTLS_LMS_SIG_LEN bytes will be read from
* this.
* \param sig_size The size of the signature to be verified.
*
* \return \c 0 on successful verification.
* \return A non-zero error code on failure.
*/
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 );
/**
* \brief This function initializes an LMS private context
*
* \param ctx The uninitialized LMS private context that will
* then be initialized. */
void mbedtls_lms_init_private( mbedtls_lms_private_t *ctx );
/**
* \brief This function uninitializes an LMS private context
*
* \param ctx The initialized LMS private context that will then
* be uninitialized.
*/
void mbedtls_lms_free_private( mbedtls_lms_private_t *ctx );
/**
* \brief This function generates an LMS private key, and
* stores in into an LMS private context.
*
* \warning This function is **not intended for use in
* production**, due to as-yet unsolved problems with
* handling stateful keys.
*
* \note The seed must have at least 256 bits of entropy.
*
* \param ctx The initialized LMOTS context to generate the key
* into.
* \param type The LMS parameter set identifier.
* \param otstype The LMOTS parameter set identifier.
* \param f_rng The RNG function to be used to generate the key ID.
* \param p_rng The RNG context to be passed to f_rng
* \param seed The seed used to deterministically generate the
* key.
* \param seed_size The length of the seed.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_generate_private_key( mbedtls_lms_private_t *ctx,
mbedtls_lms_algorithm_type_t type,
mbedtls_lmots_algorithm_type_t otstype,
int (*f_rng)(void *, unsigned char *, size_t),
void* p_rng, unsigned char *seed,
size_t seed_size );
/**
* \brief This function generates an LMS public key from a
* LMS context that already contains a private key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a private key.
*
* \param ctx The initialized LMS public context to generate the key
* from and store it into.
*
* \param ctx The LMS private context to read the private key
* from. This must have been initialized and contain a
* private key.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_calculate_public_key( mbedtls_lms_public_t *ctx,
mbedtls_lms_private_t *priv_ctx );
/**
* \brief This function exports an LMS public key from a
* LMS public context that already contains a public
* key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a public key.
*
* \note See IETF RFC8554 for details of the encoding of
* this public key.
*
* \param ctx The initialized LMS public context that contains
* the public key.
* \param key The buffer into which the key will be output. Must
* be at least #MBEDTLS_LMS_PUBLIC_KEY_LEN in size.
* \param key_size The size of the key buffer.
* \param key_len If not NULL, will be written with the size of the
* key.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_export_public_key( mbedtls_lms_public_t *ctx, unsigned char *key,
size_t key_size, size_t *key_len );
/** /**
* \brief This function creates a LMS signature, using a * \brief This function creates a LMS signature, using a
* LMOTS context that contains a private key. * LMS context that contains unused private keys.
* *
* \warning This function is **not intended for use in * \warning This function is **not intended for use in
* production**, due to as-yet unsolved problems with * production**, due to as-yet unsolved problems with
@ -167,135 +307,27 @@ int mbedtls_lms_set_algorithm_type( mbedtls_lms_context *ctx,
* important to not perform copy operations on LMS * important to not perform copy operations on LMS
* contexts that contain private key material. * contexts that contain private key material.
* *
* \param ctx The initialized LMS context from which the * \param ctx The initialized LMS private context from which the
* private key will be read. * private key will be read.
* \param f_rng The RNG function to be used for signature * \param f_rng The RNG function to be used for signature
* generation. * generation.
* \param p_rng The RNG context to be passed to f_rng * \param p_rng The RNG context to be passed to f_rng
* \param msg The buffer from which the message will be read. * \param msg The buffer from which the message will be read.
* \param msg_len The size of the message that will be read. * \param msg_size The size of the message that will be read.
* \param sig The buf into which the signature will be stored. * \param sig The buf into which the signature will be stored.
* Must be at least #MBEDTLS_LMOTS_SIG_LEN in size. * Must be at least #MBEDTLS_LMS_SIG_LEN in size.
* \param sig_size The size of the buffer the signature will be
* written into.
* \param sig_len If not NULL, will be written with the size of the
* signature.
* *
* \return \c 0 on success. * \return \c 0 on success.
* \return A non-zero error code on failure. * \return A non-zero error code on failure.
*/ */
int mbedtls_lms_sign( mbedtls_lms_context *ctx, int mbedtls_lms_sign( mbedtls_lms_private_t *ctx,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void* p_rng, unsigned char *msg, unsigned int msg_len, void* p_rng, unsigned char *msg, unsigned int msg_size,
unsigned char *sig); unsigned char *sig, size_t sig_size, size_t *sig_len);
/**
* \brief This function verifies a LMS signature, using a
* LMS context that contains a public key.
*
* \note Before this function is called, the context must
* have been initialized and must contain a public key
* (either by import or generation).
*
* \param ctx The initialized LMS context from which the public
* key will be read.
* \param msg The buffer from which the message will be read.
* \param msg_len The size of the message that will be read.
* \param sig The buf from which the signature will be read.
* #MBEDTLS_LMS_SIG_LEN bytes will be read from
* this.
*
* \return \c 0 on successful verification.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_verify( const mbedtls_lms_context *ctx,
const unsigned char *msg, unsigned int msg_len,
const unsigned char *sig );
/**
* \brief This function imports an LMOTS public key into a
* LMS context.
*
* \note Before this function is called, the context must
* have been initialized.
*
* \note See IETF RFC8554 for details of the encoding of
* this public key.
*
* \param ctx The initialized LMS context store the key in.
* \param key The buffer from which the key will be read.
* #MBEDTLS_LMS_PUBKEY_LEN bytes will be read from
* this.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_import_pubkey( mbedtls_lms_context *ctx,
const unsigned char *key );
/**
* \brief This function exports an LMOTS public key from a
* LMS context that already contains a public key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a public key.
*
* \note See IETF RFC8554 for details of the encoding of
* this public key.
*
* \param ctx The initialized LMS context that contains the
* publc key.
* \param key The buffer into which the key will be output. Must
* be at least #MBEDTLS_LMS_PUBKEY_LEN in size.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_export_pubkey( mbedtls_lms_context *ctx,
unsigned char *key );
/**
* \brief This function generates an LMS public key from a
* LMS context that already contains a private key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a private key.
*
* \param ctx The initialized LMS context to generate the key
* from and store it into.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_gen_pubkey( mbedtls_lms_context *ctx );
/**
* \brief This function generates an LMS private key, and
* stores in into an LMS context.
*
* \warning This function is **not intended for use in
* production**, due to as-yet unsolved problems with
* handling stateful keys.
*
* \note Before this function is called, the context must
* have been initialized and the type of the LMS
* context set using mbedtls_lmots_set_algorithm_type
*
* \note The seed must have at least 256 bits of entropy.
*
* \param ctx The initialized LMOTS context to generate the key
* into.
* \param f_rng The RNG function to be used to generate the key ID.
* \param p_rng The RNG context to be passed to f_rng
* \param seed The seed used to deterministically generate the
* key.
* \param seed_len The length of the seed.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lms_gen_privkey( mbedtls_lms_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void* p_rng, unsigned char *seed,
size_t seed_len );
#ifdef __cplusplus #ifdef __cplusplus
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
#ifndef MBEDTLS_LMOTS_H #ifndef MBEDTLS_LMOTS_H
#define MBEDTLS_LMOTS_H #define MBEDTLS_LMOTS_H
#include "mbedtls/private_access.h" #include "mbedtls/build_info.h"
#include "psa/crypto.h" #include "psa/crypto.h"
@ -34,27 +34,19 @@
#include <stddef.h> #include <stddef.h>
#define MBEDTLS_LMOTS_N_HASH_LEN (32) #define MBEDTLS_LMOTS_N_HASH_LEN (32)
#define MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN (34) #define MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT (34)
#define MBEDTLS_LMOTS_TYPE_LEN (4) #define MBEDTLS_LMOTS_TYPE_LEN (4)
#define MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN (MBEDTLS_LMOTS_N_HASH_LEN) #define MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN (MBEDTLS_LMOTS_N_HASH_LEN)
#define MBEDTLS_LMOTS_I_KEY_ID_LEN (16) #define MBEDTLS_LMOTS_I_KEY_ID_LEN (16)
#define MBEDTLS_LMOTS_Q_LEAF_ID_LEN (4) #define MBEDTLS_LMOTS_Q_LEAF_ID_LEN (4)
#define MBEDTLS_LMOTS_SIG_LEN (MBEDTLS_LMOTS_TYPE_LEN + MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN + \ #define MBEDTLS_LMOTS_SIG_LEN (MBEDTLS_LMOTS_TYPE_LEN + MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN + \
(MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN * MBEDTLS_LMOTS_N_HASH_LEN)) (MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT * MBEDTLS_LMOTS_N_HASH_LEN))
#define MBEDTLS_LMOTS_PUBKEY_LEN (MBEDTLS_LMOTS_TYPE_LEN + MBEDTLS_LMOTS_I_KEY_ID_LEN + \ #define MBEDTLS_LMOTS_PUBLIC_KEY_LEN (MBEDTLS_LMOTS_TYPE_LEN + MBEDTLS_LMOTS_I_KEY_ID_LEN + \
MBEDTLS_LMOTS_Q_LEAF_ID_LEN + MBEDTLS_LMOTS_N_HASH_LEN) MBEDTLS_LMOTS_Q_LEAF_ID_LEN + MBEDTLS_LMOTS_N_HASH_LEN)
#define MBEDTLS_LMOTS_SIG_TYPE_OFFSET (0) #define MBEDTLS_LMOTS_SIG_TYPE_OFFSET (0)
#define MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET (MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN)
#define MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET (MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET + MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN)
#define MBEDTLS_LMOTS_PUBKEY_TYPE_OFFSET (0)
#define MBEDTLS_LMOTS_PUBKEY_I_KEY_ID_OFFSET (MBEDTLS_LMOTS_PUBKEY_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN)
#define MBEDTLS_LMOTS_PUBKEY_Q_LEAF_ID_OFFSET (MBEDTLS_LMOTS_PUBKEY_I_KEY_ID_OFFSET + MBEDTLS_LMOTS_I_KEY_ID_LEN)
#define MBEDTLS_LMOTS_PUBKEY_KEY_HASH_OFFSET (MBEDTLS_LMOTS_PUBKEY_Q_LEAF_ID_OFFSET + MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -68,54 +60,93 @@ typedef enum {
} mbedtls_lmots_algorithm_type_t; } mbedtls_lmots_algorithm_type_t;
/** LMOTS context structure. /** LMOTS parameters structure.
*
* This contains the metadata associated with an LMOTS key, detailing the
* algorithm type, the key ID, and the leaf identifier should be key be part of
* a LMS key.
*/
typedef struct {
unsigned char MBEDTLS_PRIVATE(I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN]); /*!< The key
identifier. */
unsigned char MBEDTLS_PRIVATE(q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN]); /*!< Which
leaf of the LMS key this is.
0 if the key is not part of an LMS key. */
mbedtls_lmots_algorithm_type_t MBEDTLS_PRIVATE(type); /*!< The LM-OTS key type identifier as
per IANA. Only SHA256_N32_W8 is
currently supported. */
} mbedtls_lmots_parameters_t;
/** LMOTS public context structure.
*
* A LMOTS public key is a hash output, and the applicable parameter set.
* *
* The context must be initialized before it is used. A public key must either * The context must be initialized before it is used. A public key must either
* be imported, or an algorithm type set, a private key generated and the public * be imported or generated from a private context.
* key calculated from it. A context that does not contain a public key cannot
* verify, and a context that does not contain a private key cannot sign.
* Signing a message will remove the private key from the context, as private
* keys can only be used a single time.
* *
* \dot * \dot
* digraph lmots { * digraph lmots_public_t {
* UNINITIALIZED -> INIT [label="init"]; * UNINITIALIZED -> INIT [label="init"];
* TYPE_SET -> INIT [label="free"]; * HAVE_PUBLIC_KEY -> INIT [label="free"];
* PRIVATE -> INIT [label="free"]; * INIT -> HAVE_PUBLIC_KEY [label="import_public_key"];
* PUBLIC -> INIT [label="free"]; * INIT -> HAVE_PUBLIC_KEY [label="calculate_public_key from private key"];
* "PRIVATE+PUBLIC" -> INIT [label="free"]; * HAVE_PUBLIC_KEY -> HAVE_PUBLIC_KEY [label="export_public_key"];
* INIT -> TYPE_SET [label="set_algorithm_type"];
* PRIVATE -> TYPE_SET [label="sign"];
* "PRIVATE+PUBLIC" -> PUBLIC [label="sign"];
* INIT -> PUBLIC [label="import_public"];
* PUBLIC -> PUBLIC [label="export_pubkey"];
* "PRIVATE+PUBLIC" -> "PRIVATE+PUBLIC" [label="export_pubkey"];
* PRIVATE -> "PRIVATE+PUBLIC" [label="gen_pubkey"];
* TYPE_SET -> PRIVATE [label="gen_privkey"];
* } * }
* \enddot * \enddot
*/ */
typedef struct { typedef struct {
unsigned char MBEDTLS_PRIVATE(have_privkey); /*!< Whether the context contains a private key. mbedtls_lmots_parameters_t MBEDTLS_PRIVATE(params);
unsigned char MBEDTLS_PRIVATE(public_key)[32];
unsigned char MBEDTLS_PRIVATE(have_public_key); /*!< Whether the context contains a public key.
Boolean values only. */ Boolean values only. */
unsigned char MBEDTLS_PRIVATE(have_pubkey); /*!< Whether the context contains a public key. } mbedtls_lmots_public_t;
/** LMOTS private context structure.
*
* A LMOTS private key is one hash output for each of digit of the digest +
* checksum, and the applicable parameter set.
*
* The context must be initialized before it is used. A public key must either
* be imported or generated from a private context.
*
* \dot
* digraph lmots_public_t {
* UNINITIALIZED -> INIT [label="init"];
* HAVE_PRIVATE_KEY -> INIT [label="free"];
* INIT -> HAVE_PRIVATE_KEY [label="generate_private_key"];
* HAVE_PRIVATE_KEY -> INIT [label="sign"];
* }
* \enddot
*/
typedef struct {
mbedtls_lmots_parameters_t MBEDTLS_PRIVATE(params);
unsigned char MBEDTLS_PRIVATE(private_key)[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT][32];
unsigned char MBEDTLS_PRIVATE(have_private_key); /*!< Whether the context contains a private key.
Boolean values only. */ Boolean values only. */
unsigned char MBEDTLS_PRIVATE(I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN]); /*!< The key } mbedtls_lmots_private_t;
identifier. */
unsigned int MBEDTLS_PRIVATE(q_leaf_identifier); /*!< Which leaf of the LMS key this is. /**
0 if the key is not part of an LMS key. */ * \brief This function converts an unsigned int into a
unsigned char MBEDTLS_PRIVATE(q_leaf_identifier_bytes)[MBEDTLS_LMOTS_Q_LEAF_ID_LEN];/*!< The * network-byte-order (big endian) string.
leaf identifier in network bytes form. */ *
mbedtls_lmots_algorithm_type_t MBEDTLS_PRIVATE(type); /*!< The LM-OTS key type identifier as * \param val The unsigned integer value
per IANA. Only SHA256_N32_W8 is currently * \param len The length of the string.
supported. */ * \param bytes The string to output into.
unsigned char MBEDTLS_PRIVATE(priv_key[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32]); /*!< The private *
key, one hash output per byte of the encoded * \return The corresponding LMS error code.
symbol string P (32 bytes of hash output + */
2 bytes of checksum). */ void unsigned_int_to_network_bytes(unsigned int val, size_t len, unsigned char *bytes);
unsigned char MBEDTLS_PRIVATE(pub_key[32]); /*!< The public key, in the form of a SHA256
output. */ /**
} mbedtls_lmots_context; * \brief This function converts a network-byte-order
* (big endian) string into an unsigned integer.
*
* \param len The length of the string.
* \param bytes The string.
*
* \return The corresponding LMS error code.
*/
unsigned int network_bytes_to_unsigned_int(size_t len, const unsigned char *bytes);
/** /**
* \brief This function converts a \ref psa_status_t to a * \brief This function converts a \ref psa_status_t to a
@ -129,35 +160,41 @@ int mbedtls_lms_error_from_psa(psa_status_t status);
/** /**
* \brief This function initializes an LMOTS context * \brief This function initializes a public LMOTS context
* *
* \param ctx The uninitialized LMOTS context that will then be * \param ctx The uninitialized LMOTS context that will then be
* initialized. * initialized.
*/ */
void mbedtls_lmots_init( mbedtls_lmots_context *ctx ); void mbedtls_lmots_init_public( mbedtls_lmots_public_t *ctx );
/** /**
* \brief This function uninitializes an LMOTS context * \brief This function uninitializes a public LMOTS context
* *
* \param ctx The initialized LMOTS context that will then be * \param ctx The initialized LMOTS context that will then be
* uninitialized. * uninitialized.
*/ */
void mbedtls_lmots_free( mbedtls_lmots_context *ctx ); void mbedtls_lmots_free_public( mbedtls_lmots_public_t *ctx );
/** /**
* \brief This function sets the type of an LMOTS context * \brief This function imports an LMOTS public key into a
* LMOTS context.
* *
* \note The parameter set in the context will then be used * \note Before this function is called, the context must
* for keygen operations etc. * have been initialized.
* *
* \param ctx The initialized LMOTS context. * \note See IETF RFC8554 for details of the encoding of
* \param type The type that will be set in the context. * this public key.
*
* \param ctx The initialized LMOTS context store the key in.
* \param key The buffer from which the key will be read.
* #MBEDTLS_LMOTS_PUBLIC_KEY_LEN bytes will be read from
* this.
* *
* \return \c 0 on success. * \return \c 0 on success.
* \return A non-zero error code on failure. * \return A non-zero error code on failure.
*/ */
int mbedtls_lmots_set_algorithm_type( mbedtls_lmots_context *ctx, int mbedtls_lmots_import_public_key( mbedtls_lmots_public_t *ctx,
mbedtls_lmots_algorithm_type_t type ); const unsigned char *key, size_t key_size );
/** /**
* \brief This function creates a candidate public key from * \brief This function creates a candidate public key from
@ -170,12 +207,10 @@ int mbedtls_lmots_set_algorithm_type( mbedtls_lmots_context *ctx,
* mbedtls_lmots_verify will be used for LMOTS * mbedtls_lmots_verify will be used for LMOTS
* signature verification. * signature verification.
* *
* \param I_key_identifier The key identifier of the key, as a 16-byte string. * \param params The LMOTS parameter set, q and I values as an
* \param q_leaf_identifier The leaf identifier of key. If this LMOTS key is * mbedtls_lmots_parameters_t struct.
* not being used as part of an LMS key, this should
* be set to 0.
* \param msg The buffer from which the message will be read. * \param msg The buffer from which the message will be read.
* \param msg_len The size of the message that will be read. * \param msg_size The size of the message that will be read.
* \param sig The buffer from which the signature will be read. * \param sig The buffer from which the signature will be read.
* #MBEDTLS_LMOTS_SIG_LEN bytes will be read from this. * #MBEDTLS_LMOTS_SIG_LEN bytes will be read from this.
* \param out The buffer where the candidate public key will be * \param out The buffer where the candidate public key will be
@ -185,13 +220,128 @@ int mbedtls_lmots_set_algorithm_type( mbedtls_lmots_context *ctx,
* \return \c 0 on success. * \return \c 0 on success.
* \return A non-zero error code on failure. * \return A non-zero error code on failure.
*/ */
int mbedtls_lmots_generate_pub_key_candidate( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN], int mbedtls_lmots_calculate_public_key_candidate( const mbedtls_lmots_parameters_t *params,
const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN], const unsigned char *msg,
const unsigned char *msg, size_t msg_size,
size_t msg_len, const unsigned char *sig,
const unsigned char *sig, size_t sig_size,
unsigned char *out ); unsigned char *out,
size_t out_size,
size_t *out_len);
/**
* \brief This function verifies a LMOTS signature, using a
* LMOTS context that contains a public key.
*
* \warning This function is **not intended for use in
* production**, due to as-yet unsolved problems with
* handling stateful keys.
*
* \note Before this function is called, the context must
* have been initialized and must contain a public key
* (either by import or calculation from a private key).
*
* \param ctx The initialized LMOTS context from which the public
* key will be read.
* \param msg The buffer from which the message will be read.
* \param msg_size The size of the message that will be read.
* \param sig The buf from which the signature will be read.
* #MBEDTLS_LMOTS_SIG_LEN bytes will be read from
* this.
*
* \return \c 0 on successful verification.
* \return A non-zero error code on failure.
*/
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 );
/**
* \brief This function initializes a private LMOTS context
*
* \param ctx The uninitialized LMOTS context that will then be
* initialized.
*/
void mbedtls_lmots_init_private( mbedtls_lmots_private_t *ctx );
/**
* \brief This function uninitializes a private LMOTS context
*
* \param ctx The initialized LMOTS context that will then be
* uninitialized.
*/
void mbedtls_lmots_free_private( mbedtls_lmots_private_t *ctx );
/**
* \brief This function generates an LMOTS private key, and
* stores in into an LMOTS context.
*
* \warning This function is **not intended for use in
* production**, due to as-yet unsolved problems with
* handling stateful keys.
*
* \note The seed must have at least 256 bits of entropy.
*
* \param ctx The initialized LMOTS context to generate the key
* into.
* \param I_key_identifier The key identifier of the key, as a 16-byte string.
* \param q_leaf_identifier The leaf identifier of key. If this LMOTS key is
* not being used as part of an LMS key, this should
* be set to 0.
* \param seed The seed used to deterministically generate the
* key.
* \param seed_size The length of the seed.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_generate_private_key( mbedtls_lmots_private_t *ctx,
mbedtls_lmots_algorithm_type_t type,
const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
uint32_t q_leaf_identifier,
const unsigned char *seed,
size_t seed_size );
/**
* \brief This function generates an LMOTS public key from a
* LMOTS context that already contains a private key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a private key.
*
* \param ctx The initialized LMOTS context to generate the key
* from and store it into.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_calculate_public_key( mbedtls_lmots_public_t *ctx,
mbedtls_lmots_private_t *priv_ctx);
/**
* \brief This function exports an LMOTS public key from a
* LMOTS context that already contains a public key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a public key.
*
* \note See IETF RFC8554 for details of the encoding of
* this public key.
*
* \param ctx The initialized LMOTS context that contains the
* publc key.
* \param key The buffer into which the key will be output. Must
* be at least #MBEDTLS_LMOTS_PUBLIC_KEY_LEN in size.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_export_public_key( mbedtls_lmots_public_t *ctx,
unsigned char *key, size_t key_size,
size_t *key_len );
/** /**
* \brief This function creates a LMOTS signature, using a * \brief This function creates a LMOTS signature, using a
* LMOTS context that contains a private key. * LMOTS context that contains a private key.
@ -213,135 +363,18 @@ int mbedtls_lmots_generate_pub_key_candidate( const unsigned char I_key_identifi
* generation. * generation.
* \param p_rng The RNG context to be passed to f_rng * \param p_rng The RNG context to be passed to f_rng
* \param msg The buffer from which the message will be read. * \param msg The buffer from which the message will be read.
* \param msg_len The size of the message that will be read. * \param msg_size The size of the message that will be read.
* \param sig The buf into which the signature will be stored. * \param sig The buf into which the signature will be stored.
* Must be at least #MBEDTLS_LMOTS_SIG_LEN in size. * Must be at least #MBEDTLS_LMOTS_SIG_LEN in size.
* *
* \return \c 0 on success. * \return \c 0 on success.
* \return A non-zero error code on failure. * \return A non-zero error code on failure.
*/ */
int mbedtls_lmots_sign( mbedtls_lmots_context *ctx, int mbedtls_lmots_sign( mbedtls_lmots_private_t *ctx,
int (*f_rng)(void *, unsigned char *, size_t), int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng, const unsigned char *msg, size_t msg_len, void *p_rng, const unsigned char *msg, size_t msg_size,
unsigned char *sig ); unsigned char *sig, size_t sig_size, size_t* sig_len );
/**
* \brief This function verifies a LMOTS signature, using a
* LMOTS context that contains a public key.
*
* \warning This function is **not intended for use in
* production**, due to as-yet unsolved problems with
* handling stateful keys.
*
* \note Before this function is called, the context must
* have been initialized and must contain a public key
* (either by import or generation).
*
* \param ctx The initialized LMOTS context from which the public
* key will be read.
* \param msg The buffer from which the message will be read.
* \param msg_len The size of the message that will be read.
* \param sig The buf from which the signature will be read.
* #MBEDTLS_LMOTS_SIG_LEN bytes will be read from
* this.
*
* \return \c 0 on successful verification.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_verify( mbedtls_lmots_context *ctx, const unsigned char *msg,
size_t msg_len, const unsigned char *sig );
/**
* \brief This function imports an LMOTS public key into a
* LMOTS context.
*
* \note Before this function is called, the context must
* have been initialized.
*
* \note See IETF RFC8554 for details of the encoding of
* this public key.
*
* \param ctx The initialized LMOTS context store the key in.
* \param key The buffer from which the key will be read.
* #MBEDTLS_LMOTS_PUBKEY_LEN bytes will be read from
* this.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_import_pubkey( mbedtls_lmots_context *ctx,
const unsigned char *key );
/**
* \brief This function exports an LMOTS public key from a
* LMOTS context that already contains a public key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a public key.
*
* \note See IETF RFC8554 for details of the encoding of
* this public key.
*
* \param ctx The initialized LMOTS context that contains the
* publc key.
* \param key The buffer into which the key will be output. Must
* be at least #MBEDTLS_LMOTS_PUBKEY_LEN in size.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_export_pubkey( mbedtls_lmots_context *ctx,
unsigned char *key );
/**
* \brief This function generates an LMOTS public key from a
* LMOTS context that already contains a private key.
*
* \note Before this function is called, the context must
* have been initialized and the context must contain
* a private key.
*
* \param ctx The initialized LMOTS context to generate the key
* from and store it into.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_gen_pubkey( mbedtls_lmots_context *ctx );
/**
* \brief This function generates an LMOTS private key, and
* stores in into an LMOTS context.
*
* \warning This function is **not intended for use in
* production**, due to as-yet unsolved problems with
* handling stateful keys.
*
* \note Before this function is called, the context must
* have been initialized and the type of the LMOTS
* context set using mbedtls_lmots_set_algorithm_type
*
* \note The seed must have at least 256 bits of entropy.
*
* \param ctx The initialized LMOTS context to generate the key
* into.
* \param I_key_identifier The key identifier of the key, as a 16-byte string.
* \param q_leaf_identifier The leaf identifier of key. If this LMOTS key is
* not being used as part of an LMS key, this should
* be set to 0.
* \param seed The seed used to deterministically generate the
* key.
* \param seed_len The length of the seed.
*
* \return \c 0 on success.
* \return A non-zero error code on failure.
*/
int mbedtls_lmots_gen_privkey( mbedtls_lmots_context *ctx,
const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
unsigned int q_leaf_identifier,
const unsigned char *seed,
size_t seed_len );
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -54,45 +54,33 @@
#define mbedtls_free free #define mbedtls_free free
#endif #endif
#define MERKLE_TREE_NODE_AM (1 << (MBEDTLS_LMS_H_TREE_HEIGHT + 1)) #define MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET (0)
#define MERKLE_TREE_LEAF_AM (1 << MBEDTLS_LMS_H_TREE_HEIGHT) #define MBEDTLS_LMS_SIG_OTS_SIG_OFFSET (MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET + MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
#define MERKLE_TREE_INTR_AM (1 << MBEDTLS_LMS_H_TREE_HEIGHT) #define MBEDTLS_LMS_SIG_TYPE_OFFSET (MBEDTLS_LMS_SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_SIG_LEN)
#define MBEDTLS_LMS_SIG_PATH_OFFSET (MBEDTLS_LMS_SIG_TYPE_OFFSET + MBEDTLS_LMS_TYPE_LEN)
#define MBEDTLS_LMS_PUBLIC_KEY_TYPE_OFFSET (0)
#define MBEDTLS_LMS_PUBLIC_KEY_OTSTYPE_OFFSET (MBEDTLS_LMS_PUBLIC_KEY_TYPE_OFFSET + MBEDTLS_LMS_TYPE_LEN)
#define MBEDTLS_LMS_PUBLIC_KEY_I_KEY_ID_OFFSET (MBEDTLS_LMS_PUBLIC_KEY_OTSTYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN)
#define MBEDTLS_LMS_PUBLIC_KEY_ROOT_NODE_OFFSET (MBEDTLS_LMS_PUBLIC_KEY_I_KEY_ID_OFFSET + MBEDTLS_LMOTS_I_KEY_ID_LEN)
#define MERKLE_TREE_NODE_AM (1u << (MBEDTLS_LMS_H_TREE_HEIGHT + 1u))
#define MERKLE_TREE_LEAF_NODE_AM (1u << MBEDTLS_LMS_H_TREE_HEIGHT)
#define MERKLE_TREE_INTERNAL_NODE_AM (1u << MBEDTLS_LMS_H_TREE_HEIGHT)
#define D_CONST_LEN (2) #define D_CONST_LEN (2)
static const unsigned char D_LEAF_CONSTANT_BYTES[D_CONST_LEN] = {0x82, 0x82};
static const unsigned char D_INTERNAL_CONSTANT_BYTES[D_CONST_LEN] = {0x83, 0x83};
#define D_LEAF_CONSTANT (0x8282) static int create_merkle_leaf_node( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
#define D_INTR_CONSTANT (0x8383)
static void val_to_network_bytes(unsigned int val, size_t len, unsigned char *bytes)
{
size_t idx;
for (idx = 0; idx < len; idx++) {
bytes[idx] = (val >> ((len - 1 - idx) * 8)) & 0xFF;
}
}
static unsigned int network_bytes_to_val(size_t len, const unsigned char *bytes)
{
size_t idx;
unsigned int val = 0;
for (idx = 0; idx < len; idx++) {
val |= ((unsigned int)bytes[idx]) << (8 * (len - 1 - idx));
}
return val;
}
static int create_merkle_leaf_node( const mbedtls_lms_context *ctx,
unsigned char pub_key[MBEDTLS_LMOTS_N_HASH_LEN], unsigned char pub_key[MBEDTLS_LMOTS_N_HASH_LEN],
unsigned int r_node_idx, unsigned int r_node_idx,
unsigned char out[32] ) unsigned char out[MBEDTLS_LMS_M_NODE_BYTES] )
{ {
psa_hash_operation_t op; psa_hash_operation_t op;
psa_status_t status; psa_status_t status;
size_t output_hash_len; size_t output_hash_len;
unsigned char D_LEAF_bytes[D_CONST_LEN];
unsigned char r_node_idx_bytes[4]; unsigned char r_node_idx_bytes[4];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@ -100,64 +88,49 @@ static int create_merkle_leaf_node( const mbedtls_lms_context *ctx,
status = psa_hash_setup( &op, PSA_ALG_SHA_256 ); status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if ( ret != 0 ) if ( ret != 0 )
{ goto exit;
goto out;
}
status = psa_hash_update( &op, ctx->MBEDTLS_PRIVATE(I_key_identifier), status = psa_hash_update( &op, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
MBEDTLS_LMOTS_I_KEY_ID_LEN );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
val_to_network_bytes( r_node_idx, 4, r_node_idx_bytes ); unsigned_int_to_network_bytes( r_node_idx, 4, r_node_idx_bytes );
status = psa_hash_update( &op, r_node_idx_bytes, 4 ); status = psa_hash_update( &op, r_node_idx_bytes, 4 );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
val_to_network_bytes( D_LEAF_CONSTANT, D_CONST_LEN, D_LEAF_bytes ); status = psa_hash_update( &op, D_LEAF_CONSTANT_BYTES, D_CONST_LEN );
status = psa_hash_update( &op, D_LEAF_bytes, D_CONST_LEN );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
status = psa_hash_update( &op, pub_key, MBEDTLS_LMOTS_N_HASH_LEN ); status = psa_hash_update( &op, pub_key, MBEDTLS_LMOTS_N_HASH_LEN );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
status = psa_hash_finish( &op, out, 32, &output_hash_len); status = psa_hash_finish( &op, out, MBEDTLS_LMS_M_NODE_BYTES, &output_hash_len);
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
out: exit:
psa_hash_abort( &op ); psa_hash_abort( &op );
return( ret ); return( ret );
} }
static int create_merkle_intr_node( const mbedtls_lms_context *ctx, static int create_merkle_internal_node( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
const unsigned char left_node[32], const unsigned char left_node[MBEDTLS_LMS_M_NODE_BYTES],
const unsigned char rght_node[32], const unsigned char right_node[MBEDTLS_LMS_M_NODE_BYTES],
unsigned int r_node_idx, unsigned int r_node_idx,
unsigned char out[32] ) unsigned char out[MBEDTLS_LMS_M_NODE_BYTES] )
{ {
psa_hash_operation_t op; psa_hash_operation_t op;
psa_status_t status; psa_status_t status;
size_t output_hash_len; size_t output_hash_len;
unsigned char D_INTR_bytes[D_CONST_LEN];
unsigned char r_node_idx_bytes[4]; unsigned char r_node_idx_bytes[4];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@ -165,75 +138,62 @@ static int create_merkle_intr_node( const mbedtls_lms_context *ctx,
status = psa_hash_setup( &op, PSA_ALG_SHA_256 ); status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if ( ret != 0 ) if ( ret != 0 )
{ goto exit;
goto out;
}
status = psa_hash_update( &op, ctx->MBEDTLS_PRIVATE(I_key_identifier), status = psa_hash_update( &op, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
MBEDTLS_LMOTS_I_KEY_ID_LEN );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
val_to_network_bytes( r_node_idx, 4, r_node_idx_bytes ); unsigned_int_to_network_bytes( r_node_idx, 4, r_node_idx_bytes );
status = psa_hash_update( &op, r_node_idx_bytes, 4 ); status = psa_hash_update( &op, r_node_idx_bytes, 4 );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
val_to_network_bytes( D_INTR_CONSTANT, D_CONST_LEN, D_INTR_bytes ); status = psa_hash_update( &op, D_INTERNAL_CONSTANT_BYTES, D_CONST_LEN );
status = psa_hash_update( &op, D_INTR_bytes, D_CONST_LEN );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
status = psa_hash_update( &op, left_node, MBEDTLS_LMOTS_N_HASH_LEN ); status = psa_hash_update( &op, left_node, MBEDTLS_LMOTS_N_HASH_LEN );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
status = psa_hash_update( &op, rght_node, MBEDTLS_LMOTS_N_HASH_LEN ); status = psa_hash_update( &op, right_node, MBEDTLS_LMOTS_N_HASH_LEN );
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
ret = psa_hash_finish( &op, out, 32, &output_hash_len); ret = psa_hash_finish( &op, out, MBEDTLS_LMS_M_NODE_BYTES, &output_hash_len);
ret = mbedtls_lms_error_from_psa( status ); ret = mbedtls_lms_error_from_psa( status );
if( ret ) if( ret )
{ goto exit;
goto out;
}
out: exit:
psa_hash_abort( &op ); psa_hash_abort( &op );
return ret; return ret;
} }
static int generate_merkle_tree( mbedtls_lms_context *ctx, static int calculate_merkle_tree( mbedtls_lms_private_t *ctx,
unsigned char tree[MERKLE_TREE_NODE_AM][32] ) unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES] )
{ {
unsigned int priv_key_idx; unsigned int priv_key_idx;
unsigned int r_node_idx; unsigned int r_node_idx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* First create the leaf nodes, in ascending order */ /* First create the leaf nodes, in ascending order */
for( priv_key_idx = 0; priv_key_idx < MERKLE_TREE_INTR_AM; priv_key_idx++ ) for( priv_key_idx = 0; priv_key_idx < MERKLE_TREE_INTERNAL_NODE_AM;
priv_key_idx++ )
{ {
r_node_idx = MERKLE_TREE_INTR_AM + priv_key_idx; r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM + priv_key_idx;
ret = create_merkle_leaf_node( ctx, ctx->MBEDTLS_PRIVATE(priv_keys)[priv_key_idx].pub_key, ret = create_merkle_leaf_node(
r_node_idx, tree[r_node_idx] ); ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
ctx->MBEDTLS_PRIVATE(ots_public_keys)[priv_key_idx].MBEDTLS_PRIVATE(public_key),
r_node_idx, tree[r_node_idx] );
if( ret ) if( ret )
{ {
return( ret ); return( ret );
@ -242,11 +202,12 @@ static int generate_merkle_tree( mbedtls_lms_context *ctx,
/* Then the internal nodes, in reverse order so that we can guarantee the /* Then the internal nodes, in reverse order so that we can guarantee the
* parent has been created */ * parent has been created */
for( r_node_idx = MERKLE_TREE_INTR_AM - 1; r_node_idx > 0; r_node_idx-- ) for( r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM - 1; r_node_idx > 0;
r_node_idx-- )
{ {
ret = create_merkle_intr_node( ctx, tree[(r_node_idx * 2)], ret = create_merkle_internal_node(
tree[(r_node_idx * 2 + 1)], ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
r_node_idx, tree[r_node_idx] ); tree[(r_node_idx * 2)], tree[(r_node_idx * 2 + 1)], r_node_idx, tree[r_node_idx] );
if( ret ) if( ret )
{ {
return( ret ); return( ret );
@ -256,18 +217,17 @@ static int generate_merkle_tree( mbedtls_lms_context *ctx,
return( 0 ); return( 0 );
} }
static int get_merkle_path( mbedtls_lms_context *ctx, static int get_merkle_path( mbedtls_lms_private_t *ctx,
unsigned int leaf_node_id, unsigned char path[MBEDTLS_LMS_H_TREE_HEIGHT][32] ) 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][32]; unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES];
unsigned int curr_node_id = leaf_node_id; unsigned int curr_node_id = leaf_node_id;
unsigned int parent_node_id;
unsigned char sibling_relative_id;
unsigned int adjacent_node_id; unsigned int adjacent_node_id;
unsigned int height; unsigned int height;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ret = generate_merkle_tree( ctx, tree); ret = calculate_merkle_tree( ctx, tree);
if( ret ) if( ret )
{ {
return( ret ); return( ret );
@ -275,195 +235,107 @@ static int get_merkle_path( mbedtls_lms_context *ctx,
for( height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT; height++ ) for( height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT; height++ )
{ {
parent_node_id = ( curr_node_id / 2 ); adjacent_node_id = curr_node_id ^ 1;
/* 0 if the node is a left child, 1 if the node is a right child */
sibling_relative_id = curr_node_id & 1;
adjacent_node_id = ( parent_node_id * 2 ) + ( 1 - sibling_relative_id );
memcpy( &path[height], &tree[adjacent_node_id], MBEDTLS_LMOTS_N_HASH_LEN ); memcpy( &path[height], &tree[adjacent_node_id], MBEDTLS_LMOTS_N_HASH_LEN );
curr_node_id = parent_node_id; curr_node_id >>=1;
} }
return( 0 ); return( 0 );
} }
void mbedtls_lms_init( mbedtls_lms_context *ctx ) void mbedtls_lms_init_public( mbedtls_lms_public_t *ctx )
{ {
if( ctx == NULL ) mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) ) ;
{
return;
}
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_context ) ) ;
} }
void mbedtls_lms_free( mbedtls_lms_context *ctx ) void mbedtls_lms_free_public( mbedtls_lms_public_t *ctx )
{ {
unsigned int idx; mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) );
if( ctx == NULL )
{
return;
}
if( ctx->MBEDTLS_PRIVATE(have_privkey) )
{
for( idx = 0; idx < MERKLE_TREE_LEAF_AM; idx++ )
{
mbedtls_lmots_free( &ctx->MBEDTLS_PRIVATE(priv_keys)[idx] );
}
mbedtls_free( ctx->MBEDTLS_PRIVATE(priv_keys) );
}
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_context ) );
} }
int mbedtls_lms_set_algorithm_type( mbedtls_lms_context *ctx, int mbedtls_lms_import_public_key( mbedtls_lms_public_t *ctx,
mbedtls_lms_algorithm_type_t type, const unsigned char *key, size_t key_size )
mbedtls_lmots_algorithm_type_t otstype )
{ {
if( ctx == NULL ) mbedtls_lms_algorithm_type_t type;
mbedtls_lmots_algorithm_type_t otstype;
if( key_size < MBEDTLS_LMS_PUBLIC_KEY_LEN )
{
return( MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL );
}
type = network_bytes_to_unsigned_int( MBEDTLS_LMS_TYPE_LEN, key + MBEDTLS_LMS_PUBLIC_KEY_TYPE_OFFSET );
if( type != MBEDTLS_LMS_SHA256_M32_H10 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type) = type;
ctx->MBEDTLS_PRIVATE(type) = type; otstype = network_bytes_to_unsigned_int( MBEDTLS_LMOTS_TYPE_LEN,
ctx->MBEDTLS_PRIVATE(otstype) = otstype; key + MBEDTLS_LMS_PUBLIC_KEY_OTSTYPE_OFFSET );
if( otstype != MBEDTLS_LMOTS_SHA256_N32_W8 )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(otstype) = otstype;
memcpy( ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
key + MBEDTLS_LMS_PUBLIC_KEY_I_KEY_ID_OFFSET,
MBEDTLS_LMOTS_I_KEY_ID_LEN );
memcpy( ctx->MBEDTLS_PRIVATE(T_1_pub_key), key + MBEDTLS_LMS_PUBLIC_KEY_ROOT_NODE_OFFSET,
MBEDTLS_LMOTS_N_HASH_LEN );
ctx->MBEDTLS_PRIVATE(have_public_key) = 1;
return( 0 ); return( 0 );
} }
int mbedtls_lms_sign( mbedtls_lms_context *ctx, int mbedtls_lms_verify( const mbedtls_lms_public_t *ctx,
int ( *f_rng)(void *, unsigned char *, size_t), const unsigned char *msg, size_t msg_size,
void* p_rng, unsigned char *msg, unsigned int msg_len, const unsigned char *sig, size_t sig_size )
unsigned char *sig )
{
unsigned int q_leaf_identifier;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ctx == NULL )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( ! ctx->MBEDTLS_PRIVATE(have_privkey) )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( msg == NULL )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( sig == NULL )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( ctx->MBEDTLS_PRIVATE(type) != MBEDTLS_LMS_SHA256_M32_H10 )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( ctx->MBEDTLS_PRIVATE(otstype) != MBEDTLS_LMOTS_SHA256_N32_W8 )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( ctx->MBEDTLS_PRIVATE(q_next_usable_key) >= MERKLE_TREE_LEAF_AM )
{
return( MBEDTLS_ERR_LMS_OUT_OF_PRIV_KEYS );
}
q_leaf_identifier = ctx->MBEDTLS_PRIVATE(q_next_usable_key);
/* This new value must _always_ be written back to the disk before the
* signature is returned.
*/
ctx->MBEDTLS_PRIVATE(q_next_usable_key) += 1;
ret = mbedtls_lmots_sign( &ctx->MBEDTLS_PRIVATE(priv_keys)[q_leaf_identifier],
f_rng, p_rng, msg, msg_len,
sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET );
if( ret )
{
return( ret );
}
val_to_network_bytes( ctx->MBEDTLS_PRIVATE(type), MBEDTLS_LMS_TYPE_LEN,
sig + MBEDTLS_LMS_SIG_TYPE_OFFSET );
val_to_network_bytes( q_leaf_identifier, MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
sig + MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET);
ret = get_merkle_path( ctx, MERKLE_TREE_INTR_AM + q_leaf_identifier,
( unsigned char( * )[32] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) );
if( ret )
{
return( ret );
}
return( 0 );
}
int mbedtls_lms_verify( const mbedtls_lms_context *ctx,
const unsigned char *msg, unsigned int msg_len,
const unsigned char *sig )
{ {
unsigned int q_leaf_identifier; unsigned int q_leaf_identifier;
unsigned char Kc_candidate_ots_pub_key[MBEDTLS_LMOTS_N_HASH_LEN]; unsigned char Kc_candidate_ots_pub_key[MBEDTLS_LMOTS_N_HASH_LEN];
unsigned char Tc_candidate_root_node[32]; unsigned char Tc_candidate_root_node[MBEDTLS_LMS_M_NODE_BYTES];
unsigned int height; unsigned int height;
unsigned int curr_node_id; unsigned int curr_node_id;
unsigned int parent_node_id; unsigned int parent_node_id;
const unsigned char* left_node; const unsigned char* left_node;
const unsigned char* rght_node; const unsigned char* right_node;
mbedtls_lmots_parameters_t ots_params;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ctx == NULL ) if( ! ctx->MBEDTLS_PRIVATE(have_public_key) )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ! ctx->MBEDTLS_PRIVATE(have_pubkey) ) if( sig_size != MBEDTLS_LMS_SIG_LEN )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( msg == NULL) if( ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type)
!= MBEDTLS_LMS_SHA256_M32_H10 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( sig == NULL) if( ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(otstype)
!= MBEDTLS_LMOTS_SHA256_N32_W8 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ctx->MBEDTLS_PRIVATE(type) != MBEDTLS_LMS_SHA256_M32_H10 ) if( network_bytes_to_unsigned_int( MBEDTLS_LMS_TYPE_LEN,
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( ctx->MBEDTLS_PRIVATE(otstype) != MBEDTLS_LMOTS_SHA256_N32_W8 )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( network_bytes_to_val( MBEDTLS_LMS_TYPE_LEN,
sig + MBEDTLS_LMS_SIG_TYPE_OFFSET) != MBEDTLS_LMS_SHA256_M32_H10 ) sig + MBEDTLS_LMS_SIG_TYPE_OFFSET) != MBEDTLS_LMS_SHA256_M32_H10 )
{ {
return( MBEDTLS_ERR_LMS_VERIFY_FAILED ); return( MBEDTLS_ERR_LMS_VERIFY_FAILED );
} }
if( network_bytes_to_val( MBEDTLS_LMOTS_TYPE_LEN, if( network_bytes_to_unsigned_int( MBEDTLS_LMOTS_TYPE_LEN,
sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_SIG_TYPE_OFFSET) sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_SIG_TYPE_OFFSET)
!= MBEDTLS_LMOTS_SHA256_N32_W8 ) != MBEDTLS_LMOTS_SHA256_N32_W8 )
{ {
@ -471,29 +343,39 @@ int mbedtls_lms_verify( const mbedtls_lms_context *ctx,
} }
q_leaf_identifier = network_bytes_to_val( MBEDTLS_LMOTS_Q_LEAF_ID_LEN, q_leaf_identifier = network_bytes_to_unsigned_int( MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
sig + MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET ); sig + MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET );
if( q_leaf_identifier >= MERKLE_TREE_LEAF_AM ) if( q_leaf_identifier >= MERKLE_TREE_LEAF_NODE_AM )
{ {
return( MBEDTLS_ERR_LMS_VERIFY_FAILED ); return( MBEDTLS_ERR_LMS_VERIFY_FAILED );
} }
ret = mbedtls_lmots_generate_pub_key_candidate( ctx->MBEDTLS_PRIVATE(I_key_identifier), memcpy(ots_params.MBEDTLS_PRIVATE(I_key_identifier),
sig + MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET, ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
msg, msg_len, MBEDTLS_LMOTS_I_KEY_ID_LEN);
sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET, unsigned_int_to_network_bytes( q_leaf_identifier,
Kc_candidate_ots_pub_key ); MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
ots_params.MBEDTLS_PRIVATE(q_leaf_identifier) );
ots_params.type = ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(otstype);
ret = mbedtls_lmots_calculate_public_key_candidate( &ots_params, msg, msg_size,
sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET,
MBEDTLS_LMOTS_SIG_LEN,
Kc_candidate_ots_pub_key,
sizeof(Kc_candidate_ots_pub_key),
NULL );
if( ret ) if( ret )
{ {
return( ret ); return( ret );
} }
create_merkle_leaf_node( ctx, Kc_candidate_ots_pub_key, create_merkle_leaf_node(
MERKLE_TREE_INTR_AM + q_leaf_identifier, ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
Tc_candidate_root_node ); Kc_candidate_ots_pub_key, MERKLE_TREE_INTERNAL_NODE_AM + q_leaf_identifier,
Tc_candidate_root_node );
curr_node_id = MERKLE_TREE_INTR_AM + q_leaf_identifier; curr_node_id = MERKLE_TREE_INTERNAL_NODE_AM + q_leaf_identifier;
for( height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT; height++ ) for( height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT; height++ )
{ {
@ -502,17 +384,18 @@ int mbedtls_lms_verify( const mbedtls_lms_context *ctx,
/* Left/right node ordering matters for the hash */ /* Left/right node ordering matters for the hash */
if( curr_node_id & 1 ) if( curr_node_id & 1 )
{ {
left_node = ( ( const unsigned char( * )[32] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) )[height]; left_node = ( ( const unsigned char( * )[MBEDTLS_LMS_M_NODE_BYTES] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) )[height];
rght_node = Tc_candidate_root_node; right_node = Tc_candidate_root_node;
} }
else else
{ {
left_node = Tc_candidate_root_node; left_node = Tc_candidate_root_node;
rght_node = ( ( const unsigned char( * )[32] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) )[height]; right_node = ( ( const unsigned char( * )[MBEDTLS_LMS_M_NODE_BYTES] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) )[height];
} }
create_merkle_intr_node( ctx, left_node, rght_node, parent_node_id, create_merkle_internal_node(
Tc_candidate_root_node); ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
left_node, right_node, parent_node_id, Tc_candidate_root_node);
curr_node_id /= 2; curr_node_id /= 2;
} }
@ -526,115 +409,148 @@ int mbedtls_lms_verify( const mbedtls_lms_context *ctx,
return( 0 ); return( 0 );
} }
int mbedtls_lms_import_pubkey( mbedtls_lms_context *ctx, void mbedtls_lms_init_private( mbedtls_lms_private_t *ctx )
const unsigned char *key )
{ {
mbedtls_lms_algorithm_type_t type; mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) ) ;
mbedtls_lmots_algorithm_type_t otstype; }
if( ctx == NULL ) void mbedtls_lms_free_private( mbedtls_lms_private_t *ctx )
{
unsigned int idx;
if( ctx->MBEDTLS_PRIVATE(have_private_key) )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); for( idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM; idx++ )
{
mbedtls_lmots_free_private( &ctx->MBEDTLS_PRIVATE(ots_private_keys)[idx] );
mbedtls_lmots_free_public( &ctx->MBEDTLS_PRIVATE(ots_public_keys)[idx] );
}
mbedtls_free( ctx->MBEDTLS_PRIVATE(ots_private_keys) );
mbedtls_free( ctx->MBEDTLS_PRIVATE(ots_public_keys) );
} }
if( key == NULL ) mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) );
{ }
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
int mbedtls_lms_generate_private_key( mbedtls_lms_private_t *ctx,
mbedtls_lms_algorithm_type_t type,
mbedtls_lmots_algorithm_type_t otstype,
int (*f_rng)(void *, unsigned char *, size_t),
void* p_rng, unsigned char *seed,
size_t seed_size )
{
unsigned int idx = 0;
unsigned int free_idx = 0;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
type = network_bytes_to_val( MBEDTLS_LMS_TYPE_LEN, key + MBEDTLS_LMS_PUBKEY_TYPE_OFFSET );
if( type != MBEDTLS_LMS_SHA256_M32_H10 ) if( type != MBEDTLS_LMS_SHA256_M32_H10 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
ctx->MBEDTLS_PRIVATE(type) = type;
otstype = network_bytes_to_val( MBEDTLS_LMOTS_TYPE_LEN,
key + MBEDTLS_LMS_PUBKEY_OTSTYPE_OFFSET );
if( otstype != MBEDTLS_LMOTS_SHA256_N32_W8 ) if( otstype != MBEDTLS_LMOTS_SHA256_N32_W8 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
ctx->MBEDTLS_PRIVATE(otstype) = otstype;
memcpy( ctx->MBEDTLS_PRIVATE(I_key_identifier), key + MBEDTLS_LMS_PUBKEY_I_KEY_ID_OFFSET, if( ctx->MBEDTLS_PRIVATE(have_private_key) )
MBEDTLS_LMOTS_I_KEY_ID_LEN ); {
memcpy( ctx->MBEDTLS_PRIVATE(T_1_pub_key), key + MBEDTLS_LMS_PUBKEY_ROOT_NODE_OFFSET, return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
MBEDTLS_LMOTS_N_HASH_LEN ); }
ctx->MBEDTLS_PRIVATE(have_pubkey) = 1; ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type) = type;
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(otstype) = otstype;
f_rng( p_rng,
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
MBEDTLS_LMOTS_I_KEY_ID_LEN );
ctx->MBEDTLS_PRIVATE(ots_private_keys) = mbedtls_calloc( MERKLE_TREE_LEAF_NODE_AM,
sizeof( mbedtls_lmots_private_t));
if( ctx->MBEDTLS_PRIVATE(ots_private_keys) == NULL )
{
ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
goto exit;
}
ctx->MBEDTLS_PRIVATE(ots_public_keys) = mbedtls_calloc( MERKLE_TREE_LEAF_NODE_AM,
sizeof( mbedtls_lmots_public_t));
if( ctx->MBEDTLS_PRIVATE(ots_public_keys) == NULL )
{
ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
goto exit;
}
for( idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM; idx++ )
{
mbedtls_lmots_init_private( &ctx->MBEDTLS_PRIVATE(ots_private_keys)[idx] );
mbedtls_lmots_init_public( &ctx->MBEDTLS_PRIVATE(ots_public_keys)[idx] );
}
for( idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM; idx++ )
{
ret = mbedtls_lmots_generate_private_key( &ctx->MBEDTLS_PRIVATE(ots_private_keys)[idx],
otstype,
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
idx, seed, seed_size );
if( ret)
goto exit;
ret = mbedtls_lmots_calculate_public_key( &ctx->MBEDTLS_PRIVATE(ots_public_keys)[idx],
&ctx->MBEDTLS_PRIVATE(ots_private_keys)[idx] );
if( ret)
goto exit;
}
ctx->MBEDTLS_PRIVATE(q_next_usable_key) = 0;
ctx->MBEDTLS_PRIVATE(have_private_key) = 1;
exit:
if( ret )
{
for ( free_idx = 0; free_idx < idx; free_idx++ ) {
mbedtls_lmots_free_private( &ctx->MBEDTLS_PRIVATE(ots_private_keys)[free_idx] );
mbedtls_lmots_free_public( &ctx->MBEDTLS_PRIVATE(ots_public_keys)[free_idx] );
}
mbedtls_free( ctx->MBEDTLS_PRIVATE(ots_private_keys) );
mbedtls_free( ctx->MBEDTLS_PRIVATE(ots_public_keys) );
return( ret );
}
return( 0 ); return( 0 );
} }
int mbedtls_lms_export_pubkey( mbedtls_lms_context *ctx, int mbedtls_lms_calculate_public_key( mbedtls_lms_public_t *ctx,
unsigned char *key ) mbedtls_lms_private_t *priv_ctx )
{ {
if( ctx == NULL ) unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES];
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( key == NULL )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
if( ! ctx->MBEDTLS_PRIVATE(have_pubkey) )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
val_to_network_bytes( ctx->MBEDTLS_PRIVATE(type),
MBEDTLS_LMS_TYPE_LEN, key + MBEDTLS_LMS_PUBKEY_TYPE_OFFSET );
val_to_network_bytes( ctx->MBEDTLS_PRIVATE(otstype),
MBEDTLS_LMOTS_TYPE_LEN, key + MBEDTLS_LMS_PUBKEY_OTSTYPE_OFFSET );
memcpy( key + MBEDTLS_LMS_PUBKEY_I_KEY_ID_OFFSET,
ctx->MBEDTLS_PRIVATE(I_key_identifier),
MBEDTLS_LMOTS_I_KEY_ID_LEN );
memcpy( key + MBEDTLS_LMS_PUBKEY_ROOT_NODE_OFFSET,
ctx->MBEDTLS_PRIVATE(T_1_pub_key),
MBEDTLS_LMOTS_N_HASH_LEN );
return( 0 );
}
int mbedtls_lms_gen_pubkey( mbedtls_lms_context *ctx )
{
unsigned char tree[MERKLE_TREE_NODE_AM][32];
unsigned int idx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ctx == NULL ) if( ! priv_ctx->MBEDTLS_PRIVATE( have_private_key ) )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ! ctx->MBEDTLS_PRIVATE( have_privkey ) ) if( priv_ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type)
!= MBEDTLS_LMS_SHA256_M32_H10 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ctx->MBEDTLS_PRIVATE(type) != MBEDTLS_LMS_SHA256_M32_H10 ) if( priv_ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(otstype)
!= MBEDTLS_LMOTS_SHA256_N32_W8 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ctx->MBEDTLS_PRIVATE(otstype) != MBEDTLS_LMOTS_SHA256_N32_W8 ) memcpy( &ctx->MBEDTLS_PRIVATE(params), &priv_ctx->MBEDTLS_PRIVATE(params),
{ sizeof(mbedtls_lmots_parameters_t) );
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
for( idx = 0; idx < MERKLE_TREE_LEAF_AM; idx++ ) ret = calculate_merkle_tree( priv_ctx, tree);
{
ret = mbedtls_lmots_gen_pubkey( &ctx->MBEDTLS_PRIVATE(priv_keys)[idx] );
if( ret )
{
return( ret );
}
}
ret = generate_merkle_tree( ctx, tree);
if( ret ) if( ret )
{ {
return( ret ); return( ret );
@ -643,83 +559,112 @@ int mbedtls_lms_gen_pubkey( mbedtls_lms_context *ctx )
/* Root node is always at position 1, due to 1-based indexing */ /* Root node is always at position 1, due to 1-based indexing */
memcpy( ctx->MBEDTLS_PRIVATE(T_1_pub_key), &tree[1], MBEDTLS_LMOTS_N_HASH_LEN ); memcpy( ctx->MBEDTLS_PRIVATE(T_1_pub_key), &tree[1], MBEDTLS_LMOTS_N_HASH_LEN );
ctx->MBEDTLS_PRIVATE(have_pubkey) = 1; ctx->MBEDTLS_PRIVATE(have_public_key) = 1;
return( 0 ); return( 0 );
} }
int mbedtls_lms_gen_privkey( mbedtls_lms_context *ctx,
int ( *f_rng)(void *, unsigned char *, size_t), int mbedtls_lms_export_public_key( mbedtls_lms_public_t *ctx, unsigned char *key,
void* p_rng, unsigned char *seed, size_t key_size, size_t *key_len )
size_t seed_len )
{ {
unsigned int idx; if( key_size < MBEDTLS_LMS_PUBLIC_KEY_LEN ) {
return( MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL );
}
if( ! ctx->MBEDTLS_PRIVATE(have_public_key) )
{
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
}
unsigned_int_to_network_bytes(
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type),
MBEDTLS_LMS_TYPE_LEN, key + MBEDTLS_LMS_PUBLIC_KEY_TYPE_OFFSET );
unsigned_int_to_network_bytes(
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(otstype),
MBEDTLS_LMOTS_TYPE_LEN, key + MBEDTLS_LMS_PUBLIC_KEY_OTSTYPE_OFFSET );
memcpy( key + MBEDTLS_LMS_PUBLIC_KEY_I_KEY_ID_OFFSET,
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
MBEDTLS_LMOTS_I_KEY_ID_LEN );
memcpy( key + MBEDTLS_LMS_PUBLIC_KEY_ROOT_NODE_OFFSET,
ctx->MBEDTLS_PRIVATE(T_1_pub_key),
MBEDTLS_LMOTS_N_HASH_LEN );
if( key_len != NULL ) {
*key_len = MBEDTLS_LMS_PUBLIC_KEY_LEN;
}
return( 0 );
}
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)
{
uint32_t q_leaf_identifier;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ctx == NULL ) if( ! ctx->MBEDTLS_PRIVATE(have_private_key) )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ctx->MBEDTLS_PRIVATE(type) != MBEDTLS_LMS_SHA256_M32_H10 ) if( sig_size < MBEDTLS_LMS_SIG_LEN )
{
return( MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL );
}
if( ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type) != MBEDTLS_LMS_SHA256_M32_H10 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ctx->MBEDTLS_PRIVATE(otstype) != MBEDTLS_LMOTS_SHA256_N32_W8 ) if( ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(otstype)
!= MBEDTLS_LMOTS_SHA256_N32_W8 )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
} }
if( ctx->MBEDTLS_PRIVATE(have_privkey) ) if( ctx->MBEDTLS_PRIVATE(q_next_usable_key) >= MERKLE_TREE_LEAF_NODE_AM )
{ {
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA ); return( MBEDTLS_ERR_LMS_OUT_OF_PRIVATE_KEYS );
}
f_rng( p_rng, ctx->MBEDTLS_PRIVATE(I_key_identifier),
sizeof( ctx->MBEDTLS_PRIVATE(I_key_identifier) ) );
ctx->MBEDTLS_PRIVATE(priv_keys) = mbedtls_calloc( MERKLE_TREE_LEAF_AM,
sizeof( mbedtls_lmots_context));
if( ctx->MBEDTLS_PRIVATE(priv_keys) == NULL )
{
ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
goto out;
}
for( idx = 0; idx < MERKLE_TREE_LEAF_AM; idx++ )
{
mbedtls_lmots_init( &ctx->MBEDTLS_PRIVATE(priv_keys)[idx] );
ret = mbedtls_lmots_set_algorithm_type( &ctx->MBEDTLS_PRIVATE(priv_keys)[idx],
ctx->MBEDTLS_PRIVATE(otstype) );
if( ret)
{
goto out;
}
} }
for( idx = 0; idx < MERKLE_TREE_LEAF_AM; idx++ ) q_leaf_identifier = ctx->MBEDTLS_PRIVATE(q_next_usable_key);
{ /* This new value must _always_ be written back to the disk before the
ret = mbedtls_lmots_gen_privkey( &ctx->MBEDTLS_PRIVATE(priv_keys)[idx], * signature is returned.
ctx->MBEDTLS_PRIVATE(I_key_identifier), */
idx, seed, seed_len ); ctx->MBEDTLS_PRIVATE(q_next_usable_key) += 1;
if( ret)
{
goto out;
}
}
ctx->MBEDTLS_PRIVATE(q_next_usable_key) = 0; ret = mbedtls_lmots_sign( &ctx->MBEDTLS_PRIVATE(ots_private_keys)[q_leaf_identifier],
ctx->MBEDTLS_PRIVATE(have_privkey) = 1; f_rng, p_rng, msg, msg_size,
sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET,
out: MBEDTLS_LMS_SIG_LEN, NULL );
if( ret ) if( ret )
{ {
mbedtls_free( ctx->MBEDTLS_PRIVATE(priv_keys) );
return( ret ); return( ret );
} }
unsigned_int_to_network_bytes( ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type),
MBEDTLS_LMS_TYPE_LEN, sig + MBEDTLS_LMS_SIG_TYPE_OFFSET );
unsigned_int_to_network_bytes( q_leaf_identifier, MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
sig + MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET);
ret = get_merkle_path( ctx, MERKLE_TREE_INTERNAL_NODE_AM + q_leaf_identifier,
( unsigned char( * )[MBEDTLS_LMS_M_NODE_BYTES] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) );
if( ret )
{
return( ret );
}
if( sig_len != NULL ) {
*sig_len = MBEDTLS_LMS_SIG_LEN;
}
return( 0 ); return( 0 );
} }

View File

@ -15,7 +15,8 @@
/* BEGIN_CASE */ /* BEGIN_CASE */
void lmots_sign_verify_test ( data_t * msg ) void lmots_sign_verify_test ( data_t * msg )
{ {
mbedtls_lmots_context ctx; mbedtls_lmots_public_t pub_ctx;
mbedtls_lmots_private_t priv_ctx;
unsigned char sig[MBEDTLS_LMOTS_SIG_LEN]; unsigned char sig[MBEDTLS_LMOTS_SIG_LEN];
mbedtls_entropy_context entropy_ctx; mbedtls_entropy_context entropy_ctx;
mbedtls_ctr_drbg_context drbg_ctx; mbedtls_ctr_drbg_context drbg_ctx;
@ -23,22 +24,25 @@ void lmots_sign_verify_test ( data_t * msg )
mbedtls_entropy_init( &entropy_ctx ); mbedtls_entropy_init( &entropy_ctx );
mbedtls_ctr_drbg_init( &drbg_ctx ); mbedtls_ctr_drbg_init( &drbg_ctx );
mbedtls_lmots_init( &ctx ); mbedtls_lmots_init_public( &pub_ctx );
mbedtls_lmots_init_private( &priv_ctx );
TEST_ASSERT( mbedtls_ctr_drbg_seed( &drbg_ctx, mbedtls_entropy_func, TEST_ASSERT( mbedtls_ctr_drbg_seed( &drbg_ctx, mbedtls_entropy_func,
&entropy_ctx, (uint8_t*)"", 0 ) == 0 ); &entropy_ctx, (uint8_t*)"", 0 ) == 0 );
TEST_ASSERT( mbedtls_ctr_drbg_random( &drbg_ctx, seed, sizeof( seed ) ) == 0 ); TEST_ASSERT( mbedtls_ctr_drbg_random( &drbg_ctx, seed, sizeof( seed ) ) == 0 );
TEST_ASSERT( mbedtls_lmots_set_algorithm_type(&ctx, MBEDTLS_LMOTS_SHA256_N32_W8) == 0 ); TEST_ASSERT( mbedtls_lmots_generate_private_key(&priv_ctx, MBEDTLS_LMOTS_SHA256_N32_W8,
TEST_ASSERT( mbedtls_lmots_gen_privkey(&ctx, (uint8_t[16]){0}, 0x12, seed, sizeof( seed ) ) == 0 ); (uint8_t[16]){0}, 0x12, seed, sizeof( seed ) ) == 0 );
TEST_ASSERT( mbedtls_lmots_gen_pubkey(&ctx) == 0 ); TEST_ASSERT( mbedtls_lmots_calculate_public_key(&pub_ctx, &priv_ctx) == 0 );
TEST_ASSERT( mbedtls_lmots_sign(&ctx, mbedtls_ctr_drbg_random, &drbg_ctx, msg->x, msg->len, sig ) == 0 ); TEST_ASSERT( mbedtls_lmots_sign(&priv_ctx, mbedtls_ctr_drbg_random, &drbg_ctx,
TEST_ASSERT( mbedtls_lmots_verify(&ctx, msg->x, msg->len, sig) == 0 ); msg->x, msg->len, sig, sizeof(sig), NULL ) == 0 );
TEST_ASSERT( mbedtls_lmots_verify(&pub_ctx, msg->x, msg->len, sig, sizeof(sig)) == 0 );
exit: exit:
mbedtls_entropy_free( &entropy_ctx ); mbedtls_entropy_free( &entropy_ctx );
mbedtls_ctr_drbg_free( &drbg_ctx ); mbedtls_ctr_drbg_free( &drbg_ctx );
mbedtls_lmots_free( &ctx ); mbedtls_lmots_free_public( &pub_ctx );
mbedtls_lmots_free_private( &priv_ctx );
} }
/* END_CASE */ /* END_CASE */
@ -46,40 +50,40 @@ exit:
void lmots_verify_test ( data_t * msg, data_t * sig, data_t * pub_key, void lmots_verify_test ( data_t * msg, data_t * sig, data_t * pub_key,
int expected_rc ) int expected_rc )
{ {
mbedtls_lmots_context ctx; mbedtls_lmots_public_t ctx;
mbedtls_lmots_init( &ctx ); mbedtls_lmots_init_public( &ctx );
mbedtls_lmots_import_pubkey( &ctx, pub_key->x ); mbedtls_lmots_import_public_key( &ctx, pub_key->x, pub_key->len );
TEST_ASSERT(mbedtls_lmots_verify( &ctx, msg->x, msg->len, sig->x ) == expected_rc ); TEST_ASSERT(mbedtls_lmots_verify( &ctx, msg->x, msg->len, sig->x, sig->len ) == expected_rc );
exit: exit:
mbedtls_lmots_free( &ctx ); mbedtls_lmots_free_public( &ctx );
} }
/* END_CASE */ /* END_CASE */
/* BEGIN_CASE */ /* BEGIN_CASE */
void lmots_import_export_test ( data_t * pub_key ) void lmots_import_export_test ( data_t * pub_key )
{ {
mbedtls_lmots_context ctx; mbedtls_lmots_public_t ctx;
uint8_t exported_pub_key[MBEDTLS_LMOTS_PUBKEY_LEN]; uint8_t exported_pub_key[MBEDTLS_LMOTS_PUBLIC_KEY_LEN];
mbedtls_lmots_init( &ctx ); mbedtls_lmots_init_public( &ctx );
TEST_ASSERT( mbedtls_lmots_import_pubkey( &ctx, pub_key->x ) == 0 ); TEST_ASSERT( mbedtls_lmots_import_public_key( &ctx, pub_key->x, pub_key->len ) == 0 );
TEST_ASSERT( mbedtls_lmots_export_pubkey( &ctx, exported_pub_key ) == 0 ); TEST_ASSERT( mbedtls_lmots_export_public_key( &ctx, exported_pub_key, sizeof( exported_pub_key ), NULL ) == 0 );
TEST_ASSERT( memcmp( pub_key->x, exported_pub_key, MBEDTLS_LMOTS_PUBKEY_LEN ) == 0 ); TEST_ASSERT( memcmp( pub_key->x, exported_pub_key, MBEDTLS_LMOTS_PUBLIC_KEY_LEN ) == 0 );
exit: exit:
mbedtls_lmots_free( &ctx ); mbedtls_lmots_free_public( &ctx );
} }
/* END_CASE */ /* END_CASE */
/* BEGIN_CASE */ /* BEGIN_CASE */
void lmots_reuse_test ( data_t * msg ) void lmots_reuse_test ( data_t * msg )
{ {
mbedtls_lmots_context ctx; mbedtls_lmots_private_t ctx;
unsigned char sig[MBEDTLS_LMOTS_SIG_LEN]; unsigned char sig[MBEDTLS_LMOTS_SIG_LEN];
mbedtls_entropy_context entropy_ctx; mbedtls_entropy_context entropy_ctx;
mbedtls_ctr_drbg_context drbg_ctx; mbedtls_ctr_drbg_context drbg_ctx;
@ -92,19 +96,21 @@ void lmots_reuse_test ( data_t * msg )
mbedtls_ctr_drbg_random( &drbg_ctx, seed, sizeof( seed ) ); mbedtls_ctr_drbg_random( &drbg_ctx, seed, sizeof( seed ) );
mbedtls_lmots_init( &ctx ); mbedtls_lmots_init_private( &ctx );
TEST_ASSERT( mbedtls_lmots_set_algorithm_type( &ctx, MBEDTLS_LMOTS_SHA256_N32_W8 ) == 0 ); TEST_ASSERT( mbedtls_lmots_generate_private_key(&ctx, MBEDTLS_LMOTS_SHA256_N32_W8,
TEST_ASSERT( mbedtls_lmots_gen_privkey(&ctx, (uint8_t[16]){0}, 0x12, seed, sizeof( seed ) ) == 0 ); (uint8_t[16]){0}, 0x12, seed, sizeof( seed ) ) == 0 );
TEST_ASSERT( mbedtls_lmots_sign(&ctx, mbedtls_ctr_drbg_random, &drbg_ctx, msg->x, msg->len, sig ) == 0 ); TEST_ASSERT( mbedtls_lmots_sign(&ctx, mbedtls_ctr_drbg_random, &drbg_ctx,
msg->x, msg->len, sig, sizeof( sig ), NULL ) == 0 );
/* Running another sign operation should fail, since the key should now have /* Running another sign operation should fail, since the key should now have
* been erased. * been erased.
*/ */
TEST_ASSERT( mbedtls_lmots_sign(&ctx, mbedtls_ctr_drbg_random, &drbg_ctx, msg->x, msg->len, sig ) != 0 ); TEST_ASSERT( mbedtls_lmots_sign(&ctx, mbedtls_ctr_drbg_random, &drbg_ctx,
msg->x, msg->len, sig, sizeof( sig ), NULL ) != 0 );
exit: exit:
mbedtls_entropy_free( &entropy_ctx ); mbedtls_entropy_free( &entropy_ctx );
mbedtls_ctr_drbg_free( &drbg_ctx ); mbedtls_ctr_drbg_free( &drbg_ctx );
mbedtls_lmots_free( &ctx ); mbedtls_lmots_free_private( &ctx );
} }
/* END_CASE */ /* END_CASE */

View File

@ -13,7 +13,8 @@
/* BEGIN_CASE */ /* BEGIN_CASE */
void lms_sign_verify_test ( data_t * msg ) void lms_sign_verify_test ( data_t * msg )
{ {
mbedtls_lms_context ctx; mbedtls_lms_public_t pub_ctx;
mbedtls_lms_private_t priv_ctx;
unsigned char sig[MBEDTLS_LMS_SIG_LEN]; unsigned char sig[MBEDTLS_LMS_SIG_LEN];
mbedtls_entropy_context entropy_ctx; mbedtls_entropy_context entropy_ctx;
mbedtls_ctr_drbg_context drbg_ctx; mbedtls_ctr_drbg_context drbg_ctx;
@ -22,29 +23,35 @@ void lms_sign_verify_test ( data_t * msg )
mbedtls_entropy_init( &entropy_ctx ); mbedtls_entropy_init( &entropy_ctx );
mbedtls_ctr_drbg_init( &drbg_ctx ); mbedtls_ctr_drbg_init( &drbg_ctx );
mbedtls_lms_init( &ctx ); mbedtls_lms_init_public( &pub_ctx );
mbedtls_lms_init_private( &priv_ctx );
TEST_ASSERT( mbedtls_ctr_drbg_seed( &drbg_ctx, mbedtls_entropy_func, TEST_ASSERT( mbedtls_ctr_drbg_seed( &drbg_ctx, mbedtls_entropy_func,
&entropy_ctx, ( uint8_t* )"", 0 ) == 0 ); &entropy_ctx, ( uint8_t* )"", 0 ) == 0 );
TEST_ASSERT( mbedtls_ctr_drbg_random( &drbg_ctx, seed, sizeof( seed ) ) == 0 ); TEST_ASSERT( mbedtls_ctr_drbg_random( &drbg_ctx, seed, sizeof( seed ) ) == 0 );
TEST_ASSERT( mbedtls_lms_set_algorithm_type( &ctx, MBEDTLS_LMS_SHA256_M32_H10, MBEDTLS_LMOTS_SHA256_N32_W8 ) == 0 );
/* Allocation failure isn't a test failure, since it likely just means there's not enough memory to run the test */ /* Allocation failure isn't a test failure, since it likely just means there's not enough memory to run the test */
rc = mbedtls_lms_gen_privkey( &ctx, mbedtls_ctr_drbg_random, &drbg_ctx, seed, sizeof( seed ) ); rc = mbedtls_lms_generate_private_key( &priv_ctx, MBEDTLS_LMS_SHA256_M32_H10,
MBEDTLS_LMOTS_SHA256_N32_W8,
mbedtls_ctr_drbg_random, &drbg_ctx, seed,
sizeof( seed ) );
TEST_ASSUME( rc != MBEDTLS_ERR_LMS_ALLOC_FAILED ); TEST_ASSUME( rc != MBEDTLS_ERR_LMS_ALLOC_FAILED );
TEST_ASSERT( rc == 0 ); TEST_ASSERT( rc == 0 );
TEST_ASSERT( mbedtls_lms_gen_pubkey( &ctx) == 0 ); TEST_ASSERT( mbedtls_lms_calculate_public_key( &pub_ctx, &priv_ctx ) == 0 );
TEST_ASSERT( mbedtls_lms_sign( &ctx, mbedtls_ctr_drbg_random, &drbg_ctx, msg->x, msg->len, sig ) == 0 ); TEST_ASSERT( mbedtls_lms_sign( &priv_ctx, mbedtls_ctr_drbg_random,
&drbg_ctx, msg->x, msg->len, sig,
sizeof( sig ), NULL ) == 0 );
TEST_ASSERT( mbedtls_lms_verify( &ctx, msg->x, msg->len, sig) == 0 ); TEST_ASSERT( mbedtls_lms_verify( &pub_ctx, msg->x, msg->len, sig,
sizeof( sig ) ) == 0 );
exit: exit:
mbedtls_entropy_free( &entropy_ctx ); mbedtls_entropy_free( &entropy_ctx );
mbedtls_ctr_drbg_free( &drbg_ctx ); mbedtls_ctr_drbg_free( &drbg_ctx );
mbedtls_lms_free( &ctx ); mbedtls_lms_free_public( &pub_ctx );
mbedtls_lms_free_private( &priv_ctx );
} }
/* END_CASE */ /* END_CASE */
@ -52,34 +59,35 @@ exit:
void lms_verify_test ( data_t * msg, data_t * sig, data_t * pub_key, void lms_verify_test ( data_t * msg, data_t * sig, data_t * pub_key,
int expected_rc ) int expected_rc )
{ {
mbedtls_lms_context ctx; mbedtls_lms_public_t ctx;
mbedtls_lms_init( &ctx); mbedtls_lms_init_public( &ctx);
mbedtls_lms_import_pubkey( &ctx, pub_key->x ); mbedtls_lms_import_public_key( &ctx, pub_key->x, pub_key->len );
TEST_ASSERT( mbedtls_lms_verify( &ctx, msg->x, msg->len, sig->x ) == expected_rc ); TEST_ASSERT( mbedtls_lms_verify( &ctx, msg->x, msg->len, sig->x, sig->len ) == expected_rc );
exit: exit:
mbedtls_lms_free( &ctx ); mbedtls_lms_free_public( &ctx );
} }
/* END_CASE */ /* END_CASE */
/* BEGIN_CASE */ /* BEGIN_CASE */
void lms_import_export_test ( data_t * pub_key ) void lms_import_export_test ( data_t * pub_key )
{ {
mbedtls_lms_context ctx; mbedtls_lms_public_t ctx;
uint8_t exported_pub_key[MBEDTLS_LMS_PUBKEY_LEN]; uint8_t exported_pub_key[MBEDTLS_LMS_PUBLIC_KEY_LEN];
mbedtls_lms_init(&ctx); mbedtls_lms_init_public(&ctx);
TEST_ASSERT( mbedtls_lms_import_pubkey( &ctx, pub_key->x ) == 0 ); TEST_ASSERT( mbedtls_lms_import_public_key( &ctx, pub_key->x, pub_key->len ) == 0 );
TEST_ASSERT( mbedtls_lms_export_pubkey( &ctx, exported_pub_key) == 0 ); TEST_ASSERT( mbedtls_lms_export_public_key( &ctx, exported_pub_key,
sizeof(exported_pub_key), NULL ) == 0 );
ASSERT_COMPARE( pub_key->x, MBEDTLS_LMS_PUBKEY_LEN, ASSERT_COMPARE( pub_key->x, MBEDTLS_LMS_PUBLIC_KEY_LEN,
exported_pub_key, MBEDTLS_LMS_PUBKEY_LEN ); exported_pub_key, MBEDTLS_LMS_PUBLIC_KEY_LEN );
exit: exit:
mbedtls_lms_free( &ctx ); mbedtls_lms_free_public( &ctx );
} }
/* END_CASE */ /* END_CASE */