tls_key_material.c
Go to the documentation of this file.
1 /**
2  * @file tls_key_material.c
3  * @brief Key material generation
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSL Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TLS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "tls/tls.h"
36 #include "tls/tls_key_material.h"
38 #include "kdf/tls_kdf.h"
39 #include "debug.h"
40 
41 //Check TLS library configuration
42 #if (TLS_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Generate session keys
47  * @param[in] context Pointer to the TLS context
48  * @return Error code
49  **/
50 
52 {
53 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
54  error_t error;
55  size_t keyBlockLen;
57 
58  //Point to the negotiated cipher suite
59  cipherSuite = &context->cipherSuite;
60 
61  //Length of necessary key material
62  keyBlockLen = 2 * (cipherSuite->macKeyLen + cipherSuite->encKeyLen +
63  cipherSuite->fixedIvLen);
64 
65  //Make sure that the key block is large enough
66  if(keyBlockLen > sizeof(context->keyBlock))
67  return ERROR_FAILURE;
68 
69  //Debug message
70  TRACE_DEBUG("Generating session keys...\r\n");
71  TRACE_DEBUG(" Client random bytes:\r\n");
72  TRACE_DEBUG_ARRAY(" ", context->clientRandom, 32);
73  TRACE_DEBUG(" Server random bytes:\r\n");
74  TRACE_DEBUG_ARRAY(" ", context->serverRandom, 32);
75 
76  //If a full handshake is being performed, the premaster secret shall be
77  //first converted to the master secret
78  if(!context->resume)
79  {
80  //Debug message
81  TRACE_DEBUG(" Premaster secret:\r\n");
82  TRACE_DEBUG_ARRAY(" ", context->premasterSecret, context->premasterSecretLen);
83 
84 #if (TLS_EXT_MASTER_SECRET_SUPPORT == ENABLED)
85  //If both the ClientHello and ServerHello contain the ExtendedMasterSecret
86  //extension, the new session uses the extended master secret computation
87  if(context->emsExtReceived)
88  {
89  //Extended master secret computation
90  error = tlsGenerateExtendedMasterSecret(context);
91  }
92  else
93 #endif
94  {
95  //Legacy master secret computation
96  error = tlsGenerateMasterSecret(context);
97  }
98 
99  //Failed to generate master secret?
100  if(error)
101  return error;
102 
103  //The premaster secret should be deleted from memory once the master
104  //secret has been computed
105  osMemset(context->premasterSecret, 0, TLS_PREMASTER_SECRET_SIZE);
106  }
107 
108  //Debug message
109  TRACE_DEBUG(" Master secret:\r\n");
110  TRACE_DEBUG_ARRAY(" ", context->masterSecret, TLS_MASTER_SECRET_SIZE);
111 
112 #if (TLS_KEY_LOG_SUPPORT == ENABLED)
113  //Log master secret
114  tlsDumpSecret(context, "CLIENT_RANDOM", context->masterSecret,
116 #endif
117 
118  //The master secret is used as an entropy source to generate the key material
119  error = tlsGenerateKeyBlock(context, keyBlockLen);
120  //Any error to report?
121  if(error)
122  return error;
123 
124  //Debug message
125  TRACE_DEBUG(" Key block:\r\n");
126  TRACE_DEBUG_ARRAY(" ", context->keyBlock, keyBlockLen);
127 
128  //Successful processing
129  return NO_ERROR;
130 #else
131  //Not implemented
132  return ERROR_NOT_IMPLEMENTED;
133 #endif
134 }
135 
136 
137 /**
138  * @brief Master secret computation
139  * @param[in] context Pointer to the TLS context
140  * @return Error code
141  **/
142 
144 {
145  error_t error;
146  uint8_t random[2 * TLS_RANDOM_SIZE];
147 
148  //Concatenate client_random and server_random values
149  osMemcpy(random, context->clientRandom, TLS_RANDOM_SIZE);
150  osMemcpy(random + 32, context->serverRandom, TLS_RANDOM_SIZE);
151 
152 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
153  //TLS 1.0 or TLS 1.1 currently selected?
154  if(context->version == TLS_VERSION_1_0 || context->version == TLS_VERSION_1_1)
155  {
156  //TLS 1.0 and 1.1 use a PRF that combines MD5 and SHA-1
157  error = tlsPrf(context->premasterSecret, context->premasterSecretLen,
158  "master secret", random, sizeof(random), context->masterSecret,
160  }
161  else
162 #endif
163 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
164  //TLS 1.2 currently selected?
165  if(context->version == TLS_VERSION_1_2)
166  {
167  //TLS 1.2 PRF uses SHA-256 or a stronger hash algorithm as the core
168  //function in its construction
169  error = tls12Prf(context->cipherSuite.prfHashAlgo,
170  context->premasterSecret, context->premasterSecretLen,
171  "master secret", random, sizeof(random), context->masterSecret,
173  }
174  else
175 #endif
176  //Invalid TLS version?
177  {
178  //Report an error
179  error = ERROR_INVALID_VERSION;
180  }
181 
182  //Return status code
183  return error;
184 }
185 
186 
187 /**
188  * @brief Extended master secret computation
189  * @param[in] context Pointer to the TLS context
190  * @return Error code
191  **/
192 
194 {
195 #if (TLS_EXT_MASTER_SECRET_SUPPORT == ENABLED)
196  error_t error;
197 
198 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
199  //TLS 1.0 or TLS 1.1 currently selected?
200  if(context->version == TLS_VERSION_1_0 || context->version == TLS_VERSION_1_1)
201  {
202  //A temporary buffer is needed to concatenate MD5 and SHA-1 hash
203  //values before computing the extended master secret
204  uint8_t sessionHash[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE];
205 
206  //Finalize MD5 hash computation
207  error = tlsFinalizeTranscriptHash(context, MD5_HASH_ALGO,
208  context->transcriptMd5Context, sessionHash);
209 
210  //Check status code
211  if(!error)
212  {
213  //Finalize SHA-1 hash computation
214  error = tlsFinalizeTranscriptHash(context, SHA1_HASH_ALGO,
215  context->transcriptSha1Context, sessionHash + MD5_DIGEST_SIZE);
216  }
217 
218  //Check status code
219  if(!error)
220  {
221  //Compute the extended master secret (refer to RFC 7627, section 4)
222  error = tlsPrf(context->premasterSecret, context->premasterSecretLen,
223  "extended master secret", sessionHash, sizeof(sessionHash),
224  context->masterSecret, TLS_MASTER_SECRET_SIZE);
225  }
226  }
227  else
228 #endif
229 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
230  //TLS 1.2 currently selected?
231  if(context->version == TLS_VERSION_1_2)
232  {
233  const HashAlgo *hashAlgo;
234  HashContext *hashContext;
235  uint8_t digest[MAX_HASH_DIGEST_SIZE];
236 
237  //Point to the hash algorithm to be used
238  hashAlgo = context->cipherSuite.prfHashAlgo;
239 
240  //Allocate hash algorithm context
241  hashContext = tlsAllocMem(hashAlgo->contextSize);
242 
243  //Successful memory allocation?
244  if(hashContext != NULL)
245  {
246  //The original hash context must be preserved
247  osMemcpy(hashContext, context->transcriptHashContext,
248  hashAlgo->contextSize);
249 
250  //Finalize hash computation
251  hashAlgo->final(hashContext, digest);
252 
253  //Compute the extended master secret (refer to RFC 7627, section 4)
254  error = tls12Prf(hashAlgo, context->premasterSecret,
255  context->premasterSecretLen, "extended master secret",
256  digest, hashAlgo->digestSize, context->masterSecret,
258 
259  //Release previously allocated memory
260  tlsFreeMem(hashContext);
261  }
262  else
263  {
264  //Failed to allocate memory
265  error = ERROR_OUT_OF_MEMORY;
266  }
267  }
268  else
269 #endif
270  //Invalid TLS version?
271  {
272  //Report an error
273  error = ERROR_INVALID_VERSION;
274  }
275 
276  //Return status code
277  return error;
278 #else
279  //Extended master secret computation is not implemented
280  return ERROR_NOT_IMPLEMENTED;
281 #endif
282 }
283 
284 
285 /**
286  * @brief Premaster secret generation (for PSK cipher suites)
287  * @param[in] context Pointer to the TLS context
288  * @return Error code
289  **/
290 
292 {
293  error_t error;
294 
295 #if (TLS_PSK_KE_SUPPORT == ENABLED)
296  //PSK key exchange method?
297  if(context->keyExchMethod == TLS_KEY_EXCH_PSK)
298  {
299  size_t n;
300 
301  //Let N be the length of pre-shared key
302  n = context->pskLen;
303 
304  //Check whether the output buffer is large enough to hold the premaster
305  //secret
306  if((n * 2 + 4) <= TLS_PREMASTER_SECRET_SIZE)
307  {
308  //The premaster secret is formed as follows: if the PSK is N octets
309  //long, concatenate a uint16 with the value N, N zero octets, a second
310  //uint16 with the value N, and the PSK itself
311  STORE16BE(n, context->premasterSecret);
312  osMemset(context->premasterSecret + 2, 0, n);
313  STORE16BE(n, context->premasterSecret + n + 2);
314  osMemcpy(context->premasterSecret + n + 4, context->psk, n);
315 
316  //Save the length of the premaster secret
317  context->premasterSecretLen = n * 2 + 4;
318 
319  //Premaster secret successfully generated
320  error = NO_ERROR;
321  }
322  else
323  {
324  //Report an error
325  error = ERROR_BUFFER_OVERFLOW;
326  }
327  }
328  else
329 #endif
330 #if (TLS_RSA_PSK_KE_SUPPORT == ENABLED || TLS_DHE_PSK_KE_SUPPORT == ENABLED || \
331  TLS_ECDHE_PSK_KE_SUPPORT == ENABLED)
332  //RSA_PSK, DHE_PSK or ECDHE_PSK key exchange method?
333  if(context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK ||
334  context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
335  context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
336  {
337  size_t n;
338 
339  //Let N be the length of pre-shared key
340  n = context->pskLen;
341 
342  //Check whether the output buffer is large enough to hold the premaster
343  //secret
344  if((context->premasterSecretLen + n + 4) <= TLS_PREMASTER_SECRET_SIZE)
345  {
346  //The "other_secret" field comes from the Diffie-Hellman, ECDH or
347  //RSA exchange (DHE_PSK, ECDH_PSK and RSA_PSK, respectively)
348  osMemmove(context->premasterSecret + 2, context->premasterSecret,
349  context->premasterSecretLen);
350 
351  //The "other_secret" field is preceded by a 2-byte length field
352  STORE16BE(context->premasterSecretLen, context->premasterSecret);
353 
354  //if the PSK is N octets long, concatenate a uint16 with the value N
355  STORE16BE(n, context->premasterSecret + context->premasterSecretLen + 2);
356 
357  //Concatenate the PSK itself
358  osMemcpy(context->premasterSecret + context->premasterSecretLen + 4,
359  context->psk, n);
360 
361  //Adjust the length of the premaster secret
362  context->premasterSecretLen += n + 4;
363 
364  //Premaster secret successfully generated
365  error = NO_ERROR;
366  }
367  else
368  {
369  //Report an error
370  error = ERROR_BUFFER_OVERFLOW;
371  }
372  }
373  else
374 #endif
375  //Invalid key exchange method?
376  {
377  //The specified key exchange method is not supported
379  }
380 
381  //Return status code
382  return error;
383 }
384 
385 
386 /**
387  * @brief Key expansion function
388  * @param[in] context Pointer to the TLS context
389  * @param[in] keyBlockLen Desired length for the resulting key block
390  * @return Error code
391  **/
392 
393 __weak_func error_t tlsGenerateKeyBlock(TlsContext *context, size_t keyBlockLen)
394 {
395  error_t error;
396  uint8_t random[2 * TLS_RANDOM_SIZE];
397 
398  //Concatenate server_random and client_random values
399  osMemcpy(random, context->serverRandom, TLS_RANDOM_SIZE);
400  osMemcpy(random + 32, context->clientRandom, TLS_RANDOM_SIZE);
401 
402 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
403  //TLS 1.0 or TLS 1.1 currently selected?
404  if(context->version == TLS_VERSION_1_0 || context->version == TLS_VERSION_1_1)
405  {
406  //TLS 1.0 and 1.1 use a PRF that combines MD5 and SHA-1
407  error = tlsPrf(context->masterSecret, TLS_MASTER_SECRET_SIZE,
408  "key expansion", random, sizeof(random), context->keyBlock,
409  keyBlockLen);
410  }
411  else
412 #endif
413 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
414  //TLS 1.2 currently selected?
415  if(context->version == TLS_VERSION_1_2)
416  {
417  //TLS 1.2 PRF uses SHA-256 or a stronger hash algorithm as the core
418  //function in its construction
419  error = tls12Prf(context->cipherSuite.prfHashAlgo,
420  context->masterSecret, TLS_MASTER_SECRET_SIZE, "key expansion",
421  random, sizeof(random), context->keyBlock, keyBlockLen);
422  }
423  else
424 #endif
425  //Invalid TLS version?
426  {
427  //Report an error
428  error = ERROR_INVALID_VERSION;
429  }
430 
431  //Return status code
432  return error;
433 }
434 
435 
436 /**
437  * @brief Dump secret key (for debugging purpose only)
438  * @param[in] context Pointer to the TLS context
439  * @param[in] label Identifying label (NULL-terminated string)
440  * @param[in] secret Pointer to the secret key
441  * @param[in] secretLen Length of the secret key, in bytes
442  **/
443 
444 void tlsDumpSecret(TlsContext *context, const char_t *label,
445  const uint8_t *secret, size_t secretLen)
446 {
447 #if (TLS_KEY_LOG_SUPPORT == ENABLED)
448  //Any registered callback?
449  if(context->keyLogCallback != NULL)
450  {
451  size_t i;
452  size_t n;
453  char_t buffer[194];
454 
455  //Retrieve the length of the label
456  n = osStrlen(label);
457 
458  //Sanity check
459  if((n + 2 * secretLen + 67) <= sizeof(buffer))
460  {
461  //Copy the identifying label
462  osStrncpy(buffer, label, n);
463 
464  //Append a space character
465  buffer[n++] = ' ';
466 
467  //Convert the client random value to a hex string
468  for(i = 0; i < 32; i++)
469  {
470  //Format current byte
471  n += osSprintf(buffer + n, "%02" PRIX8, context->clientRandom[i]);
472  }
473 
474  //Append a space character
475  buffer[n++] = ' ';
476 
477  //Convert the secret key to a hex string
478  for(i = 0; i < secretLen; i++)
479  {
480  //Format current byte
481  n += osSprintf(buffer + n, "%02" PRIX8, secret[i]);
482  }
483 
484  //Properly terminate the string with a NULL character
485  buffer[n] = '\0';
486 
487  //Invoke user callback function
488  context->keyLogCallback(context, buffer);
489  }
490  }
491 #endif
492 }
493 
494 #endif
#define tlsAllocMem(size)
Definition: tls.h:911
Generic hash algorithm context.
uint16_t cipherSuite
Cipher suite identifier.
Definition: tls.h:2052
#define SHA1_HASH_ALGO
Definition: sha1.h:49
error_t tls12Prf(const HashAlgo *hashAlgo, const uint8_t *secret, size_t secretLen, const char_t *label, const uint8_t *seed, size_t seedLen, uint8_t *output, size_t outputLen)
Pseudorandom function (TLS 1.2)
Definition: tls_kdf.c:187
Key material generation.
error_t tlsGeneratePskPremasterSecret(TlsContext *context)
Premaster secret generation (for PSK cipher suites)
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:143
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
__weak_func error_t tlsGenerateMasterSecret(TlsContext *context)
Master secret computation.
error_t tlsPrf(const uint8_t *secret, size_t secretLen, const char_t *label, const uint8_t *seed, size_t seedLen, uint8_t *output, size_t outputLen)
Pseudorandom function (TLS 1.0 and 1.1)
Definition: tls_kdf.c:62
size_t digestSize
Definition: crypto.h:1249
void tlsDumpSecret(TlsContext *context, const char_t *label, const uint8_t *secret, size_t secretLen)
Dump secret key (for debugging purpose only)
Structure describing a cipher suite.
Definition: tls.h:2222
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define osStrlen(s)
Definition: os_port.h:171
error_t tlsFinalizeTranscriptHash(TlsContext *context, const HashAlgo *hash, const void *hashContext, uint8_t *output)
Finalize hash calculation from previous handshake messages.
@ ERROR_INVALID_VERSION
Definition: error.h:118
#define TLS_RANDOM_SIZE
Definition: tls.h:1020
size_t contextSize
Definition: crypto.h:1247
TLS key derivation functions.
__weak_func error_t tlsGenerateKeyBlock(TlsContext *context, size_t keyBlockLen)
Key expansion function.
#define MAX_HASH_DIGEST_SIZE
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
#define TlsContext
Definition: tls.h:36
error_t
Error codes.
Definition: error.h:43
#define osSprintf(dest,...)
Definition: os_port.h:237
#define TLS_VERSION_1_2
Definition: tls.h:98
#define TLS_PREMASTER_SECRET_SIZE
Definition: tls.h:866
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define STORE16BE(a, p)
Definition: cpu_endian.h:262
#define MD5_HASH_ALGO
Definition: md5.h:49
@ TLS_KEY_EXCH_DHE_PSK
Definition: tls.h:1238
#define MD5_DIGEST_SIZE
Definition: md5.h:45
#define TLS_MASTER_SECRET_SIZE
Definition: tls.h:859
Transcript hash calculation.
uint8_t secret[TLS_MASTER_SECRET_SIZE]
Master secret.
Definition: tls.h:2053
@ ERROR_UNSUPPORTED_KEY_EXCH_ALGO
Definition: error.h:131
uint8_t random[32]
Definition: tls.h:1940
@ TLS_KEY_EXCH_RSA_PSK
Definition: tls.h:1237
HashAlgoFinal final
Definition: crypto.h:1255
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
#define TLS_VERSION_1_1
Definition: tls.h:97
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
error_t tlsGenerateExtendedMasterSecret(TlsContext *context)
Extended master secret computation.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
uint8_t n
#define TLS_VERSION_1_0
Definition: tls.h:96
@ TLS_KEY_EXCH_PSK
Definition: tls.h:1236
@ TLS_KEY_EXCH_ECDHE_PSK
Definition: tls.h:1239
#define osStrncpy(s1, s2, length)
Definition: os_port.h:219
TLS (Transport Layer Security)
Common interface for hash algorithms.
Definition: crypto.h:1243
error_t tlsGenerateSessionKeys(TlsContext *context)
Generate session keys.
#define osMemset(p, value, length)
Definition: os_port.h:141
#define tlsFreeMem(p)
Definition: tls.h:916
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:153