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