openssl/crypto/lms/lms_pubkey_decode.c

134 lines
4.4 KiB
C

/*
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/core_names.h>
#include "crypto/lms.h"
#include "crypto/lms_util.h"
/**
* @brief Calculate the size of a public key in XDR format.
*
* @param data A byte array of XDR data for a LMS public key.
* The first 4 bytes are looked at.
* @param datalen The size of |data|.
* @returns The calculated size, or 0 on error.
*/
size_t ossl_lms_pubkey_length(const unsigned char *data, size_t datalen)
{
PACKET pkt;
uint32_t lms_type;
const LMS_PARAMS *params;
if (!PACKET_buf_init(&pkt, data, datalen)
|| !PACKET_get_net_4_len_u32(&pkt, &lms_type)
|| (params = ossl_lms_params_get(lms_type)) == NULL)
return 0;
return LMS_SIZE_LMS_TYPE + LMS_SIZE_OTS_TYPE + LMS_SIZE_I + params->n;
}
/*
* @brief Decode LMS public key data in XDR format into a LMS_KEY object.
*
* See RFC 8554 Algorithm 6: Steps 1 & 2.
* The XDR format is lms_type[4] || ots_type[4] || I[16] || K[n]
* Steps that involve checking the size of the public key data are
* done indirectly by checking the return result of PACKET_get API's.
* This function may be called multiple times.
*
* @param pkt The packet to read public key data in XDR format from.
* @param lmskey The object to store the public key into
* @return 1 on success or 0 otherwise.
*/
static
int lms_pubkey_from_pkt(LMS_KEY *lmskey, const unsigned char *pubkeydata,
size_t publen)
{
uint32_t lms_type;
uint32_t ots_type;
LMS_PUB_KEY *key = &lmskey->pub;
PACKET pkt;
if (!PACKET_buf_init(&pkt, pubkeydata, publen))
goto err;
key->encoded = (unsigned char *)PACKET_data(&pkt);
if (!PACKET_get_net_4_len_u32(&pkt, &lms_type))
goto err;
lmskey->lms_params = ossl_lms_params_get(lms_type);
if (lmskey->lms_params == NULL
|| !PACKET_get_net_4_len_u32(&pkt, &ots_type))
goto err;
lmskey->ots_params = ossl_lm_ots_params_get(ots_type);
if (lmskey->ots_params == NULL)
goto err;
/* The digest used must be the same */
if (HASH_NOT_MATCHED(lmskey->ots_params, lmskey->lms_params)
|| !PACKET_get_bytes(&pkt, (const unsigned char **)&lmskey->Id,
LMS_SIZE_I)
|| !PACKET_get_bytes(&pkt, (const unsigned char **)&key->K,
lmskey->lms_params->n))
goto err;
key->encodedlen = (unsigned char *)PACKET_data(&pkt) - key->encoded;
return PACKET_remaining(&pkt) == 0;
err:
return 0;
}
/*
* @brief Decode LMS public key data in XDR format into a LMS_KEY object.
* Used by the LMS public key decoder.
* The XDR format is lms_type[4] || ots_type[4] || I[16] || K[n]
*
* @param pub byte array of public key data in XDR format.
* @param publen is the size of |pub|.
* @param lmskey The LMS_KEY object to store the public key into.
* @returns 1 on success, or 0 otherwise. 0 is returned if either |pub| is
* invalid or |publen| is not the correct size (i.e. trailing data is not allowed)
*/
int ossl_lms_pubkey_decode(const unsigned char *pub, size_t publen,
LMS_KEY *lmskey)
{
LMS_PUB_KEY *pkey = &lmskey->pub;
if (pkey->encoded != NULL && pkey->encodedlen != publen) {
OPENSSL_free(pkey->encoded);
pkey->encodedlen = 0;
}
pkey->encoded = OPENSSL_memdup(pub, publen);
if (pkey->encoded == NULL)
return 0;
if (!lms_pubkey_from_pkt(lmskey, pkey->encoded, publen))
goto err;
pkey->encodedlen = publen;
return 1;
err:
OPENSSL_free(pkey->encoded);
pkey->encoded = NULL;
return 0;
}
/**
* @brief Load a LMS public key from OSSL_PARAM data.
*
* @param params An array of OSSL_PARAM
* @param lmskey The LMS_KEY to load the public key data into.
* @returns 1 on success, or 0 otherwise.
*/
int ossl_lms_pubkey_from_params(const OSSL_PARAM *pub, LMS_KEY *lmskey)
{
if (pub != NULL) {
if (pub->data == NULL
|| pub->data_type != OSSL_PARAM_OCTET_STRING
|| !ossl_lms_pubkey_decode(pub->data, pub->data_size, lmskey))
return 0;
}
return 1;
}