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-2024 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.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TLS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "tls.h"
36 #include "tls_key_material.h"
37 #include "tls_transcript_hash.h"
38 #include "tls13_key_material.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 
236  //Point to the hash algorithm to be used
237  hashAlgo = context->cipherSuite.prfHashAlgo;
238 
239  //Allocate hash algorithm context
240  hashContext = tlsAllocMem(hashAlgo->contextSize);
241 
242  //Successful memory allocation?
243  if(hashContext != NULL)
244  {
245  //The original hash context must be preserved
246  osMemcpy(hashContext, context->transcriptHashContext,
247  hashAlgo->contextSize);
248 
249  //Finalize hash computation
250  hashAlgo->final(hashContext, NULL);
251 
252  //Compute the extended master secret (refer to RFC 7627, section 4)
253  error = tls12Prf(hashAlgo, context->premasterSecret,
254  context->premasterSecretLen, "extended master secret",
255  hashContext->digest, hashAlgo->digestSize,
256  context->masterSecret, TLS_MASTER_SECRET_SIZE);
257 
258  //Release previously allocated memory
259  tlsFreeMem(hashContext);
260  }
261  else
262  {
263  //Failed to allocate memory
264  error = ERROR_OUT_OF_MEMORY;
265  }
266  }
267  else
268 #endif
269  //Invalid TLS version?
270  {
271  //Report an error
272  error = ERROR_INVALID_VERSION;
273  }
274 
275  //Return status code
276  return error;
277 #else
278  //Extended master secret computation is not implemented
279  return ERROR_NOT_IMPLEMENTED;
280 #endif
281 }
282 
283 
284 /**
285  * @brief Premaster secret generation (for PSK cipher suites)
286  * @param[in] context Pointer to the TLS context
287  * @return Error code
288  **/
289 
291 {
292  error_t error;
293 
294 #if (TLS_PSK_KE_SUPPORT == ENABLED)
295  //PSK key exchange method?
296  if(context->keyExchMethod == TLS_KEY_EXCH_PSK)
297  {
298  size_t n;
299 
300  //Let N be the length of pre-shared key
301  n = context->pskLen;
302 
303  //Check whether the output buffer is large enough to hold the premaster
304  //secret
305  if((n * 2 + 4) <= TLS_PREMASTER_SECRET_SIZE)
306  {
307  //The premaster secret is formed as follows: if the PSK is N octets
308  //long, concatenate a uint16 with the value N, N zero octets, a second
309  //uint16 with the value N, and the PSK itself
310  STORE16BE(n, context->premasterSecret);
311  osMemset(context->premasterSecret + 2, 0, n);
312  STORE16BE(n, context->premasterSecret + n + 2);
313  osMemcpy(context->premasterSecret + n + 4, context->psk, n);
314 
315  //Save the length of the premaster secret
316  context->premasterSecretLen = n * 2 + 4;
317 
318  //Premaster secret successfully generated
319  error = NO_ERROR;
320  }
321  else
322  {
323  //Report an error
324  error = ERROR_BUFFER_OVERFLOW;
325  }
326  }
327  else
328 #endif
329 #if (TLS_RSA_PSK_KE_SUPPORT == ENABLED || TLS_DHE_PSK_KE_SUPPORT == ENABLED || \
330  TLS_ECDHE_PSK_KE_SUPPORT == ENABLED)
331  //RSA_PSK, DHE_PSK or ECDHE_PSK key exchange method?
332  if(context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK ||
333  context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
334  context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
335  {
336  size_t n;
337 
338  //Let N be the length of pre-shared key
339  n = context->pskLen;
340 
341  //Check whether the output buffer is large enough to hold the premaster
342  //secret
343  if((context->premasterSecretLen + n + 4) <= TLS_PREMASTER_SECRET_SIZE)
344  {
345  //The "other_secret" field comes from the Diffie-Hellman, ECDH or
346  //RSA exchange (DHE_PSK, ECDH_PSK and RSA_PSK, respectively)
347  osMemmove(context->premasterSecret + 2, context->premasterSecret,
348  context->premasterSecretLen);
349 
350  //The "other_secret" field is preceded by a 2-byte length field
351  STORE16BE(context->premasterSecretLen, context->premasterSecret);
352 
353  //if the PSK is N octets long, concatenate a uint16 with the value N
354  STORE16BE(n, context->premasterSecret + context->premasterSecretLen + 2);
355 
356  //Concatenate the PSK itself
357  osMemcpy(context->premasterSecret + context->premasterSecretLen + 4,
358  context->psk, n);
359 
360  //Adjust the length of the premaster secret
361  context->premasterSecretLen += n + 4;
362 
363  //Premaster secret successfully generated
364  error = NO_ERROR;
365  }
366  else
367  {
368  //Report an error
369  error = ERROR_BUFFER_OVERFLOW;
370  }
371  }
372  else
373 #endif
374  //Invalid key exchange method?
375  {
376  //The specified key exchange method is not supported
378  }
379 
380  //Return status code
381  return error;
382 }
383 
384 
385 /**
386  * @brief Key expansion function
387  * @param[in] context Pointer to the TLS context
388  * @param[in] keyBlockLen Desired length for the resulting key block
389  * @return Error code
390  **/
391 
392 __weak_func error_t tlsGenerateKeyBlock(TlsContext *context, size_t keyBlockLen)
393 {
394  error_t error;
395  uint8_t random[2 * TLS_RANDOM_SIZE];
396 
397  //Concatenate server_random and client_random values
398  osMemcpy(random, context->serverRandom, TLS_RANDOM_SIZE);
399  osMemcpy(random + 32, context->clientRandom, TLS_RANDOM_SIZE);
400 
401 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
402  //TLS 1.0 or TLS 1.1 currently selected?
403  if(context->version == TLS_VERSION_1_0 || context->version == TLS_VERSION_1_1)
404  {
405  //TLS 1.0 and 1.1 use a PRF that combines MD5 and SHA-1
406  error = tlsPrf(context->masterSecret, TLS_MASTER_SECRET_SIZE,
407  "key expansion", random, sizeof(random), context->keyBlock,
408  keyBlockLen);
409  }
410  else
411 #endif
412 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
413  //TLS 1.2 currently selected?
414  if(context->version == TLS_VERSION_1_2)
415  {
416  //TLS 1.2 PRF uses SHA-256 or a stronger hash algorithm as the core
417  //function in its construction
418  error = tls12Prf(context->cipherSuite.prfHashAlgo,
419  context->masterSecret, TLS_MASTER_SECRET_SIZE, "key expansion",
420  random, sizeof(random), context->keyBlock, keyBlockLen);
421  }
422  else
423 #endif
424  //Invalid TLS version?
425  {
426  //Report an error
427  error = ERROR_INVALID_VERSION;
428  }
429 
430  //Return status code
431  return error;
432 }
433 
434 
435 /**
436  * @brief Export keying material per RFC 5705 standard
437  * @param[in] context Pointer to the TLS context
438  * @param[in] label Identifying label (NULL-terminated string)
439  * @param[in] useContextValue Specifies whether upper-layer context should
440  * be used when exporting keying material
441  * @param[in] contextValue Pointer to the upper-layer context
442  * @param[in] contextValueLen Length of the upper-layer context
443  * @param[out] output Pointer to the output
444  * @param[in] outputLen Desired output length
445  * @return Error code
446  **/
447 
449  bool_t useContextValue, const uint8_t *contextValue,
450  size_t contextValueLen, uint8_t *output, size_t outputLen)
451 {
452  error_t error;
453  size_t n;
454  uint8_t *seed;
455 
456  //Invalid TLS context?
457  if(context == NULL)
459 
460  //Check parameters
461  if(label == NULL || output == NULL)
463 
464  //Make sure the upper-layer context is valid
465  if(contextValue == NULL && contextValueLen != 0)
467 
468  //Calculate the length of the seed
469  n = 2 * TLS_RANDOM_SIZE;
470 
471  //Check whether a context is provided
472  if(useContextValue)
473  {
474  n += contextValueLen + 2;
475  }
476 
477  //Allocate a memory buffer to hold the seed
478  seed = tlsAllocMem(n);
479  //Failed to allocate memory?
480  if(seed == NULL)
481  return ERROR_OUT_OF_RESOURCES;
482 
483  //Concatenate client_random and server_random values
484  osMemcpy(seed, context->clientRandom, TLS_RANDOM_SIZE);
485  osMemcpy(seed + 32, context->serverRandom, TLS_RANDOM_SIZE);
486 
487  //Check whether a context is provided
488  if(useContextValue)
489  {
490  //The context_value_length is encoded as an unsigned, 16-bit quantity
491  //representing the length of the context value
492  STORE16BE(contextValueLen, seed + 64);
493 
494  //Copy the context value provided by the application using the exporter
495  osMemcpy(seed + 66, contextValue, contextValueLen);
496  }
497 
498 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
499  //TLS 1.0 or TLS 1.1 currently selected?
500  if(context->version == TLS_VERSION_1_0 || context->version == TLS_VERSION_1_1)
501  {
502  //TLS 1.0 and 1.1 use a PRF that combines MD5 and SHA-1
503  error = tlsPrf(context->masterSecret, TLS_MASTER_SECRET_SIZE,
504  label, seed, n, output, outputLen);
505  }
506  else
507 #endif
508 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
509  //TLS 1.2 currently selected?
510  if(context->version == TLS_VERSION_1_2)
511  {
512  //Make sure the PRF hash algorithm is valid
513  if(context->cipherSuite.prfHashAlgo != NULL)
514  {
515  //TLS 1.2 PRF uses SHA-256 or a stronger hash algorithm as the core
516  //function in its construction
517  error = tls12Prf(context->cipherSuite.prfHashAlgo, context->masterSecret,
518  TLS_MASTER_SECRET_SIZE, label, seed, n, output, outputLen);
519  }
520  else
521  {
522  //Invalid PRF hash algorithm
523  error = ERROR_FAILURE;
524  }
525  }
526  else
527 #endif
528 #if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
529  //TLS 1.3 currently selected?
530  if(context->version == TLS_VERSION_1_3)
531  {
532  const HashAlgo *hash;
534  uint8_t digest[TLS_MAX_HKDF_DIGEST_SIZE];
535 
536  //The hash function used by HKDF is the cipher suite hash algorithm
537  hash = context->cipherSuite.prfHashAlgo;
538 
539  //Make sure the HKDF hash algorithm is valid
540  if(hash != NULL)
541  {
542  //Derive exporter master secret
543  error = tls13DeriveSecret(context, context->exporterMasterSecret,
544  hash->digestSize, label, "", 0, secret, hash->digestSize);
545 
546  //Check status code
547  if(!error)
548  {
549  //Hash context_value input
550  error = hash->compute(contextValue, contextValueLen, digest);
551  }
552 
553  //Check status code
554  if(!error)
555  {
556  //Export keying material
557  error = tls13HkdfExpandLabel(context->transportProtocol, hash,
558  secret, hash->digestSize, "exporter", digest, hash->digestSize,
559  output, outputLen);
560  }
561  }
562  else
563  {
564  //Invalid HKDF hash algorithm
565  error = ERROR_FAILURE;
566  }
567  }
568  else
569 #endif
570  //Invalid TLS version?
571  {
572  //Report an error
573  error = ERROR_INVALID_VERSION;
574  }
575 
576  //Release previously allocated memory
577  tlsFreeMem(seed);
578 
579  //Return status code
580  return error;
581 }
582 
583 
584 /**
585  * @brief Pseudorandom function (TLS 1.0 and 1.1)
586  *
587  * The pseudorandom function (PRF) takes as input a secret, a seed, and
588  * an identifying label and produces an output of arbitrary length. This
589  * function is used to expand secrets into blocks of data for the purpose
590  * of key generation
591  *
592  * @param[in] secret Pointer to the secret
593  * @param[in] secretLen Length of the secret
594  * @param[in] label Identifying label (NULL-terminated string)
595  * @param[in] seed Pointer to the seed
596  * @param[in] seedLen Length of the seed
597  * @param[out] output Pointer to the output
598  * @param[in] outputLen Desired output length
599  * @return Error code
600  **/
601 
602 error_t tlsPrf(const uint8_t *secret, size_t secretLen, const char_t *label,
603  const uint8_t *seed, size_t seedLen, uint8_t *output, size_t outputLen)
604 {
605 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
606  error_t error;
607  uint_t i;
608  uint_t j;
609  size_t labelLen;
610  size_t sLen;
611  const uint8_t *s1;
612  const uint8_t *s2;
613  HmacContext *hmacContext;
614  uint8_t a[SHA1_DIGEST_SIZE];
615 
616  //Allocate a memory buffer to hold the HMAC context
617  hmacContext = tlsAllocMem(sizeof(HmacContext));
618 
619  //Successful memory allocation?
620  if(hmacContext != NULL)
621  {
622  //Retrieve the length of the label
623  labelLen = osStrlen(label);
624 
625  //The secret is partitioned into two halves S1 and S2
626  //with the possibility of one shared byte
627  sLen = (secretLen + 1) / 2;
628  //S1 is taken from the first half of the secret
629  s1 = secret;
630  //S2 is taken from the second half
631  s2 = secret + secretLen - sLen;
632 
633  //First compute A(1) = HMAC_MD5(S1, label + seed)
634  hmacInit(hmacContext, MD5_HASH_ALGO, s1, sLen);
635  hmacUpdate(hmacContext, label, labelLen);
636  hmacUpdate(hmacContext, seed, seedLen);
637  hmacFinal(hmacContext, a);
638 
639  //Apply the data expansion function P_MD5
640  for(i = 0; i < outputLen; )
641  {
642  //Compute HMAC_MD5(S1, A(i) + label + seed)
643  hmacInit(hmacContext, MD5_HASH_ALGO, s1, sLen);
644  hmacUpdate(hmacContext, a, MD5_DIGEST_SIZE);
645  hmacUpdate(hmacContext, label, labelLen);
646  hmacUpdate(hmacContext, seed, seedLen);
647  hmacFinal(hmacContext, NULL);
648 
649  //Copy the resulting digest
650  for(j = 0; i < outputLen && j < MD5_DIGEST_SIZE; i++, j++)
651  {
652  output[i] = hmacContext->digest[j];
653  }
654 
655  //Compute A(i + 1) = HMAC_MD5(S1, A(i))
656  hmacInit(hmacContext, MD5_HASH_ALGO, s1, sLen);
657  hmacUpdate(hmacContext, a, MD5_DIGEST_SIZE);
658  hmacFinal(hmacContext, a);
659  }
660 
661  //First compute A(1) = HMAC_SHA1(S2, label + seed)
662  hmacInit(hmacContext, SHA1_HASH_ALGO, s2, sLen);
663  hmacUpdate(hmacContext, label, labelLen);
664  hmacUpdate(hmacContext, seed, seedLen);
665  hmacFinal(hmacContext, a);
666 
667  //Apply the data expansion function P_SHA1
668  for(i = 0; i < outputLen; )
669  {
670  //Compute HMAC_SHA1(S2, A(i) + label + seed)
671  hmacInit(hmacContext, SHA1_HASH_ALGO, s2, sLen);
672  hmacUpdate(hmacContext, a, SHA1_DIGEST_SIZE);
673  hmacUpdate(hmacContext, label, labelLen);
674  hmacUpdate(hmacContext, seed, seedLen);
675  hmacFinal(hmacContext, NULL);
676 
677  //Copy the resulting digest
678  for(j = 0; i < outputLen && j < SHA1_DIGEST_SIZE; i++, j++)
679  {
680  output[i] ^= hmacContext->digest[j];
681  }
682 
683  //Compute A(i + 1) = HMAC_SHA1(S2, A(i))
684  hmacInit(hmacContext, SHA1_HASH_ALGO, s2, sLen);
685  hmacUpdate(hmacContext, a, SHA1_DIGEST_SIZE);
686  hmacFinal(hmacContext, a);
687  }
688 
689  //Free previously allocated memory
690  tlsFreeMem(hmacContext);
691 
692  //Successful processing
693  error = NO_ERROR;
694  }
695  else
696  {
697  //Failed to allocate memory
698  error = ERROR_OUT_OF_MEMORY;
699  }
700 
701  //Return status code
702  return error;
703 #else
704  //Not implemented
705  return ERROR_NOT_IMPLEMENTED;
706 #endif
707 }
708 
709 
710 /**
711  * @brief Pseudorandom function (TLS 1.2)
712  *
713  * The pseudorandom function (PRF) takes as input a secret, a seed, and
714  * an identifying label and produces an output of arbitrary length. This
715  * function is used to expand secrets into blocks of data for the purpose
716  * of key generation
717  *
718  * @param[in] hash Hash function used to compute PRF
719  * @param[in] secret Pointer to the secret
720  * @param[in] secretLen Length of the secret
721  * @param[in] label Identifying label (NULL-terminated string)
722  * @param[in] seed Pointer to the seed
723  * @param[in] seedLen Length of the seed
724  * @param[out] output Pointer to the output
725  * @param[in] outputLen Desired output length
726  * @return Error code
727  **/
728 
729 error_t tls12Prf(const HashAlgo *hash, const uint8_t *secret, size_t secretLen,
730  const char_t *label, const uint8_t *seed, size_t seedLen, uint8_t *output,
731  size_t outputLen)
732 {
733 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
734  error_t error;
735  size_t n;
736  size_t labelLen;
737  HmacContext *hmacContext;
738  uint8_t a[MAX_HASH_DIGEST_SIZE];
739 
740  //Allocate a memory buffer to hold the HMAC context
741  hmacContext = tlsAllocMem(sizeof(HmacContext));
742 
743  //Successful memory allocation?
744  if(hmacContext != NULL)
745  {
746  //Retrieve the length of the label
747  labelLen = osStrlen(label);
748 
749  //First compute A(1) = HMAC_hash(secret, label + seed)
750  hmacInit(hmacContext, hash, secret, secretLen);
751  hmacUpdate(hmacContext, label, labelLen);
752  hmacUpdate(hmacContext, seed, seedLen);
753  hmacFinal(hmacContext, a);
754 
755  //Apply the data expansion function P_hash
756  while(outputLen > 0)
757  {
758  //Compute HMAC_hash(secret, A(i) + label + seed)
759  hmacInit(hmacContext, hash, secret, secretLen);
760  hmacUpdate(hmacContext, a, hash->digestSize);
761  hmacUpdate(hmacContext, label, labelLen);
762  hmacUpdate(hmacContext, seed, seedLen);
763  hmacFinal(hmacContext, NULL);
764 
765  //Calculate the number of bytes to copy
766  n = MIN(outputLen, hash->digestSize);
767  //Copy the resulting digest
768  osMemcpy(output, hmacContext->digest, n);
769 
770  //Compute A(i + 1) = HMAC_hash(secret, A(i))
771  hmacInit(hmacContext, hash, secret, secretLen);
772  hmacUpdate(hmacContext, a, hash->digestSize);
773  hmacFinal(hmacContext, a);
774 
775  //Advance data pointer
776  output += n;
777  //Decrement byte counter
778  outputLen -= n;
779  }
780 
781  //Free previously allocated memory
782  tlsFreeMem(hmacContext);
783 
784  //Successful processing
785  error = NO_ERROR;
786  }
787  else
788  {
789  //Failed to allocate memory
790  error = ERROR_OUT_OF_MEMORY;
791  }
792 
793  //Return status code
794  return error;
795 #else
796  //Not implemented
797  return ERROR_NOT_IMPLEMENTED;
798 #endif
799 }
800 
801 
802 /**
803  * @brief Dump secret key (for debugging purpose only)
804  * @param[in] context Pointer to the TLS context
805  * @param[in] label Identifying label (NULL-terminated string)
806  * @param[in] secret Pointer to the secret key
807  * @param[in] secretLen Length of the secret key, in bytes
808  **/
809 
810 void tlsDumpSecret(TlsContext *context, const char_t *label,
811  const uint8_t *secret, size_t secretLen)
812 {
813 #if (TLS_KEY_LOG_SUPPORT == ENABLED)
814  //Any registered callback?
815  if(context->keyLogCallback != NULL)
816  {
817  size_t i;
818  size_t n;
819  char_t buffer[194];
820 
821  //Retrieve the length of the label
822  n = osStrlen(label);
823 
824  //Sanity check
825  if((n + 2 * secretLen + 67) <= sizeof(buffer))
826  {
827  //Copy the identifying label
828  osStrncpy(buffer, label, n);
829 
830  //Append a space character
831  buffer[n++] = ' ';
832 
833  //Convert the client random value to a hex string
834  for(i = 0; i < 32; i++)
835  {
836  //Format current byte
837  n += osSprintf(buffer + n, "%02" PRIX8, context->clientRandom[i]);
838  }
839 
840  //Append a space character
841  buffer[n++] = ' ';
842 
843  //Convert the secret key to a hex string
844  for(i = 0; i < secretLen; i++)
845  {
846  //Format current byte
847  n += osSprintf(buffer + n, "%02" PRIX8, secret[i]);
848  }
849 
850  //Properly terminate the string with a NULL character
851  buffer[n] = '\0';
852 
853  //Invoke user callback function
854  context->keyLogCallback(context, buffer);
855  }
856  }
857 #endif
858 }
859 
860 #endif
unsigned int uint_t
Definition: compiler_port.h:50
char char_t
Definition: compiler_port.h:48
int bool_t
Definition: compiler_port.h:53
#define STORE16BE(a, p)
Definition: cpu_endian.h:262
Debugging facilities.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_UNSUPPORTED_KEY_EXCH_ALGO
Definition: error.h:131
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
@ ERROR_INVALID_VERSION
Definition: error.h:118
#define MAX_HASH_DIGEST_SIZE
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
__weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
Update the HMAC context with a portion of the message being hashed.
Definition: hmac.c:201
#define MD5_DIGEST_SIZE
Definition: md5.h:45
#define MD5_HASH_ALGO
Definition: md5.h:49
uint8_t a
Definition: ndp.h:411
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemmove(dest, src, length)
Definition: os_port.h:147
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
#define osStrlen(s)
Definition: os_port.h:165
#define osSprintf(dest,...)
Definition: os_port.h:231
#define osStrncpy(s1, s2, length)
Definition: os_port.h:213
#define SHA1_HASH_ALGO
Definition: sha1.h:49
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
Common interface for hash algorithms.
Definition: crypto.h:1014
HashAlgoCompute compute
Definition: crypto.h:1023
HashAlgoFinal final
Definition: crypto.h:1026
size_t contextSize
Definition: crypto.h:1018
size_t digestSize
Definition: crypto.h:1020
HMAC algorithm context.
Definition: hmac.h:59
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:63
Structure describing a cipher suite.
Definition: tls.h:1999
error_t tls13DeriveSecret(TlsContext *context, const uint8_t *secret, size_t secretLen, const char_t *label, const char_t *message, size_t messageLen, uint8_t *output, size_t outputLen)
Derive-Secret function.
error_t tls13HkdfExpandLabel(TlsTransportProtocol transportProtocol, const HashAlgo *hash, const uint8_t *secret, size_t secretLen, const char_t *label, const uint8_t *context, size_t contextLen, uint8_t *output, size_t outputLen)
HKDF-Expand-Label function.
TLS 1.3 key schedule.
TLS (Transport Layer Security)
#define tlsAllocMem(size)
Definition: tls.h:846
@ TLS_KEY_EXCH_DHE_PSK
Definition: tls.h:1138
@ TLS_KEY_EXCH_RSA_PSK
Definition: tls.h:1137
@ TLS_KEY_EXCH_ECDHE_PSK
Definition: tls.h:1139
@ TLS_KEY_EXCH_PSK
Definition: tls.h:1136
uint8_t secret[TLS_MASTER_SECRET_SIZE]
Master secret.
Definition: tls.h:1867
#define tlsFreeMem(p)
Definition: tls.h:851
uint8_t random[32]
Definition: tls.h:1754
#define TLS_MAX_HKDF_DIGEST_SIZE
Definition: tls.h:906
#define TLS_VERSION_1_1
Definition: tls.h:95
#define TLS_RANDOM_SIZE
Definition: tls.h:923
#define TLS_VERSION_1_3
Definition: tls.h:97
#define TLS_PREMASTER_SECRET_SIZE
Definition: tls.h:801
#define TlsContext
Definition: tls.h:36
uint16_t cipherSuite
Cipher suite identifier.
Definition: tls.h:1866
#define TLS_VERSION_1_0
Definition: tls.h:94
#define TLS_MASTER_SECRET_SIZE
Definition: tls.h:794
#define TLS_VERSION_1_2
Definition: tls.h:96
error_t tlsGenerateExtendedMasterSecret(TlsContext *context)
Extended master secret computation.
error_t tls12Prf(const HashAlgo *hash, 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)
void tlsDumpSecret(TlsContext *context, const char_t *label, const uint8_t *secret, size_t secretLen)
Dump secret key (for debugging purpose only)
error_t tlsGenerateSessionKeys(TlsContext *context)
Generate session keys.
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)
__weak_func error_t tlsGenerateKeyBlock(TlsContext *context, size_t keyBlockLen)
Key expansion function.
error_t tlsGeneratePskPremasterSecret(TlsContext *context)
Premaster secret generation (for PSK cipher suites)
error_t tlsExportKeyingMaterial(TlsContext *context, const char_t *label, bool_t useContextValue, const uint8_t *contextValue, size_t contextValueLen, uint8_t *output, size_t outputLen)
Export keying material per RFC 5705 standard.
__weak_func error_t tlsGenerateMasterSecret(TlsContext *context)
Master secret computation.
Key material generation.
error_t tlsFinalizeTranscriptHash(TlsContext *context, const HashAlgo *hash, const void *hashContext, const char_t *label, uint8_t *output)
Finalize hash calculation from previous handshake messages.
Transcript hash calculation.
Generic hash algorithm context.
uint8_t digest[MAX_HASH_DIGEST_SIZE]