tls_transcript_hash.c
Go to the documentation of this file.
1 /**
2  * @file tls_transcript_hash.c
3  * @brief Transcript hash calculation
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.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_client.h"
37 #include "tls_key_material.h"
38 #include "tls_transcript_hash.h"
39 #include "tls13_key_material.h"
40 #include "debug.h"
41 
42 //Check TLS library configuration
43 #if (TLS_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Initialize handshake message hashing
48  * @param[in] context Pointer to the TLS context
49  * @return Error code
50  **/
51 
53 {
54 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
55  //MD5 context already instantiated?
56  if(context->transcriptMd5Context != NULL)
57  {
58  tlsFreeMem(context->transcriptMd5Context);
59  context->transcriptMd5Context = NULL;
60  }
61 #endif
62 
63 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
64  //SHA-1 context already instantiated?
65  if(context->transcriptSha1Context != NULL)
66  {
67  tlsFreeMem(context->transcriptSha1Context);
68  context->transcriptSha1Context = NULL;
69  }
70 #endif
71 
72 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
73  //Hash algorithm context already instantiated?
74  if(context->transcriptHashContext != NULL)
75  {
76  tlsFreeMem(context->transcriptHashContext);
77  context->transcriptHashContext = NULL;
78  }
79 #endif
80 
81 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
82  //TLS 1.0 or TLS 1.1 currently selected?
83  if(context->version <= TLS_VERSION_1_1)
84  {
85  //Allocate MD5 context
86  context->transcriptMd5Context = tlsAllocMem(sizeof(Md5Context));
87  //Failed to allocate memory?
88  if(context->transcriptMd5Context == NULL)
89  return ERROR_OUT_OF_MEMORY;
90 
91  //Initialize MD5 context
92  md5Init(context->transcriptMd5Context);
93  }
94 #endif
95 
96 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
97  //TLS 1.0, TLS 1.1 or TLS 1.2 currently selected?
98  if(context->version <= TLS_VERSION_1_2)
99  {
100  //Allocate SHA-1 context
101  context->transcriptSha1Context = tlsAllocMem(sizeof(Sha1Context));
102  //Failed to allocate memory?
103  if(context->transcriptSha1Context == NULL)
104  return ERROR_OUT_OF_MEMORY;
105 
106  //Initialize SHA-1 context
107  sha1Init(context->transcriptSha1Context);
108  }
109 #endif
110 
111 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
112  //TLS 1.2 or 1.3 currently selected?
113  if(context->version >= TLS_VERSION_1_2)
114  {
115  const HashAlgo *hashAlgo;
116 
117  //Point to the hash algorithm to be used
118  hashAlgo = context->cipherSuite.prfHashAlgo;
119  //Make sure the hash algorithm is valid
120  if(hashAlgo == NULL)
121  return ERROR_FAILURE;
122 
123  //Allocate hash algorithm context
124  context->transcriptHashContext = tlsAllocMem(hashAlgo->contextSize);
125  //Failed to allocate memory?
126  if(context->transcriptHashContext == NULL)
127  return ERROR_OUT_OF_MEMORY;
128 
129  //Initialize the hash algorithm context
130  hashAlgo->init(context->transcriptHashContext);
131  }
132 #endif
133 
134 #if (TLS_CLIENT_SUPPORT == ENABLED)
135  //Client mode?
136  if(context->entity == TLS_CONNECTION_END_CLIENT)
137  {
138 #if (DTLS_SUPPORT == ENABLED)
139  //DTLS protocol?
140  if(context->transportProtocol == TLS_TRANSPORT_PROTOCOL_DATAGRAM)
141  {
142  size_t length;
143  DtlsRecord *record;
144 
145  //Point to the DTLS record that holds the ClientHello message
146  record = (DtlsRecord *) context->txBuffer;
147 
148  //Sanity check
149  if(context->txBufferLen > sizeof(DtlsRecord))
150  {
151  //Retrieve the length of the handshake message
152  length = context->txBufferLen - sizeof(DtlsRecord);
153 
154  //Update the hash value with the ClientHello message
155  tlsUpdateTranscriptHash(context, record->data, length);
156  }
157  }
158  else
159 #endif
160  //TLS protocol?
161  {
162  size_t length;
163  TlsRecord *record;
164 
165  //Point to the TLS record that holds the ClientHello message
166  record = (TlsRecord *) context->txBuffer;
167 
168  //Retrieve the length of the handshake message
169  length = ntohs(record->length);
170 
171  //Sanity check
172  if((length + sizeof(TlsRecord)) <= context->txBufferSize)
173  {
174  //Update the hash value with the ClientHello message
175  tlsUpdateTranscriptHash(context, record->data, length);
176  }
177  }
178  }
179 #endif
180 
181  //Successful initialization
182  return NO_ERROR;
183 }
184 
185 
186 /**
187  * @brief Update hash value with a handshake message
188  * @param[in] context Pointer to the TLS context
189  * @param[in] data Pointer to the handshake message being hashed
190  * @param[in] length Length of the message
191  **/
192 
193 void tlsUpdateTranscriptHash(TlsContext *context, const void *data,
194  size_t length)
195 {
196 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
197  //TLS 1.0 or TLS 1.1 currently selected?
198  if(context->version <= TLS_VERSION_1_1)
199  {
200  //Valid MD5 context?
201  if(context->transcriptMd5Context != NULL)
202  {
203  //Update MD5 hash value with message contents
204  md5Update(context->transcriptMd5Context, data, length);
205  }
206  }
207 #endif
208 
209 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
210  //TLS 1.0, TLS 1.1 or TLS 1.2 currently selected?
211  if(context->version <= TLS_VERSION_1_2)
212  {
213  //Valid SHA-1 context?
214  if(context->transcriptSha1Context != NULL)
215  {
216  //Update SHA-1 hash value with message contents
217  sha1Update(context->transcriptSha1Context, data, length);
218  }
219  }
220 #endif
221 
222 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
223  //TLS 1.2 or TLS 1.3 currently selected?
224  if(context->version >= TLS_VERSION_1_2)
225  {
226  const HashAlgo *hashAlgo;
227 
228  //Point to the PRF hash algorithm to be used
229  hashAlgo = context->cipherSuite.prfHashAlgo;
230 
231  //Valid hash algorithm?
232  if(hashAlgo != NULL && context->transcriptHashContext != NULL)
233  {
234  //DTLS 1.3 protocol?
235  if(context->transportProtocol == TLS_TRANSPORT_PROTOCOL_DATAGRAM &&
236  context->version == TLS_VERSION_1_3 &&
237  length >= sizeof(DtlsHandshake))
238  {
239  const DtlsHandshake *message;
240 
241  //Point to the handshake message
242  message = (DtlsHandshake *) data;
243 
244  //In DTLS 1.3, the message transcript is computed over the original
245  //TLS 1.3-style handshake messages without the message_seq,
246  //fragment_offset, and fragment_length values. Note that this is a
247  //change from DTLS 1.2 where those values were included in the
248  //transcript (refer to RFC 9147, section 5.2)
249  hashAlgo->update(context->transcriptHashContext, message, 4);
250 
251  //Update hash value with message contents
252  hashAlgo->update(context->transcriptHashContext, message->data,
253  length - sizeof(DtlsHandshake));
254  }
255  else
256  {
257  //Update hash value with message contents
258  hashAlgo->update(context->transcriptHashContext, data, length);
259  }
260  }
261  }
262 #endif
263 }
264 
265 
266 /**
267  * @brief Finalize hash calculation from previous handshake messages
268  * @param[in] context Pointer to the TLS context
269  * @param[in] hash Hash function used to digest the handshake messages
270  * @param[in] hashContext Pointer to the hash context
271  * @param[in] label NULL-terminated string
272  * @param[out] output Buffer where to store the resulting hash value
273  * @return Error code
274  **/
275 
277  const void *hashContext, const char_t *label, uint8_t *output)
278 {
279  error_t error;
280  HashContext *tempHashContext;
281 
282  //Make sure the hash context is valid
283  if(hash == NULL || hashContext == NULL)
285 
286  //Allocate a temporary hash context
287  tempHashContext = tlsAllocMem(hash->contextSize);
288 
289  //Successful memory allocation?
290  if(tempHashContext != NULL)
291  {
292  //The original hash context must be preserved
293  osMemcpy(tempHashContext, hashContext, hash->contextSize);
294 
295  //Compute hash(handshakeMessages)
296  hash->final(tempHashContext, output);
297 
298  //Release previously allocated resources
299  tlsFreeMem(tempHashContext);
300 
301  //Successful processing
302  error = NO_ERROR;
303  }
304  else
305  {
306  //Failed to allocate memory
307  error = ERROR_OUT_OF_MEMORY;
308  }
309 
310  //Return status code
311  return error;
312 }
313 
314 
315 /**
316  * @brief Release transcript hash context
317  * @param[in] context Pointer to the TLS context
318  **/
319 
321 {
322 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
323  //Release MD5 hash context
324  if(context->transcriptMd5Context != NULL)
325  {
326  osMemset(context->transcriptMd5Context, 0, sizeof(Md5Context));
327  tlsFreeMem(context->transcriptMd5Context);
328  context->transcriptMd5Context = NULL;
329  }
330 #endif
331 
332 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
333  //Release SHA-1 hash context
334  if(context->transcriptSha1Context != NULL)
335  {
336  osMemset(context->transcriptSha1Context, 0, sizeof(Sha1Context));
337  tlsFreeMem(context->transcriptSha1Context);
338  context->transcriptSha1Context = NULL;
339  }
340 #endif
341 
342 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
343  //Release transcript hash context
344  if(context->transcriptHashContext != NULL)
345  {
346  tlsFreeMem(context->transcriptHashContext);
347  context->transcriptHashContext = NULL;
348  }
349 #endif
350 }
351 
352 
353 /**
354  * @brief Compute verify data from previous handshake messages
355  * @param[in] context Pointer to the TLS context
356  * @param[in] entity Specifies whether the computation is performed at client
357  * or server side
358  * @param[out] verifyData Pointer to the buffer where to store the verify data
359  * @param[out] verifyDataLen Length of the verify data
360  * @return Error code
361  **/
362 
364  TlsConnectionEnd entity, uint8_t *verifyData, size_t *verifyDataLen)
365 {
366  error_t error;
367 
368 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
369  //TLS 1.0 or 1.1 currently selected?
370  if(context->version == TLS_VERSION_1_0 || context->version == TLS_VERSION_1_1)
371  {
372  const char_t *label;
373  uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE];
374 
375  //Finalize MD5 hash computation
376  error = tlsFinalizeTranscriptHash(context, MD5_HASH_ALGO,
377  context->transcriptMd5Context, "", digest);
378 
379  //Check status code
380  if(!error)
381  {
382  //Finalize SHA-1 hash computation
383  error = tlsFinalizeTranscriptHash(context, SHA1_HASH_ALGO,
384  context->transcriptSha1Context, "", digest + MD5_DIGEST_SIZE);
385  }
386 
387  //Check status code
388  if(!error)
389  {
390  //Check whether the computation is performed at client or server side
391  if(entity == TLS_CONNECTION_END_CLIENT)
392  {
393  label = "client finished";
394  }
395  else
396  {
397  label = "server finished";
398  }
399 
400  //The verify data is always 12-byte long for TLS 1.0 and 1.1
401  error = tlsPrf(context->masterSecret, TLS_MASTER_SECRET_SIZE,
402  label, digest, sizeof(digest), verifyData, 12);
403  }
404  }
405  else
406 #endif
407 #if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
408  //TLS 1.2 currently selected?
409  if(context->version == TLS_VERSION_1_2)
410  {
411  const char_t *label;
412  const HashAlgo *hashAlgo;
413  HashContext *hashContext;
414  uint8_t digest[MAX_HASH_DIGEST_SIZE];
415 
416  //Point to the hash algorithm to be used
417  hashAlgo = context->cipherSuite.prfHashAlgo;
418 
419  //Valid hash algorithm?
420  if(hashAlgo != NULL && context->transcriptHashContext != NULL)
421  {
422  //Allocate hash algorithm context
423  hashContext = tlsAllocMem(hashAlgo->contextSize);
424 
425  //Successful memory allocation?
426  if(hashContext != NULL)
427  {
428  //The original hash context must be preserved
429  osMemcpy(hashContext, context->transcriptHashContext,
430  hashAlgo->contextSize);
431 
432  //Finalize hash computation
433  hashAlgo->final(hashContext, digest);
434 
435  //Check whether the computation is performed at client or server side
436  if(entity == TLS_CONNECTION_END_CLIENT)
437  {
438  label = "client finished";
439  }
440  else
441  {
442  label = "server finished";
443  }
444 
445  //Compute the verify data
446  error = tls12Prf(hashAlgo, context->masterSecret,
447  TLS_MASTER_SECRET_SIZE, label, digest, hashAlgo->digestSize,
448  verifyData, context->cipherSuite.verifyDataLen);
449 
450  //Release previously allocated memory
451  tlsFreeMem(hashContext);
452  }
453  else
454  {
455  //Failed to allocate memory
456  error = ERROR_OUT_OF_MEMORY;
457  }
458  }
459  else
460  {
461  //Invalid hash algorithm
462  error = ERROR_FAILURE;
463  }
464  }
465  else
466 #endif
467 #if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
468  //TLS 1.3 currently selected?
469  if(context->version == TLS_VERSION_1_3)
470  {
471  uint8_t *baseKey;
472  const HashAlgo *hashAlgo;
473  uint8_t digest[TLS_MAX_HKDF_DIGEST_SIZE];
474  uint8_t finishedKey[TLS_MAX_HKDF_DIGEST_SIZE];
475 
476  //The hash function used by HKDF is the cipher suite hash algorithm
477  hashAlgo = context->cipherSuite.prfHashAlgo;
478 
479  //Valid hash algorithm?
480  if(hashAlgo != NULL && context->transcriptHashContext != NULL)
481  {
482  //Check whether the computation is performed at client or server side
483  if(entity == TLS_CONNECTION_END_CLIENT)
484  {
485  baseKey = context->clientHsTrafficSecret;
486  }
487  else
488  {
489  baseKey = context->serverHsTrafficSecret;
490  }
491 
492  //The key used to compute the Finished message is computed from the
493  //base key using HKDF
494  error = tls13HkdfExpandLabel(context->transportProtocol, hashAlgo,
495  baseKey, hashAlgo->digestSize, "finished", NULL, 0, finishedKey,
496  hashAlgo->digestSize);
497 
498  //Check status code
499  if(!error)
500  {
501  //Compute the transcript hash
502  error = tlsFinalizeTranscriptHash(context, hashAlgo,
503  context->transcriptHashContext, "", digest);
504  }
505 
506  //Check status code
507  if(!error)
508  {
509  //Compute the verify data
510  error = hmacCompute(hashAlgo, finishedKey, hashAlgo->digestSize,
511  digest, hashAlgo->digestSize, verifyData);
512  }
513  }
514  else
515  {
516  //Invalid hash algorithm
517  error = ERROR_FAILURE;
518  }
519  }
520  else
521 #endif
522  //Invalid TLS version?
523  {
524  //Report an error
525  error = ERROR_INVALID_VERSION;
526  }
527 
528  //Check status code
529  if(!error)
530  {
531  //Save the length of the verify data
532  *verifyDataLen = context->cipherSuite.verifyDataLen;
533 
534  //Debug message
535  TRACE_DEBUG("Verify data:\r\n");
536  TRACE_DEBUG_ARRAY(" ", verifyData, *verifyDataLen);
537  }
538 
539  //Return status code
540  return error;
541 }
542 
543 #endif
#define tlsAllocMem(size)
Definition: tls.h:888
HashAlgoInit init
Definition: crypto.h:1161
Generic hash algorithm context.
#define SHA1_HASH_ALGO
Definition: sha1.h:49
Key material generation.
void sha1Update(Sha1Context *context, const void *data, size_t length)
Update the SHA-1 context with a portion of the message being hashed.
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.
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)
DtlsRecord
Definition: dtls_misc.h:180
uint8_t message[]
Definition: chap.h:154
TlsConnectionEnd
TLS connection end.
Definition: tls.h:1011
uint8_t data[]
Definition: ethernet.h:224
size_t digestSize
Definition: crypto.h:1157
@ TLS_TRANSPORT_PROTOCOL_DATAGRAM
Definition: tls.h:1000
HashAlgoUpdate update
Definition: crypto.h:1162
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_INVALID_VERSION
Definition: error.h:118
size_t contextSize
Definition: crypto.h:1155
__weak_func error_t tlsComputeVerifyData(TlsContext *context, TlsConnectionEnd entity, uint8_t *verifyData, size_t *verifyDataLen)
Compute verify data from previous handshake messages.
void md5Init(Md5Context *context)
Initialize MD5 message digest context.
#define MAX_HASH_DIGEST_SIZE
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
#define TlsContext
Definition: tls.h:36
error_t
Error codes.
Definition: error.h:43
#define TLS_VERSION_1_2
Definition: tls.h:96
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define MD5_HASH_ALGO
Definition: md5.h:49
#define TLS_VERSION_1_3
Definition: tls.h:97
MD5 algorithm context.
Definition: md5.h:62
uint8_t length
Definition: tcp.h:375
#define MD5_DIGEST_SIZE
Definition: md5.h:45
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)
#define TLS_MASTER_SECRET_SIZE
Definition: tls.h:836
void tlsUpdateTranscriptHash(TlsContext *context, const void *data, size_t length)
Update hash value with a handshake message.
Transcript hash calculation.
HashAlgoFinal final
Definition: crypto.h:1163
#define ntohs(value)
Definition: cpu_endian.h:421
TlsRecord
Definition: tls.h:1864
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
__weak_func error_t hmacCompute(const HashAlgo *hash, const void *key, size_t keyLen, const void *data, size_t dataLen, uint8_t *digest)
Compute HMAC using the specified hash function.
Definition: hmac.c:91
#define TLS_VERSION_1_1
Definition: tls.h:95
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
DtlsHandshake
Definition: dtls_misc.h:195
#define TLS_VERSION_1_0
Definition: tls.h:94
error_t tlsInitTranscriptHash(TlsContext *context)
Initialize handshake message hashing.
#define TLS_MAX_HKDF_DIGEST_SIZE
Definition: tls.h:964
@ TLS_CONNECTION_END_CLIENT
Definition: tls.h:1012
TLS (Transport Layer Security)
SHA-1 algorithm context.
Definition: sha1.h:62
TLS 1.3 key schedule.
Common interface for hash algorithms.
Definition: crypto.h:1151
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.
#define osMemset(p, value, length)
Definition: os_port.h:138
Handshake message processing (TLS client)
#define tlsFreeMem(p)
Definition: tls.h:893
void md5Update(Md5Context *context, const void *data, size_t length)
Update the MD5 context with a portion of the message being hashed.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void tlsFreeTranscriptHash(TlsContext *context)
Release transcript hash context.