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