1 /*
2  * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include "crypto/lms_sig.h"
11 #include "crypto/lms_util.h"
12 
13 /**
14  * @brief Decode a byte array containing XDR signature data into a LMS_SIG object.
15  *
16  * This is used for LMS Signature Verification.
17  * This function may be called multiple times.
18  * See RFC 8554 Algorithm 6a: Steps 1 and 2.
19  * It uses shallow copies for C, y and path.
20  *
21  * @param pkt Contains the signature data to decode. There may still be data
22  *            remaining in pkt after decoding.
23  * @param pub A public key that contains LMS_PARAMS and LM_OTS_PARAMS associated
24  *            with the signature.
25  * @returns The created LMS_SIG object if successful, or NULL on failure. A
26  *          failure may occur if the passed in LMS public key |pub| is not
27  *          compatible with the decoded LMS_SIG object,
28  */
ossl_lms_sig_from_pkt(PACKET * pkt,const LMS_KEY * pub)29 LMS_SIG *ossl_lms_sig_from_pkt(PACKET *pkt, const LMS_KEY *pub)
30 {
31     uint32_t sig_ots_type = 0, sig_lms_type = 0;
32     const LMS_PARAMS *lparams = pub->lms_params;
33     const LM_OTS_PARAMS *pub_ots_params = pub->ots_params;
34     const LM_OTS_PARAMS *sig_params;
35     LMS_SIG *lsig = NULL;
36 
37     lsig = ossl_lms_sig_new();
38     if (lsig == NULL)
39         return NULL;
40 
41     if (!PACKET_get_net_4_len_u32(pkt, &lsig->q)    /* q = Leaf Index */
42             || !PACKET_get_net_4_len_u32(pkt, &sig_ots_type)
43             || pub_ots_params->lm_ots_type != sig_ots_type)
44         goto err;
45     sig_params = pub_ots_params;
46     lsig->sig.params = sig_params;
47     lsig->params = lparams;
48 
49     if (!PACKET_get_bytes(pkt, (const unsigned char **)&lsig->sig.C,
50                           sig_params->n)
51             || !PACKET_get_bytes(pkt, (const unsigned char **)&lsig->sig.y,
52                                  sig_params->p * sig_params->n)
53             || !PACKET_get_net_4_len_u32(pkt, &sig_lms_type)
54             || (lparams->lms_type != sig_lms_type)
55             || HASH_NOT_MATCHED(lparams, sig_params)
56             || lsig->q >= (uint32_t)(1 << lparams->h)
57             || !PACKET_get_bytes(pkt, (const unsigned char **)&lsig->paths,
58                                  lparams->h * lparams->n)
59             || PACKET_remaining(pkt) > 0)
60         goto err;
61     return lsig;
62 err:
63     ossl_lms_sig_free(lsig);
64     return NULL;
65 }
66 
67 /**
68  * @brief Decode a byte array of LMS signature data.
69  *
70  * This function does not duplicate any of the byte data contained within
71  * |sig|. So it is expected that |sig| will exist for the duration of the
72  * returned signature |out|.
73  *
74  * @param out Used to return the LMS_SIG object.
75  * @param pub The root public LMS key
76  * @param sig A input byte array of signature data.
77  * @param siglen The size of sig.
78  * @returns 1 if the signature is successfully decoded,
79  *          otherwise it returns 0.
80  */
ossl_lms_sig_decode(LMS_SIG ** out,LMS_KEY * pub,const unsigned char * sig,size_t siglen)81 int ossl_lms_sig_decode(LMS_SIG **out, LMS_KEY *pub,
82                         const unsigned char *sig, size_t siglen)
83 {
84     PACKET pkt;
85     LMS_SIG *s = NULL;
86 
87     if (pub == NULL)
88         return 0;
89 
90     if (!PACKET_buf_init(&pkt, sig, siglen))
91         return 0;
92 
93     s = ossl_lms_sig_from_pkt(&pkt, pub);
94     if (s == NULL)
95         return 0;
96 
97     /* Fail if there are trailing bytes */
98     if (PACKET_remaining(&pkt) > 0)
99         goto err;
100     *out = s;
101     return 1;
102 err:
103     ossl_lms_sig_free(s);
104     return 0;
105 }
106