1
0
mirror of https://github.com/ARMmbed/mbedtls.git synced 2025-05-10 08:59:05 +08:00
Agathiyan Bragadeesh 10b6775aeb Add enum type casts in lmots.c and lms.c
The IAR compiler throws an error when trying to assign an int to an enum
so these casts have been added.

Signed-off-by: Agathiyan Bragadeesh <agathiyan.bragadeesh2@arm.com>
2023-07-17 15:14:42 +01:00

794 lines
27 KiB
C

/*
* The LMS stateful-hash public-key signature scheme
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* The following sources were referenced in the design of this implementation
* of the LMS algorithm:
*
* [1] IETF RFC8554
* D. McGrew, M. Curcio, S.Fluhrer
* https://datatracker.ietf.org/doc/html/rfc8554
*
* [2] NIST Special Publication 800-208
* David A. Cooper et. al.
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
*/
#include "common.h"
#if defined(MBEDTLS_LMS_C)
#include <string.h>
#include "lmots.h"
#include "psa/crypto.h"
#include "mbedtls/psa_util.h"
#include "mbedtls/lms.h"
#include "mbedtls/error.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/platform.h"
/* Define a local translating function to save code size by not using too many
* arguments in each translating place. */
static int local_err_translation(psa_status_t status)
{
return psa_status_to_mbedtls(status, psa_to_lms_errors,
ARRAY_LENGTH(psa_to_lms_errors),
psa_generic_status_to_mbedtls);
}
#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
#define SIG_Q_LEAF_ID_OFFSET (0)
#define SIG_OTS_SIG_OFFSET (SIG_Q_LEAF_ID_OFFSET + \
MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
#define SIG_TYPE_OFFSET(otstype) (SIG_OTS_SIG_OFFSET + \
MBEDTLS_LMOTS_SIG_LEN(otstype))
#define SIG_PATH_OFFSET(otstype) (SIG_TYPE_OFFSET(otstype) + \
MBEDTLS_LMS_TYPE_LEN)
#define PUBLIC_KEY_TYPE_OFFSET (0)
#define PUBLIC_KEY_OTSTYPE_OFFSET (PUBLIC_KEY_TYPE_OFFSET + \
MBEDTLS_LMS_TYPE_LEN)
#define PUBLIC_KEY_I_KEY_ID_OFFSET (PUBLIC_KEY_OTSTYPE_OFFSET + \
MBEDTLS_LMOTS_TYPE_LEN)
#define PUBLIC_KEY_ROOT_NODE_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \
MBEDTLS_LMOTS_I_KEY_ID_LEN)
/* Currently only support H=10 */
#define H_TREE_HEIGHT_MAX 10
#define MERKLE_TREE_NODE_AM(type) ((size_t) 1 << (MBEDTLS_LMS_H_TREE_HEIGHT(type) + 1u))
#define MERKLE_TREE_LEAF_NODE_AM(type) ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
#define MERKLE_TREE_INTERNAL_NODE_AM(type) ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
#define D_CONST_LEN (2)
static const unsigned char D_LEAF_CONSTANT_BYTES[D_CONST_LEN] = { 0x82, 0x82 };
static const unsigned char D_INTR_CONSTANT_BYTES[D_CONST_LEN] = { 0x83, 0x83 };
/* Calculate the value of a leaf node of the Merkle tree (which is a hash of a
* public key and some other parameters like the leaf index). This function
* implements RFC8554 section 5.3, in the case where r >= 2^h.
*
* params The LMS parameter set, the underlying LMOTS
* parameter set, and I value which describe the key
* being used.
*
* pub_key The public key of the private whose index
* corresponds to the index of this leaf node. This
* is a hash output.
*
* r_node_idx The index of this node in the Merkle tree. Note
* that the root node of the Merkle tree is
* 1-indexed.
*
* out The output node value, which is a hash output.
*/
static int create_merkle_leaf_value(const mbedtls_lms_parameters_t *params,
unsigned char *pub_key,
unsigned int r_node_idx,
unsigned char *out)
{
psa_hash_operation_t op;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
unsigned char r_node_idx_bytes[4];
op = psa_hash_operation_init();
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, params->I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
mbedtls_lms_unsigned_int_to_network_bytes(r_node_idx, 4, r_node_idx_bytes);
status = psa_hash_update(&op, r_node_idx_bytes, 4);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, D_LEAF_CONSTANT_BYTES, D_CONST_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, pub_key,
MBEDTLS_LMOTS_N_HASH_LEN(params->otstype));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
&output_hash_len);
if (status != PSA_SUCCESS) {
goto exit;
}
exit:
psa_hash_abort(&op);
return PSA_TO_MBEDTLS_ERR(status);
}
/* Calculate the value of an internal node of the Merkle tree (which is a hash
* of a public key and some other parameters like the node index). This function
* implements RFC8554 section 5.3, in the case where r < 2^h.
*
* params The LMS parameter set, the underlying LMOTS
* parameter set, and I value which describe the key
* being used.
*
* left_node The value of the child of this node which is on
* the left-hand side. As with all nodes on the
* Merkle tree, this is a hash output.
*
* right_node The value of the child of this node which is on
* the right-hand side. As with all nodes on the
* Merkle tree, this is a hash output.
*
* r_node_idx The index of this node in the Merkle tree. Note
* that the root node of the Merkle tree is
* 1-indexed.
*
* out The output node value, which is a hash output.
*/
static int create_merkle_internal_value(const mbedtls_lms_parameters_t *params,
const unsigned char *left_node,
const unsigned char *right_node,
unsigned int r_node_idx,
unsigned char *out)
{
psa_hash_operation_t op;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
unsigned char r_node_idx_bytes[4];
op = psa_hash_operation_init();
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, params->I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
mbedtls_lms_unsigned_int_to_network_bytes(r_node_idx, 4, r_node_idx_bytes);
status = psa_hash_update(&op, r_node_idx_bytes, 4);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, D_INTR_CONSTANT_BYTES, D_CONST_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, left_node,
MBEDTLS_LMS_M_NODE_BYTES(params->type));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, right_node,
MBEDTLS_LMS_M_NODE_BYTES(params->type));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
&output_hash_len);
if (status != PSA_SUCCESS) {
goto exit;
}
exit:
psa_hash_abort(&op);
return PSA_TO_MBEDTLS_ERR(status);
}
void mbedtls_lms_public_init(mbedtls_lms_public_t *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
void mbedtls_lms_public_free(mbedtls_lms_public_t *ctx)
{
mbedtls_platform_zeroize(ctx, sizeof(*ctx));
}
int mbedtls_lms_import_public_key(mbedtls_lms_public_t *ctx,
const unsigned char *key, size_t key_size)
{
mbedtls_lms_algorithm_type_t type;
mbedtls_lmots_algorithm_type_t otstype;
type = (mbedtls_lms_algorithm_type_t) mbedtls_lms_network_bytes_to_unsigned_int(
MBEDTLS_LMS_TYPE_LEN,
key +
PUBLIC_KEY_TYPE_OFFSET);
if (type != MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.type = type;
if (key_size != MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
otstype = (mbedtls_lmots_algorithm_type_t) mbedtls_lms_network_bytes_to_unsigned_int(
MBEDTLS_LMOTS_TYPE_LEN,
key +
PUBLIC_KEY_OTSTYPE_OFFSET);
if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.otstype = otstype;
memcpy(ctx->params.I_key_identifier,
key + PUBLIC_KEY_I_KEY_ID_OFFSET,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
memcpy(ctx->T_1_pub_key, key + PUBLIC_KEY_ROOT_NODE_OFFSET,
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
ctx->have_public_key = 1;
return 0;
}
int mbedtls_lms_export_public_key(const mbedtls_lms_public_t *ctx,
unsigned char *key,
size_t key_size, size_t *key_len)
{
if (key_size < MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
}
if (!ctx->have_public_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
mbedtls_lms_unsigned_int_to_network_bytes(
ctx->params.type,
MBEDTLS_LMS_TYPE_LEN, key + PUBLIC_KEY_TYPE_OFFSET);
mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.otstype,
MBEDTLS_LMOTS_TYPE_LEN,
key + PUBLIC_KEY_OTSTYPE_OFFSET);
memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
ctx->params.I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
memcpy(key +PUBLIC_KEY_ROOT_NODE_OFFSET,
ctx->T_1_pub_key,
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
if (key_len != NULL) {
*key_len = MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type);
}
return 0;
}
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_MAX];
unsigned char Tc_candidate_root_node[MBEDTLS_LMS_M_NODE_BYTES_MAX];
unsigned int height;
unsigned int curr_node_id;
unsigned int parent_node_id;
const unsigned char *left_node;
const unsigned char *right_node;
mbedtls_lmots_parameters_t ots_params;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (!ctx->have_public_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->params.type
!= MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->params.otstype
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (sig_size != MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (sig_size < SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMOTS_TYPE_LEN,
sig + SIG_OTS_SIG_OFFSET +
MBEDTLS_LMOTS_SIG_TYPE_OFFSET)
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (sig_size < SIG_TYPE_OFFSET(ctx->params.otstype) + MBEDTLS_LMS_TYPE_LEN) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMS_TYPE_LEN,
sig + SIG_TYPE_OFFSET(ctx->params.otstype))
!= MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
q_leaf_identifier = mbedtls_lms_network_bytes_to_unsigned_int(
MBEDTLS_LMOTS_Q_LEAF_ID_LEN, sig + SIG_Q_LEAF_ID_OFFSET);
if (q_leaf_identifier >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
memcpy(ots_params.I_key_identifier,
ctx->params.I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
mbedtls_lms_unsigned_int_to_network_bytes(q_leaf_identifier,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
ots_params.q_leaf_identifier);
ots_params.type = ctx->params.otstype;
ret = mbedtls_lmots_calculate_public_key_candidate(&ots_params,
msg,
msg_size,
sig + SIG_OTS_SIG_OFFSET,
MBEDTLS_LMOTS_SIG_LEN(ctx->params.otstype),
Kc_candidate_ots_pub_key,
sizeof(Kc_candidate_ots_pub_key),
NULL);
if (ret != 0) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
create_merkle_leaf_value(
&ctx->params,
Kc_candidate_ots_pub_key,
MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
Tc_candidate_root_node);
curr_node_id = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) +
q_leaf_identifier;
for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
height++) {
parent_node_id = curr_node_id / 2;
/* Left/right node ordering matters for the hash */
if (curr_node_id & 1) {
left_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
right_node = Tc_candidate_root_node;
} else {
left_node = Tc_candidate_root_node;
right_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
}
create_merkle_internal_value(&ctx->params, left_node, right_node,
parent_node_id, Tc_candidate_root_node);
curr_node_id /= 2;
}
if (memcmp(Tc_candidate_root_node, ctx->T_1_pub_key,
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type))) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
return 0;
}
#if defined(MBEDTLS_LMS_PRIVATE)
/* Calculate a full Merkle tree based on a private key. This function
* implements RFC8554 section 5.3, and is used to generate a public key (as the
* public key is the root node of the Merkle tree).
*
* ctx The LMS private context, containing a parameter
* set and private key material consisting of both
* public and private OTS.
*
* tree The output tree, which is 2^(H + 1) hash outputs.
* In the case of H=10 we have 2048 tree nodes (of
* which 1024 of them are leaf nodes). Note that
* because the Merkle tree root is 1-indexed, the 0
* index tree node is never used.
*/
static int calculate_merkle_tree(const mbedtls_lms_private_t *ctx,
unsigned char *tree)
{
unsigned int priv_key_idx;
unsigned int r_node_idx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* First create the leaf nodes, in ascending order */
for (priv_key_idx = 0;
priv_key_idx < MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type);
priv_key_idx++) {
r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + priv_key_idx;
ret = create_merkle_leaf_value(&ctx->params,
ctx->ots_public_keys[priv_key_idx].public_key,
r_node_idx,
&tree[r_node_idx * MBEDTLS_LMS_M_NODE_BYTES(
ctx->params.type)]);
if (ret != 0) {
return ret;
}
}
/* Then the internal nodes, in reverse order so that we can guarantee the
* parent has been created */
for (r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) - 1;
r_node_idx > 0;
r_node_idx--) {
ret = create_merkle_internal_value(&ctx->params,
&tree[(r_node_idx * 2) *
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
&tree[(r_node_idx * 2 + 1) *
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
r_node_idx,
&tree[r_node_idx *
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)]);
if (ret != 0) {
return ret;
}
}
return 0;
}
/* Calculate a path from a leaf node of the Merkle tree to the root of the tree,
* and return the full path. This function implements RFC8554 section 5.4.1, as
* the Merkle path is the main component of an LMS signature.
*
* ctx The LMS private context, containing a parameter
* set and private key material consisting of both
* public and private OTS.
*
* leaf_node_id Which leaf node to calculate the path from.
*
* path The output path, which is H hash outputs.
*/
static int get_merkle_path(mbedtls_lms_private_t *ctx,
unsigned int leaf_node_id,
unsigned char *path)
{
const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
unsigned int curr_node_id = leaf_node_id;
unsigned int adjacent_node_id;
unsigned char *tree = NULL;
unsigned int height;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
tree = mbedtls_calloc(MERKLE_TREE_NODE_AM(ctx->params.type),
node_bytes);
if (tree == NULL) {
return MBEDTLS_ERR_LMS_ALLOC_FAILED;
}
ret = calculate_merkle_tree(ctx, tree);
if (ret != 0) {
goto exit;
}
for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
height++) {
adjacent_node_id = curr_node_id ^ 1;
memcpy(&path[height * node_bytes],
&tree[adjacent_node_id * node_bytes], node_bytes);
curr_node_id >>= 1;
}
ret = 0;
exit:
mbedtls_platform_zeroize(tree, node_bytes *
MERKLE_TREE_NODE_AM(ctx->params.type));
mbedtls_free(tree);
return ret;
}
void mbedtls_lms_private_init(mbedtls_lms_private_t *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
void mbedtls_lms_private_free(mbedtls_lms_private_t *ctx)
{
unsigned int idx;
if (ctx->have_private_key) {
if (ctx->ots_private_keys != NULL) {
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
mbedtls_lmots_private_free(&ctx->ots_private_keys[idx]);
}
}
if (ctx->ots_public_keys != NULL) {
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
mbedtls_lmots_public_free(&ctx->ots_public_keys[idx]);
}
}
mbedtls_free(ctx->ots_private_keys);
mbedtls_free(ctx->ots_public_keys);
}
mbedtls_platform_zeroize(ctx, sizeof(*ctx));
}
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, const unsigned char *seed,
size_t seed_size)
{
unsigned int idx = 0;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (type != MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.type = type;
ctx->params.otstype = otstype;
ctx->have_private_key = 1;
ret = f_rng(p_rng,
ctx->params.I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (ret != 0) {
goto exit;
}
/* Requires a cast to size_t to avoid an implicit cast warning on certain
* platforms (particularly Windows) */
ctx->ots_private_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
sizeof(*ctx->ots_private_keys));
if (ctx->ots_private_keys == NULL) {
ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
goto exit;
}
/* Requires a cast to size_t to avoid an implicit cast warning on certain
* platforms (particularly Windows) */
ctx->ots_public_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
sizeof(*ctx->ots_public_keys));
if (ctx->ots_public_keys == NULL) {
ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
goto exit;
}
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
mbedtls_lmots_private_init(&ctx->ots_private_keys[idx]);
mbedtls_lmots_public_init(&ctx->ots_public_keys[idx]);
}
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
ret = mbedtls_lmots_generate_private_key(&ctx->ots_private_keys[idx],
otstype,
ctx->params.I_key_identifier,
idx, seed, seed_size);
if (ret != 0) {
goto exit;
}
ret = mbedtls_lmots_calculate_public_key(&ctx->ots_public_keys[idx],
&ctx->ots_private_keys[idx]);
if (ret != 0) {
goto exit;
}
}
ctx->q_next_usable_key = 0;
exit:
if (ret != 0) {
mbedtls_lms_private_free(ctx);
}
return ret;
}
int mbedtls_lms_calculate_public_key(mbedtls_lms_public_t *ctx,
const mbedtls_lms_private_t *priv_ctx)
{
const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(priv_ctx->params.type);
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *tree = NULL;
if (!priv_ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (priv_ctx->params.type
!= MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (priv_ctx->params.otstype
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
tree = mbedtls_calloc(MERKLE_TREE_NODE_AM(priv_ctx->params.type),
node_bytes);
if (tree == NULL) {
return MBEDTLS_ERR_LMS_ALLOC_FAILED;
}
memcpy(&ctx->params, &priv_ctx->params,
sizeof(mbedtls_lmots_parameters_t));
ret = calculate_merkle_tree(priv_ctx, tree);
if (ret != 0) {
goto exit;
}
/* Root node is always at position 1, due to 1-based indexing */
memcpy(ctx->T_1_pub_key, &tree[node_bytes], node_bytes);
ctx->have_public_key = 1;
ret = 0;
exit:
mbedtls_platform_zeroize(tree, node_bytes *
MERKLE_TREE_NODE_AM(priv_ctx->params.type));
mbedtls_free(tree);
return ret;
}
int mbedtls_lms_sign(mbedtls_lms_private_t *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng, const 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->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (sig_size < MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
}
if (ctx->params.type != MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->params.otstype
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->q_next_usable_key >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
return MBEDTLS_ERR_LMS_OUT_OF_PRIVATE_KEYS;
}
q_leaf_identifier = ctx->q_next_usable_key;
/* This new value must _always_ be written back to the disk before the
* signature is returned.
*/
ctx->q_next_usable_key += 1;
if (MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)
< SIG_OTS_SIG_OFFSET) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ret = mbedtls_lmots_sign(&ctx->ots_private_keys[q_leaf_identifier],
f_rng,
p_rng,
msg,
msg_size,
sig + SIG_OTS_SIG_OFFSET,
MBEDTLS_LMS_SIG_LEN(ctx->params.type,
ctx->params.otstype) - SIG_OTS_SIG_OFFSET,
NULL);
if (ret != 0) {
return ret;
}
mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.type,
MBEDTLS_LMS_TYPE_LEN,
sig + SIG_TYPE_OFFSET(ctx->params.otstype));
mbedtls_lms_unsigned_int_to_network_bytes(q_leaf_identifier,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
sig + SIG_Q_LEAF_ID_OFFSET);
ret = get_merkle_path(ctx,
MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
sig + SIG_PATH_OFFSET(ctx->params.otstype));
if (ret != 0) {
return ret;
}
if (sig_len != NULL) {
*sig_len = MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype);
}
return 0;
}
#endif /* defined(MBEDTLS_LMS_PRIVATE) */
#endif /* defined(MBEDTLS_LMS_C) */