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:
parent
c8f9604d7b
commit
01c71a17b3
6 changed files with 1238 additions and 1219 deletions
|
@ -32,33 +32,24 @@
|
|||
|
||||
#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_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_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_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_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 + \
|
||||
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)
|
||||
|
||||
#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
|
||||
extern "C" {
|
||||
|
@ -72,85 +63,234 @@ typedef enum {
|
|||
} 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
|
||||
* be imported, or an algorithm type set, a private key generated and the public
|
||||
* 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.
|
||||
* be imported or generated from a private context.
|
||||
*
|
||||
* \dot
|
||||
* digraph lmots {
|
||||
* digraph lms_public_t {
|
||||
* UNINITIALIZED -> INIT [label="init"];
|
||||
* TYPE_SET -> INIT [label="free"];
|
||||
* PRIVATE -> INIT [label="free"];
|
||||
* PUBLIC -> INIT [label="free"];
|
||||
* "PRIVATE+PUBLIC" -> INIT [label="free"];
|
||||
* 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"];
|
||||
* HAVE_PUBLIC_KEY -> INIT [label="free"];
|
||||
* INIT -> HAVE_PUBLIC_KEY [label="import_public_key"];
|
||||
* INIT -> HAVE_PUBLIC_KEY [label="calculate_public_key from private key"];
|
||||
* HAVE_PUBLIC_KEY -> HAVE_PUBLIC_KEY [label="export_public_key"];
|
||||
* }
|
||||
* \enddot
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char MBEDTLS_PRIVATE(have_privkey); /*!< Whether the context contains a private key.
|
||||
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. */
|
||||
mbedtls_lms_parameters_t MBEDTLS_PRIVATE(params);
|
||||
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. */
|
||||
} 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
|
||||
* 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
|
||||
* 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
|
||||
* for keygen operations etc.
|
||||
* \note Before this function is called, the context must
|
||||
* have been initialized.
|
||||
*
|
||||
* \param ctx The initialized LMS context.
|
||||
* \param type The type that will be set in the context.
|
||||
* \param otstype The type of the LMOTS implementation used by this
|
||||
* context.
|
||||
* \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_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,
|
||||
mbedtls_lms_algorithm_type_t type,
|
||||
mbedtls_lmots_algorithm_type_t otstype);
|
||||
int mbedtls_lms_import_public_key( mbedtls_lms_public_t *ctx,
|
||||
const unsigned char *key, size_t key_size );
|
||||
|
||||
/**
|
||||
* \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
|
||||
* LMOTS context that contains a private key.
|
||||
* LMS context that contains unused private keys.
|
||||
*
|
||||
* \warning This function is **not intended for use in
|
||||
* 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
|
||||
* 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.
|
||||
* \param f_rng The RNG function to be used for signature
|
||||
* generation.
|
||||
* \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_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.
|
||||
* 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 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),
|
||||
void* p_rng, unsigned char *msg, unsigned int msg_len,
|
||||
unsigned char *sig);
|
||||
|
||||
/**
|
||||
* \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 );
|
||||
void* p_rng, unsigned char *msg, unsigned int msg_size,
|
||||
unsigned char *sig, size_t sig_size, size_t *sig_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
835
library/lmots.c
835
library/lmots.c
File diff suppressed because it is too large
Load diff
419
library/lmots.h
419
library/lmots.h
|
@ -26,7 +26,7 @@
|
|||
#ifndef MBEDTLS_LMOTS_H
|
||||
#define MBEDTLS_LMOTS_H
|
||||
|
||||
#include "mbedtls/private_access.h"
|
||||
#include "mbedtls/build_info.h"
|
||||
|
||||
#include "psa/crypto.h"
|
||||
|
||||
|
@ -34,27 +34,19 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#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_C_RANDOM_VALUE_LEN (MBEDTLS_LMOTS_N_HASH_LEN)
|
||||
#define MBEDTLS_LMOTS_I_KEY_ID_LEN (16)
|
||||
#define MBEDTLS_LMOTS_Q_LEAF_ID_LEN (4)
|
||||
|
||||
#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)
|
||||
|
||||
#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)
|
||||
|
||||
#define MBEDTLS_LMOTS_SIG_TYPE_OFFSET (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -68,54 +60,93 @@ typedef enum {
|
|||
} 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
|
||||
* be imported, or an algorithm type set, a private key generated and the public
|
||||
* 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.
|
||||
* be imported or generated from a private context.
|
||||
*
|
||||
* \dot
|
||||
* digraph lmots {
|
||||
* digraph lmots_public_t {
|
||||
* UNINITIALIZED -> INIT [label="init"];
|
||||
* TYPE_SET -> INIT [label="free"];
|
||||
* PRIVATE -> INIT [label="free"];
|
||||
* PUBLIC -> INIT [label="free"];
|
||||
* "PRIVATE+PUBLIC" -> INIT [label="free"];
|
||||
* 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"];
|
||||
* HAVE_PUBLIC_KEY -> INIT [label="free"];
|
||||
* INIT -> HAVE_PUBLIC_KEY [label="import_public_key"];
|
||||
* INIT -> HAVE_PUBLIC_KEY [label="calculate_public_key from private key"];
|
||||
* HAVE_PUBLIC_KEY -> HAVE_PUBLIC_KEY [label="export_public_key"];
|
||||
* }
|
||||
* \enddot
|
||||
*/
|
||||
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. */
|
||||
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. */
|
||||
unsigned char MBEDTLS_PRIVATE(I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN]); /*!< The key
|
||||
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. */
|
||||
unsigned char MBEDTLS_PRIVATE(q_leaf_identifier_bytes)[MBEDTLS_LMOTS_Q_LEAF_ID_LEN];/*!< The
|
||||
leaf identifier in network bytes form. */
|
||||
mbedtls_lmots_algorithm_type_t MBEDTLS_PRIVATE(type); /*!< The LM-OTS key type identifier as
|
||||
per IANA. Only SHA256_N32_W8 is currently
|
||||
supported. */
|
||||
unsigned char MBEDTLS_PRIVATE(priv_key[MBEDTLS_LMOTS_P_SIG_SYMBOL_LEN][32]); /*!< The private
|
||||
key, one hash output per byte of the encoded
|
||||
symbol string P (32 bytes of hash output +
|
||||
2 bytes of checksum). */
|
||||
unsigned char MBEDTLS_PRIVATE(pub_key[32]); /*!< The public key, in the form of a SHA256
|
||||
output. */
|
||||
} mbedtls_lmots_context;
|
||||
} mbedtls_lmots_private_t;
|
||||
|
||||
/**
|
||||
* \brief This function converts an unsigned int into a
|
||||
* network-byte-order (big endian) string.
|
||||
*
|
||||
* \param val The unsigned integer value
|
||||
* \param len The length of the string.
|
||||
* \param bytes The string to output into.
|
||||
*
|
||||
* \return The corresponding LMS error code.
|
||||
*/
|
||||
void unsigned_int_to_network_bytes(unsigned int val, size_t len, unsigned char *bytes);
|
||||
|
||||
/**
|
||||
* \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
|
||||
|
@ -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
|
||||
* 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
|
||||
* 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
|
||||
* for keygen operations etc.
|
||||
* \note Before this function is called, the context must
|
||||
* have been initialized.
|
||||
*
|
||||
* \param ctx The initialized LMOTS context.
|
||||
* \param type The type that will be set in the context.
|
||||
* \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_PUBLIC_KEY_LEN bytes will be read from
|
||||
* this.
|
||||
*
|
||||
* \return \c 0 on success.
|
||||
* \return A non-zero error code on failure.
|
||||
*/
|
||||
int mbedtls_lmots_set_algorithm_type( mbedtls_lmots_context *ctx,
|
||||
mbedtls_lmots_algorithm_type_t type );
|
||||
int mbedtls_lmots_import_public_key( mbedtls_lmots_public_t *ctx,
|
||||
const unsigned char *key, size_t key_size );
|
||||
|
||||
/**
|
||||
* \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
|
||||
* signature verification.
|
||||
*
|
||||
* \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 params The LMOTS parameter set, q and I values as an
|
||||
* mbedtls_lmots_parameters_t struct.
|
||||
* \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.
|
||||
* #MBEDTLS_LMOTS_SIG_LEN bytes will be read from this.
|
||||
* \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 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],
|
||||
const unsigned char q_leaf_identifier[MBEDTLS_LMOTS_Q_LEAF_ID_LEN],
|
||||
const unsigned char *msg,
|
||||
size_t msg_len,
|
||||
const unsigned char *sig,
|
||||
unsigned char *out );
|
||||
int mbedtls_lmots_calculate_public_key_candidate( const mbedtls_lmots_parameters_t *params,
|
||||
const unsigned char *msg,
|
||||
size_t msg_size,
|
||||
const unsigned char *sig,
|
||||
size_t sig_size,
|
||||
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
|
||||
* 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.
|
||||
* \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_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.
|
||||
* Must be at least #MBEDTLS_LMOTS_SIG_LEN in size.
|
||||
*
|
||||
* \return \c 0 on success.
|
||||
* \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),
|
||||
void *p_rng, const unsigned char *msg, size_t msg_len,
|
||||
unsigned char *sig );
|
||||
void *p_rng, const unsigned char *msg, size_t msg_size,
|
||||
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
|
||||
}
|
||||
|
|
701
library/lms.c
701
library/lms.c
|
@ -54,45 +54,33 @@
|
|||
#define mbedtls_free free
|
||||
#endif
|
||||
|
||||
#define MERKLE_TREE_NODE_AM (1 << (MBEDTLS_LMS_H_TREE_HEIGHT + 1))
|
||||
#define MERKLE_TREE_LEAF_AM (1 << MBEDTLS_LMS_H_TREE_HEIGHT)
|
||||
#define MERKLE_TREE_INTR_AM (1 << MBEDTLS_LMS_H_TREE_HEIGHT)
|
||||
#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_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)
|
||||
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)
|
||||
#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,
|
||||
static int create_merkle_leaf_node( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
|
||||
unsigned char pub_key[MBEDTLS_LMOTS_N_HASH_LEN],
|
||||
unsigned int r_node_idx,
|
||||
unsigned char out[32] )
|
||||
unsigned char out[MBEDTLS_LMS_M_NODE_BYTES] )
|
||||
{
|
||||
psa_hash_operation_t op;
|
||||
psa_status_t status;
|
||||
size_t output_hash_len;
|
||||
unsigned char D_LEAF_bytes[D_CONST_LEN];
|
||||
unsigned char r_node_idx_bytes[4];
|
||||
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 );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if ( ret != 0 )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
status = psa_hash_update( &op, ctx->MBEDTLS_PRIVATE(I_key_identifier),
|
||||
MBEDTLS_LMOTS_I_KEY_ID_LEN );
|
||||
status = psa_hash_update( &op, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
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 );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
val_to_network_bytes( D_LEAF_CONSTANT, D_CONST_LEN, D_LEAF_bytes );
|
||||
status = psa_hash_update( &op, D_LEAF_bytes, D_CONST_LEN );
|
||||
status = psa_hash_update( &op, D_LEAF_CONSTANT_BYTES, D_CONST_LEN );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
status = psa_hash_update( &op, pub_key, MBEDTLS_LMOTS_N_HASH_LEN );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
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 );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
out:
|
||||
exit:
|
||||
psa_hash_abort( &op );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
|
||||
static int create_merkle_intr_node( const mbedtls_lms_context *ctx,
|
||||
const unsigned char left_node[32],
|
||||
const unsigned char rght_node[32],
|
||||
unsigned int r_node_idx,
|
||||
unsigned char out[32] )
|
||||
static int create_merkle_internal_node( const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
|
||||
const unsigned char left_node[MBEDTLS_LMS_M_NODE_BYTES],
|
||||
const unsigned char right_node[MBEDTLS_LMS_M_NODE_BYTES],
|
||||
unsigned int r_node_idx,
|
||||
unsigned char out[MBEDTLS_LMS_M_NODE_BYTES] )
|
||||
{
|
||||
psa_hash_operation_t op;
|
||||
psa_status_t status;
|
||||
size_t output_hash_len;
|
||||
unsigned char D_INTR_bytes[D_CONST_LEN];
|
||||
unsigned char r_node_idx_bytes[4];
|
||||
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 );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if ( ret != 0 )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
status = psa_hash_update( &op, ctx->MBEDTLS_PRIVATE(I_key_identifier),
|
||||
MBEDTLS_LMOTS_I_KEY_ID_LEN );
|
||||
status = psa_hash_update( &op, I_key_identifier, MBEDTLS_LMOTS_I_KEY_ID_LEN );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
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 );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
val_to_network_bytes( D_INTR_CONSTANT, D_CONST_LEN, D_INTR_bytes );
|
||||
status = psa_hash_update( &op, D_INTR_bytes, D_CONST_LEN );
|
||||
status = psa_hash_update( &op, D_INTERNAL_CONSTANT_BYTES, D_CONST_LEN );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
status = psa_hash_update( &op, left_node, MBEDTLS_LMOTS_N_HASH_LEN );
|
||||
ret = mbedtls_lms_error_from_psa( status );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
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 );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
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 );
|
||||
if( ret )
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
goto exit;
|
||||
|
||||
out:
|
||||
exit:
|
||||
psa_hash_abort( &op );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int generate_merkle_tree( mbedtls_lms_context *ctx,
|
||||
unsigned char tree[MERKLE_TREE_NODE_AM][32] )
|
||||
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_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,
|
||||
r_node_idx, tree[r_node_idx] );
|
||||
ret = create_merkle_leaf_node(
|
||||
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 )
|
||||
{
|
||||
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
|
||||
* 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)],
|
||||
tree[(r_node_idx * 2 + 1)],
|
||||
r_node_idx, tree[r_node_idx] );
|
||||
ret = create_merkle_internal_node(
|
||||
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(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 );
|
||||
|
@ -256,18 +217,17 @@ static int generate_merkle_tree( mbedtls_lms_context *ctx,
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
static int get_merkle_path( mbedtls_lms_context *ctx,
|
||||
unsigned int leaf_node_id, unsigned char path[MBEDTLS_LMS_H_TREE_HEIGHT][32] )
|
||||
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][32];
|
||||
unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES];
|
||||
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 height;
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
|
||||
ret = generate_merkle_tree( ctx, tree);
|
||||
ret = calculate_merkle_tree( ctx, tree);
|
||||
if( 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++ )
|
||||
{
|
||||
parent_node_id = ( curr_node_id / 2 );
|
||||
|
||||
/* 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 );
|
||||
adjacent_node_id = curr_node_id ^ 1;
|
||||
|
||||
memcpy( &path[height], &tree[adjacent_node_id], MBEDTLS_LMOTS_N_HASH_LEN );
|
||||
|
||||
curr_node_id = parent_node_id;
|
||||
curr_node_id >>=1;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
void mbedtls_lms_init( mbedtls_lms_context *ctx )
|
||||
void mbedtls_lms_init_public( mbedtls_lms_public_t *ctx )
|
||||
{
|
||||
if( ctx == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_context ) ) ;
|
||||
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) ) ;
|
||||
}
|
||||
|
||||
void mbedtls_lms_free( mbedtls_lms_context *ctx )
|
||||
void mbedtls_lms_free_public( mbedtls_lms_public_t *ctx )
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
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 ) );
|
||||
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) );
|
||||
}
|
||||
|
||||
int mbedtls_lms_set_algorithm_type( mbedtls_lms_context *ctx,
|
||||
mbedtls_lms_algorithm_type_t type,
|
||||
mbedtls_lmots_algorithm_type_t otstype )
|
||||
int mbedtls_lms_import_public_key( mbedtls_lms_public_t *ctx,
|
||||
const unsigned char *key, size_t key_size )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type) = type;
|
||||
|
||||
ctx->MBEDTLS_PRIVATE(type) = type;
|
||||
ctx->MBEDTLS_PRIVATE(otstype) = otstype;
|
||||
otstype = network_bytes_to_unsigned_int( MBEDTLS_LMOTS_TYPE_LEN,
|
||||
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 );
|
||||
}
|
||||
|
||||
int mbedtls_lms_sign( mbedtls_lms_context *ctx,
|
||||
int ( *f_rng)(void *, unsigned char *, size_t),
|
||||
void* p_rng, unsigned char *msg, unsigned int msg_len,
|
||||
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 )
|
||||
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 )
|
||||
{
|
||||
unsigned int q_leaf_identifier;
|
||||
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 curr_node_id;
|
||||
unsigned int parent_node_id;
|
||||
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;
|
||||
|
||||
if( ctx == NULL )
|
||||
if( ! ctx->MBEDTLS_PRIVATE(have_public_key) )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
if( msg == NULL)
|
||||
if( ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(type)
|
||||
!= MBEDTLS_LMS_SHA256_M32_H10 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
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( network_bytes_to_val( MBEDTLS_LMS_TYPE_LEN,
|
||||
if( network_bytes_to_unsigned_int( MBEDTLS_LMS_TYPE_LEN,
|
||||
sig + MBEDTLS_LMS_SIG_TYPE_OFFSET) != MBEDTLS_LMS_SHA256_M32_H10 )
|
||||
{
|
||||
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)
|
||||
!= 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 );
|
||||
|
||||
if( q_leaf_identifier >= MERKLE_TREE_LEAF_AM )
|
||||
if( q_leaf_identifier >= MERKLE_TREE_LEAF_NODE_AM )
|
||||
{
|
||||
return( MBEDTLS_ERR_LMS_VERIFY_FAILED );
|
||||
}
|
||||
|
||||
ret = mbedtls_lmots_generate_pub_key_candidate( ctx->MBEDTLS_PRIVATE(I_key_identifier),
|
||||
sig + MBEDTLS_LMS_SIG_Q_LEAF_ID_OFFSET,
|
||||
msg, msg_len,
|
||||
sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET,
|
||||
Kc_candidate_ots_pub_key );
|
||||
memcpy(ots_params.MBEDTLS_PRIVATE(I_key_identifier),
|
||||
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
|
||||
MBEDTLS_LMOTS_I_KEY_ID_LEN);
|
||||
unsigned_int_to_network_bytes( q_leaf_identifier,
|
||||
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 )
|
||||
{
|
||||
return( ret );
|
||||
}
|
||||
|
||||
create_merkle_leaf_node( ctx, Kc_candidate_ots_pub_key,
|
||||
MERKLE_TREE_INTR_AM + q_leaf_identifier,
|
||||
Tc_candidate_root_node );
|
||||
create_merkle_leaf_node(
|
||||
ctx->MBEDTLS_PRIVATE(params).MBEDTLS_PRIVATE(I_key_identifier),
|
||||
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++ )
|
||||
{
|
||||
|
@ -502,17 +384,18 @@ int mbedtls_lms_verify( const mbedtls_lms_context *ctx,
|
|||
/* Left/right node ordering matters for the hash */
|
||||
if( curr_node_id & 1 )
|
||||
{
|
||||
left_node = ( ( const unsigned char( * )[32] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) )[height];
|
||||
rght_node = Tc_candidate_root_node;
|
||||
left_node = ( ( const unsigned char( * )[MBEDTLS_LMS_M_NODE_BYTES] )( sig + MBEDTLS_LMS_SIG_PATH_OFFSET ) )[height];
|
||||
right_node = Tc_candidate_root_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
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,
|
||||
Tc_candidate_root_node);
|
||||
create_merkle_internal_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;
|
||||
}
|
||||
|
@ -526,115 +409,148 @@ int mbedtls_lms_verify( const mbedtls_lms_context *ctx,
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
int mbedtls_lms_import_pubkey( mbedtls_lms_context *ctx,
|
||||
const unsigned char *key )
|
||||
void mbedtls_lms_init_private( mbedtls_lms_private_t *ctx )
|
||||
{
|
||||
mbedtls_lms_algorithm_type_t type;
|
||||
mbedtls_lmots_algorithm_type_t otstype;
|
||||
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) ) ;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
|
||||
}
|
||||
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lms_public_t ) );
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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,
|
||||
MBEDTLS_LMOTS_I_KEY_ID_LEN );
|
||||
memcpy( ctx->MBEDTLS_PRIVATE(T_1_pub_key), key + MBEDTLS_LMS_PUBKEY_ROOT_NODE_OFFSET,
|
||||
MBEDTLS_LMOTS_N_HASH_LEN );
|
||||
if( ctx->MBEDTLS_PRIVATE(have_private_key) )
|
||||
{
|
||||
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
int mbedtls_lms_export_pubkey( mbedtls_lms_context *ctx,
|
||||
unsigned char *key )
|
||||
int mbedtls_lms_calculate_public_key( mbedtls_lms_public_t *ctx,
|
||||
mbedtls_lms_private_t *priv_ctx )
|
||||
{
|
||||
if( ctx == NULL )
|
||||
{
|
||||
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;
|
||||
unsigned char tree[MERKLE_TREE_NODE_AM][MBEDTLS_LMS_M_NODE_BYTES];
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
if( ctx->MBEDTLS_PRIVATE(otstype) != MBEDTLS_LMOTS_SHA256_N32_W8 )
|
||||
{
|
||||
return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
|
||||
}
|
||||
memcpy( &ctx->MBEDTLS_PRIVATE(params), &priv_ctx->MBEDTLS_PRIVATE(params),
|
||||
sizeof(mbedtls_lmots_parameters_t) );
|
||||
|
||||
for( idx = 0; idx < MERKLE_TREE_LEAF_AM; idx++ )
|
||||
{
|
||||
ret = mbedtls_lmots_gen_pubkey( &ctx->MBEDTLS_PRIVATE(priv_keys)[idx] );
|
||||
if( ret )
|
||||
{
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
|
||||
ret = generate_merkle_tree( ctx, tree);
|
||||
ret = calculate_merkle_tree( priv_ctx, tree);
|
||||
if( 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 */
|
||||
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 );
|
||||
}
|
||||
|
||||
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 )
|
||||
|
||||
int mbedtls_lms_export_public_key( mbedtls_lms_public_t *ctx, unsigned char *key,
|
||||
size_t key_size, size_t *key_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;
|
||||
|
||||
if( ctx == NULL )
|
||||
if( ! ctx->MBEDTLS_PRIVATE(have_private_key) )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return( MBEDTLS_ERR_LMS_OUT_OF_PRIVATE_KEYS );
|
||||
}
|
||||
|
||||
|
||||
for( idx = 0; idx < MERKLE_TREE_LEAF_AM; idx++ )
|
||||
{
|
||||
ret = mbedtls_lmots_gen_privkey( &ctx->MBEDTLS_PRIVATE(priv_keys)[idx],
|
||||
ctx->MBEDTLS_PRIVATE(I_key_identifier),
|
||||
idx, seed, seed_len );
|
||||
if( ret)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
ctx->MBEDTLS_PRIVATE(q_next_usable_key) = 0;
|
||||
ctx->MBEDTLS_PRIVATE(have_privkey) = 1;
|
||||
|
||||
out:
|
||||
ret = mbedtls_lmots_sign( &ctx->MBEDTLS_PRIVATE(ots_private_keys)[q_leaf_identifier],
|
||||
f_rng, p_rng, msg, msg_size,
|
||||
sig + MBEDTLS_LMS_SIG_OTS_SIG_OFFSET,
|
||||
MBEDTLS_LMS_SIG_LEN, NULL );
|
||||
if( ret )
|
||||
{
|
||||
mbedtls_free( ctx->MBEDTLS_PRIVATE(priv_keys) );
|
||||
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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
/* BEGIN_CASE */
|
||||
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];
|
||||
mbedtls_entropy_context entropy_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_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,
|
||||
&entropy_ctx, (uint8_t*)"", 0 ) == 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_gen_privkey(&ctx, (uint8_t[16]){0}, 0x12, seed, sizeof( seed ) ) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_gen_pubkey(&ctx) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_sign(&ctx, mbedtls_ctr_drbg_random, &drbg_ctx, msg->x, msg->len, sig ) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_verify(&ctx, msg->x, msg->len, sig) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_generate_private_key(&priv_ctx, MBEDTLS_LMOTS_SHA256_N32_W8,
|
||||
(uint8_t[16]){0}, 0x12, seed, sizeof( seed ) ) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_calculate_public_key(&pub_ctx, &priv_ctx) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_sign(&priv_ctx, mbedtls_ctr_drbg_random, &drbg_ctx,
|
||||
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:
|
||||
mbedtls_entropy_free( &entropy_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 */
|
||||
|
||||
|
@ -46,40 +50,40 @@ exit:
|
|||
void lmots_verify_test ( data_t * msg, data_t * sig, data_t * pub_key,
|
||||
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:
|
||||
mbedtls_lmots_free( &ctx );
|
||||
mbedtls_lmots_free_public( &ctx );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE */
|
||||
void lmots_import_export_test ( data_t * pub_key )
|
||||
{
|
||||
mbedtls_lmots_context ctx;
|
||||
uint8_t exported_pub_key[MBEDTLS_LMOTS_PUBKEY_LEN];
|
||||
mbedtls_lmots_public_t ctx;
|
||||
uint8_t exported_pub_key[MBEDTLS_LMOTS_PUBLIC_KEY_LEN];
|
||||
|
||||
mbedtls_lmots_init( &ctx );
|
||||
TEST_ASSERT( mbedtls_lmots_import_pubkey( &ctx, pub_key->x ) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_export_pubkey( &ctx, exported_pub_key ) == 0 );
|
||||
mbedtls_lmots_init_public( &ctx );
|
||||
TEST_ASSERT( mbedtls_lmots_import_public_key( &ctx, pub_key->x, pub_key->len ) == 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:
|
||||
mbedtls_lmots_free( &ctx );
|
||||
mbedtls_lmots_free_public( &ctx );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE */
|
||||
void lmots_reuse_test ( data_t * msg )
|
||||
{
|
||||
mbedtls_lmots_context ctx;
|
||||
mbedtls_lmots_private_t ctx;
|
||||
unsigned char sig[MBEDTLS_LMOTS_SIG_LEN];
|
||||
mbedtls_entropy_context entropy_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_lmots_init( &ctx );
|
||||
TEST_ASSERT( mbedtls_lmots_set_algorithm_type( &ctx, MBEDTLS_LMOTS_SHA256_N32_W8 ) == 0 );
|
||||
TEST_ASSERT( mbedtls_lmots_gen_privkey(&ctx, (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 );
|
||||
mbedtls_lmots_init_private( &ctx );
|
||||
TEST_ASSERT( mbedtls_lmots_generate_private_key(&ctx, MBEDTLS_LMOTS_SHA256_N32_W8,
|
||||
(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, sizeof( sig ), NULL ) == 0 );
|
||||
|
||||
/* Running another sign operation should fail, since the key should now have
|
||||
* 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:
|
||||
mbedtls_entropy_free( &entropy_ctx );
|
||||
mbedtls_ctr_drbg_free( &drbg_ctx );
|
||||
mbedtls_lmots_free( &ctx );
|
||||
mbedtls_lmots_free_private( &ctx );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
/* BEGIN_CASE */
|
||||
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];
|
||||
mbedtls_entropy_context entropy_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_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,
|
||||
&entropy_ctx, ( uint8_t* )"", 0 ) == 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 */
|
||||
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_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:
|
||||
mbedtls_entropy_free( &entropy_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 */
|
||||
|
||||
|
@ -52,34 +59,35 @@ exit:
|
|||
void lms_verify_test ( data_t * msg, data_t * sig, data_t * pub_key,
|
||||
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:
|
||||
mbedtls_lms_free( &ctx );
|
||||
mbedtls_lms_free_public( &ctx );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE */
|
||||
void lms_import_export_test ( data_t * pub_key )
|
||||
{
|
||||
mbedtls_lms_context ctx;
|
||||
uint8_t exported_pub_key[MBEDTLS_LMS_PUBKEY_LEN];
|
||||
mbedtls_lms_public_t ctx;
|
||||
uint8_t exported_pub_key[MBEDTLS_LMS_PUBLIC_KEY_LEN];
|
||||
|
||||
mbedtls_lms_init(&ctx);
|
||||
TEST_ASSERT( mbedtls_lms_import_pubkey( &ctx, pub_key->x ) == 0 );
|
||||
TEST_ASSERT( mbedtls_lms_export_pubkey( &ctx, exported_pub_key) == 0 );
|
||||
mbedtls_lms_init_public(&ctx);
|
||||
TEST_ASSERT( mbedtls_lms_import_public_key( &ctx, pub_key->x, pub_key->len ) == 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,
|
||||
exported_pub_key, MBEDTLS_LMS_PUBKEY_LEN );
|
||||
ASSERT_COMPARE( pub_key->x, MBEDTLS_LMS_PUBLIC_KEY_LEN,
|
||||
exported_pub_key, MBEDTLS_LMS_PUBLIC_KEY_LEN );
|
||||
|
||||
exit:
|
||||
mbedtls_lms_free( &ctx );
|
||||
mbedtls_lms_free_public( &ctx );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
|
|
Loading…
Reference in a new issue