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-2019 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 1.9.6
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  memset(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  //Sucessful 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  memmove(data, plaintext, plaintextLen);
155  //Copy key name
156  memcpy(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 
179  //Check status code
180  if(!error)
181  {
182  //Calculate the length of the encrypted ticket
183  *ciphertextLen = plaintextLen + TLS_TICKET_KEY_NAME_SIZE +
185 
186  //The actual state information in encrypted using AES-GCM
187  error = gcmEncrypt(&ticketContext->gcmContext, iv, TLS_TICKET_IV_SIZE,
188  state->keyName, TLS_TICKET_KEY_NAME_SIZE, data, data, plaintextLen,
189  tag, TLS_TICKET_TAG_SIZE);
190  }
191 
192  //Release exclusive access to the ticket encryption context
193  osReleaseMutex(&ticketContext->mutex);
194 
195  //Return status code
196  return error;
197 }
198 
199 
200 /**
201  * @brief Session ticket decryption
202  * @param[in] context Pointer to the TLS context
203  * @param[in] ciphertext Encrypted ticket
204  * @param[in] ciphertextLen Length of the encrypted ticket, in bytes
205  * @param[out] plaintext Plaintext session state
206  * @param[out] plaintextLen Length of the plaintext session state, in bytes
207  * @param[in] param Pointer to the ticket encryption context
208  * @return Error code
209  **/
210 
211 error_t tlsDecryptTicket(TlsContext *context, const uint8_t *ciphertext,
212  size_t ciphertextLen, uint8_t *plaintext, size_t *plaintextLen, void *param)
213 {
214  error_t error;
215  const uint8_t *iv;
216  const uint8_t *data;
217  const uint8_t *tag;
218  TlsTicketContext *ticketContext;
220 
221  //Check parameters
222  if(context == NULL || param == NULL)
224  if(ciphertext == NULL || plaintext == NULL || plaintextLen == NULL)
226 
227  //Check the length of the encrypted ticket
228  if(ciphertextLen < (TLS_TICKET_KEY_NAME_SIZE + TLS_TICKET_IV_SIZE +
230  {
231  //Report an error
233  }
234 
235  //Initialize status code
236  error = NO_ERROR;
237 
238  //Initialize variables
239  iv = NULL;
240  data = NULL;
241  tag = NULL;
242  state = NULL;
243 
244  //Point to the ticket encryption context
245  ticketContext = (TlsTicketContext *) param;
246 
247  //Acquire exclusive access to the ticket encryption context
248  osAcquireMutex(&ticketContext->mutex);
249 
250  //The keys should be changed regularly (refer to RFC 5077, section 5.5)
253 
254  //Compare key names
255  if(tlsCompareTicketKeyName(ciphertext, ciphertextLen,
256  &ticketContext->encryptionState))
257  {
258  //Point to the current set of keys
259  state = &ticketContext->encryptionState;
260  }
261  else if(tlsCompareTicketKeyName(ciphertext, ciphertextLen,
262  &ticketContext->prevEncryptionState))
263  {
264  //Point to the previous set of keys
265  state = &ticketContext->prevEncryptionState;
266  }
267  else
268  {
269  //Unknown key name
270  error = ERROR_DECRYPTION_FAILED;
271  }
272 
273  //Check status code
274  if(!error)
275  {
276  //Point to the IV
277  iv = ciphertext + TLS_TICKET_KEY_NAME_SIZE;
278  //Point to the data
279  data = iv + TLS_TICKET_IV_SIZE;
280  //Point to the authentication tag
281  tag = ciphertext + ciphertextLen - TLS_TICKET_TAG_SIZE;
282 
283  //Retrieve the length of the data
284  *plaintextLen = ciphertextLen - TLS_TICKET_KEY_NAME_SIZE -
286 
287  //Initialize AES context
288  error = aesInit(&ticketContext->aesContext, state->key,
290  }
291 
292  //Check status code
293  if(!error)
294  {
295  //Initialize GCM context
296  error = gcmInit(&ticketContext->gcmContext, AES_CIPHER_ALGO,
297  &ticketContext->aesContext);
298  }
299 
300  //Check status code
301  if(!error)
302  {
303  //The actual state information in encrypted using AES-GCM
304  error = gcmDecrypt(&ticketContext->gcmContext, iv, TLS_TICKET_IV_SIZE,
305  state->keyName, TLS_TICKET_KEY_NAME_SIZE, data, plaintext,
306  *plaintextLen, tag, TLS_TICKET_TAG_SIZE);
307  }
308 
309  //Release exclusive access to the ticket encryption context
310  osReleaseMutex(&ticketContext->mutex);
311 
312  //Return status code
313  return error;
314 }
315 
316 
317 /**
318  * @brief Generate a new set of keys
319  * @param[in] ticketContext Pointer to ticket encryption context
320  * @param[in] prngAlgo PRNG algorithm
321  * @param[in] prngContext Pointer to the PRNG context
322  * @return Error code
323  **/
324 
326  const PrngAlgo *prngAlgo, void *prngContext)
327 {
328  error_t error;
330 
331  //Point to the current ticket encryption state
332  state = &ticketContext->encryptionState;
333 
334  //The set of keys is not valid anymore
335  state->valid = FALSE;
336 
337  //The key name should be randomly generated to avoid collisions between
338  //servers (refer to RFC 5077, section 4)
339  error = prngAlgo->read(prngContext, state->keyName,
341  //Any error to report?
342  if(error)
343  return error;
344 
345  //Generate a random encryption key
346  error = prngAlgo->read(prngContext, state->key, TLS_TICKET_KEY_SIZE);
347  //Any error to report?
348  if(error)
349  return error;
350 
351  //Save current time
352  state->timestamp = osGetSystemTime();
353  //The set of keys is valid
354  state->valid = TRUE;
355 
356  //Successful processing
357  return NO_ERROR;
358 }
359 
360 
361 /**
362  * @brief Check the validity of a given set of keys
363  * @param[in] state Pointer to ticket encryption state
364  **/
365 
367 {
368  systime_t time;
369 
370  //Get current time
371  time = osGetSystemTime();
372 
373  //Valid set of keys?
374  if(state->valid)
375  {
376  //Check lifetime
377  if((time - state->timestamp) >= (2 * TLS_TICKET_LIFETIME))
378  {
379  //Clear ticket keys
380  memset(state, 0, sizeof(TlsTicketEncryptionState));
381  }
382  }
383 }
384 
385 
386 /**
387  * @brief Key name comparison
388  * @param[in] ticket Encrypted ticket
389  * @param[in] ticketLen Length of the encrypted ticket, in bytes
390  * @param[in] state Pointer to ticket encryption state
391  **/
392 
393 bool_t tlsCompareTicketKeyName(const uint8_t *ticket, size_t ticketLen,
394  const TlsTicketEncryptionState *state)
395 {
396  bool_t res;
397 
398  //Initialize flag
399  res = FALSE;
400 
401  //Valid set of keys?
402  if(state->valid)
403  {
404  //The key name serves to identify a particular set of keys used to
405  //protect the ticket (refer to RFC 5077, section 4)
406  if(ticketLen >= TLS_TICKET_KEY_NAME_SIZE)
407  {
408  //Compare key names
409  if(memcmp(ticket, state->keyName, TLS_TICKET_KEY_NAME_SIZE) == 0)
410  {
411  //The key name is valid
412  res = TRUE;
413  }
414  }
415  }
416 
417  //Return comparison result
418  return res;
419 }
420 
421 
422 /**
423  * @brief Properly dispose ticket encryption context
424  * @param[in] ticketContext Pointer to ticket encryption context to be released
425  **/
426 
428 {
429  //Make sure the ticket encryption context is valid
430  if(ticketContext != NULL)
431  {
432  //Release previously allocated resources
433  osDeleteMutex(&ticketContext->mutex);
434 
435  //Erase ticket encryption context
436  memset(ticketContext, 0, sizeof(TlsTicketContext));
437  }
438 }
439 
440 #endif
error_t tlsInitTicketContext(TlsTicketContext *ticketContext)
Initialize ticket encryption context.
Definition: tls_ticket.c:50
int bool_t
Definition: compiler_port.h:49
TlsTicketEncryptionState encryptionState
Current set of keys.
Definition: tls_ticket.h:93
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
Common interface for pseudo-random number generators.
Definition: crypto.h:1168
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:211
PrngAlgoRead read
Definition: crypto.h:1176
@ ERROR_DECRYPTION_FAILED
Definition: error.h:236
#define TRUE
Definition: os_port.h:50
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
TlsTicketEncryptionState prevEncryptionState
Previous set of keys.
Definition: tls_ticket.h:94
const uint8_t res[]
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
Definition: aes.c:202
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:337
#define TLS_TICKET_IV_SIZE
Definition: tls_ticket.h:55
Session ticket encryption context.
Definition: tls_ticket.h:90
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
Session ticket encryption state.
Definition: tls_ticket.h:77
#define TlsContext
Definition: tls.h:36
error_t
Error codes.
Definition: error.h:42
bool_t tlsCompareTicketKeyName(const uint8_t *ticket, size_t ticketLen, const TlsTicketEncryptionState *state)
Key name comparison.
Definition: tls_ticket.c:393
TLS session tickets.
uint8_t key[TLS_TICKET_KEY_SIZE]
Encryption key.
Definition: tls_ticket.h:82
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:190
uint32_t time
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
#define TLS_TICKET_LIFETIME
Definition: tls.h:155
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 gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
Definition: gcm.c:78
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:366
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:40
#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:325
void tlsFreeTicketContext(TlsTicketContext *ticketContext)
Properly dispose ticket encryption context.
Definition: tls_ticket.c:427
#define TLS_TICKET_KEY_NAME_SIZE
Definition: tls_ticket.h:41
uint8_t data[]
Definition: dtls_misc.h:176
OsMutex mutex
Mutex preventing simultaneous access to the context.
Definition: tls_ticket.h:92
#define TLS_TICKET_TAG_SIZE
Definition: tls_ticket.h:62
uint32_t systime_t
Definition: compiler_port.h:46
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
systime_t osGetSystemTime(void)
Retrieve system time.