/* * 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 "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 if 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_net_4_len_u32(pkt, &lsig->q) /* q = Leaf Index */ || !PACKET_get_net_4_len_u32(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(pkt, (const unsigned char **)&lsig->sig.C, sig_params->n) || !PACKET_get_bytes(pkt, (const unsigned char **)&lsig->sig.y, sig_params->p * sig_params->n) || !PACKET_get_net_4_len_u32(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(pkt, (const unsigned char **)&lsig->paths, lparams->h * lparams->n) || PACKET_remaining(pkt) > 0) 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; }