tls_ticket.c
Go to the documentation of this file.
1 /**
2  * @file tls_ticket.c
3  * @brief TLS session tickets
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.4
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_ticket.h"
37 #include "debug.h"
38 
39 //Check TLS library configuration
40 #if (TLS_SUPPORT == ENABLED && TLS_TICKET_SUPPORT == ENABLED)
41 
42 
43 /**
44  * @brief Initialize ticket encryption context
45  * @param[in] ticketContext Pointer to ticket encryption context
46  * @return Error code
47  **/
48 
50 {
51  //Make sure the ticket encryption context is valid
52  if(ticketContext == NULL)
54 
55  //Erase ticket encryption context
56  osMemset(ticketContext, 0, sizeof(TlsTicketContext));
57 
58  //Create a mutex to prevent simultaneous access to the context
59  if(!osCreateMutex(&ticketContext->mutex))
60  {
61  //Report an error
63  }
64 
65  //Successful initialization
66  return NO_ERROR;
67 }
68 
69 
70 /**
71  * @brief Session ticket encryption
72  * @param[in] context Pointer to the TLS context
73  * @param[in] plaintext Plaintext session state
74  * @param[in] plaintextLen Length of the plaintext session state, in bytes
75  * @param[out] ciphertext Encrypted ticket
76  * @param[out] ciphertextLen Length of the encrypted ticket, in bytes
77  * @param[in] param Pointer to the ticket encryption context
78  * @return Error code
79  **/
80 
81 error_t tlsEncryptTicket(TlsContext *context, const uint8_t *plaintext,
82  size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen, void *param)
83 {
84  error_t error;
85  uint8_t *iv;
86  uint8_t *data;
87  uint8_t *tag;
89  TlsTicketContext *ticketContext;
91 
92  //Check parameters
93  if(context == NULL || param == NULL)
95  if(plaintext == NULL || ciphertext == NULL || ciphertextLen == NULL)
97 
98  //Initialize status code
99  error = NO_ERROR;
100 
101  //Initialize variables
102  iv = NULL;
103  data = NULL;
104  tag = NULL;
105 
106  //Point to the ticket encryption context
107  ticketContext = (TlsTicketContext *) param;
108 
109  //Acquire exclusive access to the ticket encryption context
110  osAcquireMutex(&ticketContext->mutex);
111 
112  //The keys should be changed regularly (refer to RFC 5077, section 5.5)
115 
116  //Point to the current ticket encryption state
117  state = &ticketContext->encryptionState;
118 
119  //Check whether the ticket encryption state is valid
120  if(state->valid)
121  {
122  //Get current time
123  time = osGetSystemTime();
124 
125  //Check the validity of the encryption keys
126  if((time - state->timestamp) >= TLS_TICKET_LIFETIME)
127  {
128  //Rotate keys
129  ticketContext->prevEncryptionState = ticketContext->encryptionState;
130  ticketContext->encryptionState.valid = FALSE;
131  }
132  }
133 
134  //Invalid set of keys?
135  if(!state->valid)
136  {
137  //Generate a new set of keys
138  error = tlsGenerateTicketKeys(ticketContext, context->prngAlgo,
139  context->prngContext);
140  }
141 
142  //Check status code
143  if(!error)
144  {
145  //Point to the IV
146  iv = ciphertext + TLS_TICKET_KEY_NAME_SIZE;
147  //Point to the data
149  //Point to the buffer where to store the authentication tag
150  tag = data + plaintextLen;
151 
152  //Copy plaintext state
153  osMemmove(data, plaintext, plaintextLen);
154  //Copy key name
155  osMemcpy(ciphertext, state->keyName, TLS_TICKET_KEY_NAME_SIZE);
156 
157  //Generate a random IV
158  error = context->prngAlgo->read(context->prngContext, iv,
160  }
161 
162  //Check status code
163  if(!error)
164  {
165  //Initialize AES context
166  error = aesInit(&ticketContext->aesContext, state->key,
168  }
169 
170  //Check status code
171  if(!error)
172  {
173  //Initialize GCM context
174  error = gcmInit(&ticketContext->gcmContext, AES_CIPHER_ALGO,
175  &ticketContext->aesContext);
176  }
177  else
178  {
179  //Failed to initialize AES context
180  state = NULL;
181  }
182 
183  //Check status code
184  if(!error)
185  {
186  //Calculate the length of the encrypted ticket
187  *ciphertextLen = plaintextLen + TLS_TICKET_KEY_NAME_SIZE +
189 
190  //The actual state information in encrypted using AES-GCM
191  error = gcmEncrypt(&ticketContext->gcmContext, iv, TLS_TICKET_IV_SIZE,
192  state->keyName, TLS_TICKET_KEY_NAME_SIZE, data, data, plaintextLen,
193  tag, TLS_TICKET_TAG_SIZE);
194  }
195 
196  //Erase AES context
197  if(state != NULL)
198  {
199  aesDeinit(&ticketContext->aesContext);
200  }
201 
202  //Release exclusive access to the ticket encryption context
203  osReleaseMutex(&ticketContext->mutex);
204 
205  //Return status code
206  return error;
207 }
208 
209 
210 /**
211  * @brief Session ticket decryption
212  * @param[in] context Pointer to the TLS context
213  * @param[in] ciphertext Encrypted ticket
214  * @param[in] ciphertextLen Length of the encrypted ticket, in bytes
215  * @param[out] plaintext Plaintext session state
216  * @param[out] plaintextLen Length of the plaintext session state, in bytes
217  * @param[in] param Pointer to the ticket encryption context
218  * @return Error code
219  **/
220 
221 error_t tlsDecryptTicket(TlsContext *context, const uint8_t *ciphertext,
222  size_t ciphertextLen, uint8_t *plaintext, size_t *plaintextLen, void *param)
223 {
224  error_t error;
225  const uint8_t *iv;
226  const uint8_t *data;
227  const uint8_t *tag;
228  TlsTicketContext *ticketContext;
230 
231  //Check parameters
232  if(context == NULL || param == NULL)
234  if(ciphertext == NULL || plaintext == NULL || plaintextLen == NULL)
236 
237  //Check the length of the encrypted ticket
238  if(ciphertextLen < (TLS_TICKET_KEY_NAME_SIZE + TLS_TICKET_IV_SIZE +
240  {
241  //Report an error
243  }
244 
245  //Initialize status code
246  error = NO_ERROR;
247 
248  //Initialize variables
249  iv = NULL;
250  data = NULL;
251  tag = NULL;
252  state = NULL;
253 
254  //Point to the ticket encryption context
255  ticketContext = (TlsTicketContext *) param;
256 
257  //Acquire exclusive access to the ticket encryption context
258  osAcquireMutex(&ticketContext->mutex);
259 
260  //The keys should be changed regularly (refer to RFC 5077, section 5.5)
263 
264  //Compare key names
265  if(tlsCompareTicketKeyName(ciphertext, ciphertextLen,
266  &ticketContext->encryptionState))
267  {
268  //Point to the current set of keys
269  state = &ticketContext->encryptionState;
270  }
271  else if(tlsCompareTicketKeyName(ciphertext, ciphertextLen,
272  &ticketContext->prevEncryptionState))
273  {
274  //Point to the previous set of keys
275  state = &ticketContext->prevEncryptionState;
276  }
277  else
278  {
279  //Unknown key name
280  error = ERROR_DECRYPTION_FAILED;
281  }
282 
283  //Check status code
284  if(!error)
285  {
286  //Point to the IV
287  iv = ciphertext + TLS_TICKET_KEY_NAME_SIZE;
288  //Point to the data
290  //Point to the authentication tag
291  tag = ciphertext + ciphertextLen - TLS_TICKET_TAG_SIZE;
292 
293  //Retrieve the length of the data
294  *plaintextLen = ciphertextLen - TLS_TICKET_KEY_NAME_SIZE -
296 
297  //Initialize AES context
298  error = aesInit(&ticketContext->aesContext, state->key,
300  }
301 
302  //Check status code
303  if(!error)
304  {
305  //Initialize GCM context
306  error = gcmInit(&ticketContext->gcmContext, AES_CIPHER_ALGO,
307  &ticketContext->aesContext);
308  }
309  else
310  {
311  //Failed to initialize AES context
312  state = NULL;
313  }
314 
315  //Check status code
316  if(!error)
317  {
318  //The actual state information in encrypted using AES-GCM
319  error = gcmDecrypt(&ticketContext->gcmContext, iv, TLS_TICKET_IV_SIZE,
320  state->keyName, TLS_TICKET_KEY_NAME_SIZE, data, plaintext,
321  *plaintextLen, tag, TLS_TICKET_TAG_SIZE);
322  }
323 
324  //Erase AES context
325  if(state != NULL)
326  {
327  aesDeinit(&ticketContext->aesContext);
328  }
329 
330  //Release exclusive access to the ticket encryption context
331  osReleaseMutex(&ticketContext->mutex);
332 
333  //Return status code
334  return error;
335 }
336 
337 
338 /**
339  * @brief Generate a new set of keys
340  * @param[in] ticketContext Pointer to ticket encryption context
341  * @param[in] prngAlgo PRNG algorithm
342  * @param[in] prngContext Pointer to the PRNG context
343  * @return Error code
344  **/
345 
347  const PrngAlgo *prngAlgo, void *prngContext)
348 {
349  error_t error;
351 
352  //Point to the current ticket encryption state
353  state = &ticketContext->encryptionState;
354 
355  //The set of keys is not valid anymore
356  state->valid = FALSE;
357 
358  //The key name should be randomly generated to avoid collisions between
359  //servers (refer to RFC 5077, section 4)
360  error = prngAlgo->read(prngContext, state->keyName,
362  //Any error to report?
363  if(error)
364  return error;
365 
366  //Generate a random encryption key
367  error = prngAlgo->read(prngContext, state->key, TLS_TICKET_KEY_SIZE);
368  //Any error to report?
369  if(error)
370  return error;
371 
372  //Save current time
373  state->timestamp = osGetSystemTime();
374  //The set of keys is valid
375  state->valid = TRUE;
376 
377  //Successful processing
378  return NO_ERROR;
379 }
380 
381 
382 /**
383  * @brief Check the validity of a given set of keys
384  * @param[in] state Pointer to ticket encryption state
385  **/
386 
388 {
389  systime_t time;
390 
391  //Get current time
392  time = osGetSystemTime();
393 
394  //Valid set of keys?
395  if(state->valid)
396  {
397  //Check lifetime
398  if((time - state->timestamp) >= (2 * TLS_TICKET_LIFETIME))
399  {
400  //Clear ticket keys
401  osMemset(state, 0, sizeof(TlsTicketEncryptionState));
402  }
403  }
404 }
405 
406 
407 /**
408  * @brief Key name comparison
409  * @param[in] ticket Encrypted ticket
410  * @param[in] ticketLen Length of the encrypted ticket, in bytes
411  * @param[in] state Pointer to ticket encryption state
412  **/
413 
415  const TlsTicketEncryptionState *state)
416 {
417  bool_t res;
418 
419  //Initialize flag
420  res = FALSE;
421 
422  //Valid set of keys?
423  if(state->valid)
424  {
425  //The key name serves to identify a particular set of keys used to
426  //protect the ticket (refer to RFC 5077, section 4)
428  {
429  //Compare key names
431  {
432  //The key name is valid
433  res = TRUE;
434  }
435  }
436  }
437 
438  //Return comparison result
439  return res;
440 }
441 
442 
443 /**
444  * @brief Properly dispose ticket encryption context
445  * @param[in] ticketContext Pointer to ticket encryption context to be released
446  **/
447 
449 {
450  //Make sure the ticket encryption context is valid
451  if(ticketContext != NULL)
452  {
453  //Release previously allocated resources
454  osDeleteMutex(&ticketContext->mutex);
455 
456  //Erase ticket encryption context
457  osMemset(ticketContext, 0, sizeof(TlsTicketContext));
458  }
459 }
460 
461 #endif
error_t tlsInitTicketContext(TlsTicketContext *ticketContext)
Initialize ticket encryption context.
Definition: tls_ticket.c:49
int bool_t
Definition: compiler_port.h:53
TlsTicketEncryptionState encryptionState
Current set of keys.
Definition: tls_ticket.h:93
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
error_t tlsDecryptTicket(TlsContext *context, const uint8_t *ciphertext, size_t ciphertextLen, uint8_t *plaintext, size_t *plaintextLen, void *param)
Session ticket decryption.
Definition: tls_ticket.c:221
#define PrngAlgo
Definition: crypto.h:938
@ ERROR_DECRYPTION_FAILED
Definition: error.h:242
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
AesContext aesContext
AES context.
Definition: tls_ticket.h:95
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
bool_t valid
Valid set of keys.
Definition: tls_ticket.h:79
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
__weak_func error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
Definition: gcm.c:99
TlsTicketEncryptionState prevEncryptionState
Previous set of keys.
Definition: tls_ticket.h:94
const uint8_t res[]
#define TLS_TICKET_IV_SIZE
Definition: tls_ticket.h:55
Session ticket encryption context.
Definition: tls_ticket.h:91
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
Session ticket encryption state.
Definition: tls_ticket.h:78
#define TlsContext
Definition: tls.h:36
error_t
Error codes.
Definition: error.h:43
__weak_func error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
Definition: aes.c:242
uint8_t iv[]
Definition: ike.h:1502
bool_t tlsCompareTicketKeyName(const uint8_t *ticket, size_t ticketLen, const TlsTicketEncryptionState *state)
Key name comparison.
Definition: tls_ticket.c:414
TLS session tickets.
__weak_func void aesDeinit(AesContext *context)
Release AES context.
Definition: aes.c:571
uint32_t systime_t
System time.
uint8_t key[TLS_TICKET_KEY_SIZE]
Encryption key.
Definition: tls_ticket.h:82
uint8_t ticket[]
Definition: tls.h:1844
uint32_t time
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
#define TLS_TICKET_LIFETIME
Definition: tls.h:164
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
GcmContext gcmContext
GCM context.
Definition: tls_ticket.h:96
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
systime_t timestamp
Generation time.
Definition: tls_ticket.h:80
error_t tlsEncryptTicket(TlsContext *context, const uint8_t *plaintext, size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen, void *param)
Session ticket encryption.
Definition: tls_ticket.c:81
void tlsCheckTicketKeyLifetime(TlsTicketEncryptionState *state)
Check the validity of a given set of keys.
Definition: tls_ticket.c:387
uint8_t keyName[TLS_TICKET_KEY_NAME_SIZE]
Key identifier.
Definition: tls_ticket.h:81
TLS (Transport Layer Security)
#define AES_CIPHER_ALGO
Definition: aes.h:45
#define TLS_TICKET_KEY_SIZE
Definition: tls_ticket.h:48
error_t tlsGenerateTicketKeys(TlsTicketContext *ticketContext, const PrngAlgo *prngAlgo, void *prngContext)
Generate a new set of keys.
Definition: tls_ticket.c:346
void tlsFreeTicketContext(TlsTicketContext *ticketContext)
Properly dispose ticket encryption context.
Definition: tls_ticket.c:448
#define TLS_TICKET_KEY_NAME_SIZE
Definition: tls_ticket.h:41
uint16_t ticketLen
Definition: tls.h:1843
#define osMemset(p, value, length)
Definition: os_port.h:135
OsMutex mutex
Mutex preventing simultaneous access to the context.
Definition: tls_ticket.h:92
__weak_func error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using GCM.
Definition: gcm.c:361
#define TLS_TICKET_TAG_SIZE
Definition: tls_ticket.h:62
__weak_func error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
Authenticated encryption using GCM.
Definition: gcm.c:214
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:147
systime_t osGetSystemTime(void)
Retrieve system time.