Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2024 DMTF. All rights reserved.
4 : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : **/
6 :
7 : /** @file
8 : * Diffie-Hellman Wrapper Implementation over.
9 : *
10 : * RFC 7919 - Negotiated Finite Field Diffie-Hellman Ephemeral (FFDHE) Parameters
11 : **/
12 :
13 : #include "internal_crypt_lib.h"
14 : #include <mbedtls/dhm.h>
15 : #include <mbedtls/bignum.h>
16 : #include <string.h>
17 :
18 : #if LIBSPDM_FFDHE_SUPPORT
19 :
20 : static const unsigned char m_ffehde2048_p[] =
21 : MBEDTLS_DHM_RFC7919_FFDHE2048_P_BIN;
22 : static const unsigned char m_ffehde3072_p[] =
23 : MBEDTLS_DHM_RFC7919_FFDHE3072_P_BIN;
24 : static const unsigned char m_ffehde4096_p[] =
25 : MBEDTLS_DHM_RFC7919_FFDHE4096_P_BIN;
26 : static const unsigned char m_ffehde2048_g[] =
27 : MBEDTLS_DHM_RFC7919_FFDHE2048_G_BIN;
28 : static const unsigned char m_ffehde3072_g[] =
29 : MBEDTLS_DHM_RFC7919_FFDHE3072_G_BIN;
30 : static const unsigned char m_ffehde4096_g[] =
31 : MBEDTLS_DHM_RFC7919_FFDHE4096_G_BIN;
32 :
33 : /**
34 : * Allocates and Initializes one Diffie-Hellman context for subsequent use
35 : * with the NID.
36 : *
37 : * @param nid cipher NID
38 : *
39 : * @return Pointer to the Diffie-Hellman context that has been initialized.
40 : * If the allocations fails, dh_new() returns NULL.
41 : *
42 : **/
43 2 : void *libspdm_dh_new_by_nid(size_t nid)
44 : {
45 : mbedtls_dhm_context *ctx;
46 : int ret;
47 :
48 2 : ctx = allocate_zero_pool(sizeof(mbedtls_dhm_context));
49 2 : if (ctx == NULL) {
50 0 : return NULL;
51 : }
52 :
53 2 : mbedtls_dhm_init(ctx);
54 :
55 2 : switch (nid) {
56 2 : case LIBSPDM_CRYPTO_NID_FFDHE2048:
57 2 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(P), m_ffehde2048_p,
58 : sizeof(m_ffehde2048_p));
59 2 : if (ret != 0) {
60 0 : goto error;
61 : }
62 2 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(G), m_ffehde2048_g,
63 : sizeof(m_ffehde2048_g));
64 2 : if (ret != 0) {
65 0 : goto error;
66 : }
67 2 : break;
68 0 : case LIBSPDM_CRYPTO_NID_FFDHE3072:
69 0 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(P), m_ffehde3072_p,
70 : sizeof(m_ffehde3072_p));
71 0 : if (ret != 0) {
72 0 : goto error;
73 : }
74 0 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(G), m_ffehde3072_g,
75 : sizeof(m_ffehde3072_g));
76 0 : if (ret != 0) {
77 0 : goto error;
78 : }
79 0 : break;
80 0 : case LIBSPDM_CRYPTO_NID_FFDHE4096:
81 0 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(P), m_ffehde4096_p,
82 : sizeof(m_ffehde4096_p));
83 0 : if (ret != 0) {
84 0 : goto error;
85 : }
86 0 : ret = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(G), m_ffehde4096_g,
87 : sizeof(m_ffehde4096_g));
88 0 : if (ret != 0) {
89 0 : goto error;
90 : }
91 0 : break;
92 0 : default:
93 0 : goto error;
94 : }
95 2 : return ctx;
96 0 : error:
97 0 : free_pool(ctx);
98 0 : return NULL;
99 : }
100 :
101 : /**
102 : * Release the specified DH context.
103 : *
104 : * If dh_context is NULL, then return false.
105 : *
106 : * @param[in] dh_context Pointer to the DH context to be released.
107 : *
108 : **/
109 2 : void libspdm_dh_free(void *dh_context)
110 : {
111 2 : mbedtls_dhm_free(dh_context);
112 2 : free_pool(dh_context);
113 2 : }
114 :
115 : /**
116 : * Generates DH parameter.
117 : *
118 : * Given generator g, and length of prime number p in bits, this function generates p,
119 : * and sets DH context according to value of g and p.
120 : *
121 : * If dh_context is NULL, then return false.
122 : * If prime is NULL, then return false.
123 : *
124 : * @param[in, out] dh_context Pointer to the DH context.
125 : * @param[in] generator value of generator.
126 : * @param[in] prime_length length in bits of prime to be generated.
127 : * @param[out] prime Pointer to the buffer to receive the generated prime number.
128 : *
129 : * @retval true DH parameter generation succeeded.
130 : * @retval false value of generator is not supported.
131 : * @retval false PRNG fails to generate random prime number with prime_length.
132 : *
133 : **/
134 0 : bool libspdm_dh_generate_parameter(void *dh_context, size_t generator,
135 : size_t prime_length, uint8_t *prime)
136 : {
137 0 : return false;
138 : }
139 :
140 : /**
141 : * Sets generator and prime parameters for DH.
142 : *
143 : * Given generator g, and prime number p, this function and sets DH
144 : * context accordingly.
145 : *
146 : * If dh_context is NULL, then return false.
147 : * If prime is NULL, then return false.
148 : *
149 : * @param[in, out] dh_context Pointer to the DH context.
150 : * @param[in] generator value of generator.
151 : * @param[in] prime_length length in bits of prime to be generated.
152 : * @param[in] prime Pointer to the prime number.
153 : *
154 : * @retval true DH parameter setting succeeded.
155 : * @retval false value of generator is not supported.
156 : * @retval false value of generator is not suitable for the prime.
157 : * @retval false value of prime is not a prime number.
158 : * @retval false value of prime is not a safe prime number.
159 : *
160 : **/
161 0 : bool libspdm_dh_set_parameter(void *dh_context, size_t generator,
162 : size_t prime_length, const uint8_t *prime)
163 : {
164 0 : return false;
165 : }
166 :
167 : /**
168 : * Generates DH public key.
169 : *
170 : * This function generates random secret exponent, and computes the public key, which is
171 : * returned via parameter public_key and public_key_size. DH context is updated accordingly.
172 : * If the public_key buffer is too small to hold the public key, false is returned and
173 : * public_key_size is set to the required buffer size to obtain the public key.
174 : *
175 : * If dh_context is NULL, then return false.
176 : * If public_key_size is NULL, then return false.
177 : * If public_key_size is large enough but public_key is NULL, then return false.
178 : *
179 : * For FFDHE2048, the public_size is 256.
180 : * For FFDHE3072, the public_size is 384.
181 : * For FFDHE4096, the public_size is 512.
182 : *
183 : * @param[in, out] dh_context Pointer to the DH context.
184 : * @param[out] public_key Pointer to the buffer to receive generated public key.
185 : * @param[in, out] public_key_size On input, the size of public_key buffer in bytes.
186 : * On output, the size of data returned in public_key buffer in bytes.
187 : *
188 : * @retval true DH public key generation succeeded.
189 : * @retval false DH public key generation failed.
190 : * @retval false public_key_size is not large enough.
191 : *
192 : **/
193 2 : bool libspdm_dh_generate_key(void *dh_context, uint8_t *public_key,
194 : size_t *public_key_size)
195 : {
196 : int ret;
197 : mbedtls_dhm_context *ctx;
198 : size_t final_pub_key_size;
199 :
200 :
201 : /* Check input parameters.*/
202 :
203 2 : if (dh_context == NULL || public_key_size == NULL) {
204 0 : return false;
205 : }
206 :
207 2 : if (public_key == NULL && *public_key_size != 0) {
208 0 : return false;
209 : }
210 :
211 2 : ctx = dh_context;
212 2 : switch (mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(P))) {
213 2 : case 256:
214 2 : final_pub_key_size = 256;
215 2 : break;
216 0 : case 384:
217 0 : final_pub_key_size = 384;
218 0 : break;
219 0 : case 512:
220 0 : final_pub_key_size = 512;
221 0 : break;
222 0 : default:
223 0 : return false;
224 : }
225 2 : if (*public_key_size < final_pub_key_size) {
226 0 : *public_key_size = final_pub_key_size;
227 0 : return false;
228 : }
229 2 : *public_key_size = final_pub_key_size;
230 2 : libspdm_zero_mem(public_key, *public_key_size);
231 :
232 2 : ret = mbedtls_dhm_make_public(dh_context, (uint32_t)*public_key_size,
233 2 : public_key, (uint32_t)*public_key_size,
234 : libspdm_myrand, NULL);
235 2 : if (ret != 0) {
236 0 : return false;
237 : }
238 :
239 2 : return true;
240 : }
241 :
242 : /**
243 : * Computes exchanged common key.
244 : *
245 : * Given peer's public key, this function computes the exchanged common key, based on its own
246 : * context including value of prime modulus and random secret exponent.
247 : *
248 : * If dh_context is NULL, then return false.
249 : * If peer_public_key is NULL, then return false.
250 : * If key_size is NULL, then return false.
251 : * If key is NULL, then return false.
252 : * If key_size is not large enough, then return false.
253 : *
254 : * For FFDHE2048, the peer_public_size is 256.
255 : * For FFDHE3072, the peer_public_size is 384.
256 : * For FFDHE4096, the peer_public_size is 512.
257 : *
258 : * @param[in, out] dh_context Pointer to the DH context.
259 : * @param[in] peer_public_key Pointer to the peer's public key.
260 : * @param[in] peer_public_key_size size of peer's public key in bytes.
261 : * @param[out] key Pointer to the buffer to receive generated key.
262 : * @param[in, out] key_size On input, the size of key buffer in bytes.
263 : * On output, the size of data returned in key buffer in bytes.
264 : *
265 : * @retval true DH exchanged key generation succeeded.
266 : * @retval false DH exchanged key generation failed.
267 : * @retval false key_size is not large enough.
268 : *
269 : **/
270 2 : bool libspdm_dh_compute_key(void *dh_context, const uint8_t *peer_public_key,
271 : size_t peer_public_key_size, uint8_t *key,
272 : size_t *key_size)
273 : {
274 : int ret;
275 : mbedtls_dhm_context *ctx;
276 : size_t return_size;
277 : size_t dh_key_size;
278 :
279 : /* Check input parameters.*/
280 :
281 2 : if (dh_context == NULL || peer_public_key == NULL || key_size == NULL ||
282 : key == NULL) {
283 0 : return false;
284 : }
285 :
286 2 : if (peer_public_key_size > INT_MAX) {
287 0 : return false;
288 : }
289 :
290 2 : ctx = dh_context;
291 2 : switch (mbedtls_mpi_size(&ctx->MBEDTLS_PRIVATE(P))) {
292 2 : case 256:
293 2 : dh_key_size = 256;
294 2 : break;
295 0 : case 384:
296 0 : dh_key_size = 384;
297 0 : break;
298 0 : case 512:
299 0 : dh_key_size = 512;
300 0 : break;
301 0 : default:
302 0 : return false;
303 : }
304 2 : if (peer_public_key_size != dh_key_size) {
305 0 : return false;
306 : }
307 2 : if (*key_size < dh_key_size) {
308 0 : return false;
309 : }
310 2 : *key_size = dh_key_size;
311 :
312 2 : ret = mbedtls_dhm_read_public(dh_context, peer_public_key,
313 : peer_public_key_size);
314 2 : if (ret != 0) {
315 0 : return false;
316 : }
317 :
318 2 : return_size = 0;
319 2 : ret = mbedtls_dhm_calc_secret(dh_context, key, *key_size, &return_size,
320 : libspdm_myrand, NULL);
321 2 : if (ret != 0) {
322 0 : return false;
323 : }
324 :
325 : /*change the key, for example: from 0x123400 to 0x001234*/
326 2 : if (return_size < dh_key_size) {
327 0 : memmove(key + dh_key_size - return_size, key, return_size);
328 0 : libspdm_zero_mem(key, dh_key_size - return_size);
329 : }
330 :
331 2 : return true;
332 : }
333 :
334 : #endif /* LIBSPDM_FFDHE_SUPPORT */
|