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