openssl/crypto/lms/lms_sig_decoder.c
slontis 2ae5fd035a Add LMS Signature verification.
Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25598)
2025-02-04 08:29:22 +11:00

103 lines
3.3 KiB
C

/*
* Copyright 2024 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 "crypto/lms_sig.h"
#include "crypto/lms_util.h"
/**
* @brief Decode a byte array containing XDR signature data into a LMS_SIG object.
*
* This is used for LMS Signature Verification.
* This function may be called multiple times.
* See RFC 8554 Algorithm 6a: Steps 1 and 2.
* It uses shallow copies for C, y and path.
*
* @param pkt Contains the signature data to decode. There may still be data
* remaining in pkt after decoding.
* @param pub A public key that contains LMS_PARAMS and LM_OTS_PARAMS associated
* with the signature.
* @returns The created LMS_SIG object is successful, or NULL on failure. A
* failure may occur if the passed in LMS public key |pub| is not
* compatible with the decoded LMS_SIG object,
*/
LMS_SIG *ossl_lms_sig_from_pkt(PACKET *pkt, const LMS_KEY *pub)
{
uint32_t sig_ots_type = 0, sig_lms_type = 0;
const LMS_PARAMS *lparams = pub->lms_params;
const LM_OTS_PARAMS *pub_ots_params = pub->ots_params;
const LM_OTS_PARAMS *sig_params;
LMS_SIG *lsig = NULL;
lsig = ossl_lms_sig_new();
if (lsig == NULL)
return NULL;
if (!PACKET_get_4_len(pkt, &lsig->q) /* q = Leaf Index */
|| !PACKET_get_4_len(pkt, &sig_ots_type)
|| pub_ots_params->lm_ots_type != sig_ots_type)
goto err;
sig_params = pub_ots_params;
lsig->sig.params = sig_params;
lsig->params = lparams;
if (!PACKET_get_bytes_shallow(pkt, &lsig->sig.C, sig_params->n)
|| !PACKET_get_bytes_shallow(pkt, &lsig->sig.y,
sig_params->p * sig_params->n)
|| !PACKET_get_4_len(pkt, &sig_lms_type)
|| (lparams->lms_type != sig_lms_type)
|| HASH_NOT_MATCHED(lparams, sig_params)
|| lsig->q >= (uint32_t)(1 << lparams->h)
|| !PACKET_get_bytes_shallow(pkt, &lsig->paths,
lparams->h * lparams->n))
goto err;
return lsig;
err:
ossl_lms_sig_free(lsig);
return NULL;
}
/**
* @brief Decode a byte array of LMS signature data.
*
* This function does not duplicate any of the byte data contained within
* |sig|. So it is expected that |sig| will exist for the duration of the
* returned signature |out|.
*
* @param out Used to return the LMS_SIG object.
* @param pub The root public LMS key
* @param sig A input byte array of signature data.
* @param siglen The size of sig.
* @returns 1 if the signature is successfully decoded,
* otherwise it returns 0.
*/
int ossl_lms_sig_decode(LMS_SIG **out, LMS_KEY *pub,
const unsigned char *sig, size_t siglen)
{
PACKET pkt;
LMS_SIG *s = NULL;
if (pub == NULL)
return 0;
if (!PACKET_buf_init(&pkt, sig, siglen))
return 0;
s = ossl_lms_sig_from_pkt(&pkt, pub);
if (s == NULL)
return 0;
/* Fail if there are trailing bytes */
if (PACKET_remaining(&pkt) > 0)
goto err;
*out = s;
return 1;
err:
ossl_lms_sig_free(s);
return 0;
}