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 <openssl/byteorder.h>
11 #include "crypto/lms_sig.h"
12 #include "crypto/lms_util.h"
13 #include "internal/common.h"
14 
15 /*
16  * Constants used for obtaining unique inputs for different hashing operations
17  * e.g H(I || q || OSSL_LMS_D_LEAF || ... )
18  */
19 const uint16_t OSSL_LMS_D_PBLC          = 0x8080;
20 const uint16_t OSSL_LMS_D_MESG          = 0x8181;
21 const uint16_t OSSL_LMS_D_LEAF          = 0x8282;
22 const uint16_t OSSL_LMS_D_INTR          = 0x8383;
23 
24 /*
25  * @brief Compute the candidate LMS root value Tc
26  *
27  * @param paths An array of bytes representing the hash values associated with
28  *              the path through the tree from the leaf associated with the
29  *              LM-OTS signature to the root public key node.
30  * @param n The hash output size (The size of each path in |paths|)
31  * @param nodenum The leaf index node number. The root node had a value of 1
32  *                Each subsequent level has nodes in the range 2^h...2^(h+1)-1
33  * @param ctx A EVP_MD_CTX object used for calculations
34  * @param ctxI A EVP_MD_CTX object containing an unfinalised H(I)
35  * @param Tc Contains H(I || u32str(node_num) || u16str(D_LEAF) || Kc) on input,
36  *           and on output returns the calculated candidate public key.
37  * @returns 1 on success, or 0 otherwise.
38  */
39 static
lms_sig_compute_tc_from_path(const unsigned char * paths,uint32_t n,uint32_t node_num,EVP_MD_CTX * ctx,EVP_MD_CTX * ctxI,unsigned char * Tc)40 int lms_sig_compute_tc_from_path(const unsigned char *paths, uint32_t n,
41                                  uint32_t node_num,
42                                  EVP_MD_CTX *ctx, EVP_MD_CTX *ctxI,
43                                  unsigned char *Tc)
44 {
45     int ret = 0;
46     unsigned char qbuf[4];
47     unsigned char d_intr[sizeof(uint16_t)];
48     const unsigned char *path = paths;
49 
50     OPENSSL_store_u16_be(d_intr, OSSL_LMS_D_INTR);
51 
52     /*
53      * Calculate the public key Tc using the path
54      * The root hash is the hash of its 2 childrens Hash values.
55      * A child hash for each level is passed in by paths, and we have
56      * a leaf value that can be used with the path to calculate the parent
57      * hash.
58      */
59     while (node_num > 1) {
60         /* At each level the path contains either the left or right child */
61         int odd = node_num & 1;
62 
63         node_num = node_num >> 1; /* get the parent node_num */
64         OPENSSL_store_u32_be(qbuf, node_num);
65 
66         /*
67          * Calculate Tc as either
68          *   Tc(parent) = H(I || node_q || 0x8383 || paths[i][n] || Tc(right) OR
69          *   Tc(parent) = H(I || node_q || 0x8383 || Tc(left) || paths[i][n])
70          */
71         if (!EVP_MD_CTX_copy_ex(ctx, ctxI)
72                 || !EVP_DigestUpdate(ctx, qbuf, sizeof(qbuf))
73                 || !EVP_DigestUpdate(ctx, d_intr, sizeof(d_intr)))
74             goto err;
75 
76         if (odd) {
77             if (!EVP_DigestUpdate(ctx, path, n)
78                 || !EVP_DigestUpdate(ctx, Tc, n))
79                 goto err;
80         } else {
81             if (!EVP_DigestUpdate(ctx, Tc, n)
82                 || !EVP_DigestUpdate(ctx, path, n))
83                 goto err;
84         }
85         /*
86          * Tc = parent Hash, which is either the left or right child for the next
87          * level up (node_num determines if it is left or right).
88          */
89         if (!EVP_DigestFinal_ex(ctx, Tc, NULL))
90             goto err;
91         path += n;
92     }
93     ret = 1;
94 err:
95     return ret;
96 }
97 
98 /*
99  * @brief LMS signature verification.
100  * See RFC 8554 Section 5.4.2. Algorithm 6: Steps 3 & 4
101  *
102  * @param lms_sig Is a valid decoded LMS_SIG signature object.
103  * @param pub Is a valid LMS public key object.
104  * @param md Contains the fetched digest to be used for Hash operations
105  * @param msg A message to verify
106  * @param msglen The size of |msg|
107  * @returns 1 if the verification succeeded, or 0 otherwise.
108  */
ossl_lms_sig_verify(const LMS_SIG * lms_sig,const LMS_KEY * pub,const EVP_MD * md,const unsigned char * msg,size_t msglen)109 int ossl_lms_sig_verify(const LMS_SIG *lms_sig, const LMS_KEY *pub,
110                         const EVP_MD *md,
111                         const unsigned char *msg, size_t msglen)
112 {
113     int ret = 0;
114     EVP_MD_CTX *ctx = NULL, *ctxIq = NULL;
115     EVP_MD_CTX *ctxI;
116     unsigned char Kc[LMS_MAX_DIGEST_SIZE];
117     unsigned char Tc[LMS_MAX_DIGEST_SIZE];
118     unsigned char qbuf[4];
119     unsigned char d_leaf[sizeof(uint16_t)];
120     const LMS_PARAMS *lms_params = pub->lms_params;
121     uint32_t n = lms_params->n;
122     uint32_t node_num;
123 
124     ctx = EVP_MD_CTX_create();
125     ctxIq = EVP_MD_CTX_create();
126     if (ctx == NULL || ctxIq == NULL)
127         goto err;
128 
129     if (!lms_evp_md_ctx_init(ctxIq, md, lms_sig->params))
130         goto err;
131     /*
132      * Algorithm 6a: Step 3.
133      * Calculate a candidate public key |Kc| using the lmots_signature, message,
134      * and the identifiers I, q
135      */
136     if (!ossl_lm_ots_compute_pubkey(ctx, ctxIq, &lms_sig->sig,
137                                     pub->ots_params, pub->Id,
138                                     lms_sig->q, msg, msglen, Kc))
139         goto err;
140 
141     /*
142      * Algorithm 6a: Step 4
143      * Compute the candidate LMS root value Tc
144      */
145     if (!ossl_assert(lms_sig->q < (uint32_t)(1 << lms_params->h)))
146         return 0;
147     node_num = (1 << lms_params->h) + lms_sig->q;
148 
149     OPENSSL_store_u32_be(qbuf, node_num);
150     OPENSSL_store_u16_be(d_leaf, OSSL_LMS_D_LEAF);
151     ctxI = ctxIq;
152     /*
153      * Tc = H(I || u32str(node_num) || u16str(D_LEAF) || Kc)
154      *
155      * ctx is left initialised with the md from ossl_lm_ots_compute_pubkey,
156      * so there is no need to reinitialise it here.
157      */
158     if (!EVP_DigestInit_ex2(ctx, NULL, NULL)
159             || !EVP_DigestUpdate(ctx, pub->Id, LMS_SIZE_I)
160             || !EVP_MD_CTX_copy_ex(ctxI, ctx)
161             || !EVP_DigestUpdate(ctx, qbuf, sizeof(qbuf))
162             || !EVP_DigestUpdate(ctx, d_leaf, sizeof(d_leaf))
163             || !EVP_DigestUpdate(ctx, Kc, n)
164             || !EVP_DigestFinal_ex(ctx, Tc, NULL)
165             || !lms_sig_compute_tc_from_path(lms_sig->paths, n, node_num,
166                                              ctx, ctxI, Tc))
167         goto err;
168     /* Algorithm 6: Step 4 */
169     ret = (memcmp(pub->pub.K, Tc, n) == 0);
170 err:
171     EVP_MD_CTX_free(ctxIq);
172     EVP_MD_CTX_free(ctx);
173     return ret;
174 }
175