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  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneSSL Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL TLS_TRACE_LEVEL
31 
32 //Dependencies
33 #include <string.h>
34 #include "tls.h"
35 #include "tls_ticket.h"
36 #include "debug.h"
37 
38 //Check TLS library configuration
39 #if (TLS_SUPPORT == ENABLED && TLS_TICKET_SUPPORT == ENABLED)
40 
41 
42 /**
43  * @brief Initialize ticket encryption context
44  * @param[in] ticketContext Pointer to ticket encryption context
45  * @return Error code
46  **/
47 
49 {
50  //Make sure the ticket encryption context is valid
51  if(ticketContext == NULL)
53 
54  //Erase ticket encryption context
55  memset(ticketContext, 0, sizeof(TlsTicketContext));
56 
57  //Create a mutex to prevent simultaneous access to the context
58  if(!osCreateMutex(&ticketContext->mutex))
59  {
60  //Report an error
62  }
63 
64  //Sucessful initialization
65  return NO_ERROR;
66 }
67 
68 
69 /**
70  * @brief Session ticket encryption
71  * @param[in] context Pointer to the TLS context
72  * @param[in] plaintext Plaintext session state
73  * @param[in] plaintextLen Length of the plaintext session state, in bytes
74  * @param[out] ciphertext Encrypted ticket
75  * @param[out] ciphertextLen Length of the encrypted ticket, in bytes
76  * @param[in] param Pointer to the ticket encryption context
77  * @return Error code
78  **/
79 
80 error_t tlsEncryptTicket(TlsContext *context, const uint8_t *plaintext,
81  size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen, void *param)
82 {
83  error_t error;
84  uint8_t *iv;
85  uint8_t *data;
86  uint8_t *tag;
88  TlsTicketContext *ticketContext;
90 
91  //Check parameters
92  if(context == NULL || param == NULL)
94  if(plaintext == NULL || ciphertext == NULL || ciphertextLen == NULL)
96 
97  //Initialize status code
98  error = NO_ERROR;
99  //Point to the ticket encryption context
100  ticketContext = (TlsTicketContext *) param;
101 
102  //Acquire exclusive access to the ticket encryption context
103  osAcquireMutex(&ticketContext->mutex);
104 
105  //The keys should be changed regularly (refer to RFC 5077, section 5.5)
108 
109  //Point to the current ticket encryption state
110  state = &ticketContext->encryptionState;
111 
112  //Check whether the ticket encryption state is valid
113  if(state->valid)
114  {
115  //Get current time
116  time = osGetSystemTime();
117 
118  //Check the validity of the encryption keys
119  if((time - state->timestamp) >= TLS_TICKET_LIFETIME)
120  {
121  //Rotate keys
122  ticketContext->prevEncryptionState = ticketContext->encryptionState;
123  ticketContext->encryptionState.valid = FALSE;
124  }
125  }
126 
127  //Invalid set of keys?
128  if(!state->valid)
129  {
130  //Generate a new set of keys
131  error = tlsGenerateTicketKeys(ticketContext, context->prngAlgo,
132  context->prngContext);
133  }
134 
135  //Check status code
136  if(!error)
137  {
138  //Point to the IV
139  iv = ciphertext + TLS_TICKET_KEY_NAME_SIZE;
140  //Point to the data
141  data = iv + TLS_TICKET_IV_SIZE;
142  //Point to the buffer where to store the authentication tag
143  tag = data + plaintextLen;
144 
145  //Copy plaintext state
146  memmove(data, plaintext, plaintextLen);
147  //Copy key name
148  memcpy(ciphertext, state->keyName, TLS_TICKET_KEY_NAME_SIZE);
149 
150  //Generate a random IV
151  error = context->prngAlgo->read(context->prngContext, iv,
153  }
154 
155  //Check status code
156  if(!error)
157  {
158  //Initialize AES context
159  error = aesInit(&ticketContext->aesContext, state->key,
161  }
162 
163  //Check status code
164  if(!error)
165  {
166  //Initialize GCM context
167  error = gcmInit(&ticketContext->gcmContext, AES_CIPHER_ALGO,
168  &ticketContext->aesContext);
169  }
170 
171  //Check status code
172  if(!error)
173  {
174  //Calculate the length of the encrypted ticket
175  *ciphertextLen = plaintextLen + TLS_TICKET_KEY_NAME_SIZE +
177 
178  //The actual state information in encrypted using AES-GCM
179  error = gcmEncrypt(&ticketContext->gcmContext, iv, TLS_TICKET_IV_SIZE,
180  state->keyName, TLS_TICKET_KEY_NAME_SIZE, data, data, plaintextLen,
181  tag, TLS_TICKET_TAG_SIZE);
182  }
183 
184  //Release exclusive access to the ticket encryption context
185  osReleaseMutex(&ticketContext->mutex);
186 
187  //Return status code
188  return error;
189 }
190 
191 
192 /**
193  * @brief Session ticket decryption
194  * @param[in] context Pointer to the TLS context
195  * @param[in] ciphertext Encrypted ticket
196  * @param[in] ciphertextLen Length of the encrypted ticket, in bytes
197  * @param[out] plaintext Plaintext session state
198  * @param[out] plaintextLen Length of the plaintext session state, in bytes
199  * @param[in] param Pointer to the ticket encryption context
200  * @return Error code
201  **/
202 
203 error_t tlsDecryptTicket(TlsContext *context, const uint8_t *ciphertext,
204  size_t ciphertextLen, uint8_t *plaintext, size_t *plaintextLen, void *param)
205 {
206  error_t error;
207  const uint8_t *iv;
208  const uint8_t *data;
209  const uint8_t *tag;
210  TlsTicketContext *ticketContext;
212 
213  //Check parameters
214  if(context == NULL || param == NULL)
216  if(ciphertext == NULL || plaintext == NULL || plaintextLen == NULL)
218 
219  //Check the length of the encrypted ticket
220  if(ciphertextLen < (TLS_TICKET_KEY_NAME_SIZE + TLS_TICKET_IV_SIZE +
222  {
223  //Report an error
225  }
226 
227  //Initialize status code
228  error = NO_ERROR;
229  //Point to the ticket encryption context
230  ticketContext = (TlsTicketContext *) param;
231 
232  //Acquire exclusive access to the ticket encryption context
233  osAcquireMutex(&ticketContext->mutex);
234 
235  //The keys should be changed regularly (refer to RFC 5077, section 5.5)
238 
239  //Compare key names
240  if(tlsCompareTicketKeyName(ciphertext, ciphertextLen,
241  &ticketContext->encryptionState))
242  {
243  //Point to the current set of keys
244  state = &ticketContext->encryptionState;
245  }
246  else if(tlsCompareTicketKeyName(ciphertext, ciphertextLen,
247  &ticketContext->prevEncryptionState))
248  {
249  //Point to the previous set of keys
250  state = &ticketContext->prevEncryptionState;
251  }
252  else
253  {
254  //Unknown key name
255  error = ERROR_DECRYPTION_FAILED;
256  }
257 
258  //Check status code
259  if(!error)
260  {
261  //Point to the IV
262  iv = ciphertext + TLS_TICKET_KEY_NAME_SIZE;
263  //Point to the data
264  data = iv + TLS_TICKET_IV_SIZE;
265  //Point to the authentication tag
266  tag = ciphertext + ciphertextLen - TLS_TICKET_TAG_SIZE;
267 
268  //Retrieve the length of the data
269  *plaintextLen = ciphertextLen - TLS_TICKET_KEY_NAME_SIZE -
271 
272  //Initialize AES context
273  error = aesInit(&ticketContext->aesContext, state->key,
275  }
276 
277  //Check status code
278  if(!error)
279  {
280  //Initialize GCM context
281  error = gcmInit(&ticketContext->gcmContext, AES_CIPHER_ALGO,
282  &ticketContext->aesContext);
283  }
284 
285  //Check status code
286  if(!error)
287  {
288  //The actual state information in encrypted using AES-GCM
289  error = gcmDecrypt(&ticketContext->gcmContext, iv, TLS_TICKET_IV_SIZE,
290  state->keyName, TLS_TICKET_KEY_NAME_SIZE, data, plaintext, *plaintextLen,
291  tag, TLS_TICKET_TAG_SIZE);
292  }
293 
294  //Release exclusive access to the ticket encryption context
295  osReleaseMutex(&ticketContext->mutex);
296 
297  //Return status code
298  return error;
299 }
300 
301 
302 /**
303  * @brief Generate a new set of keys
304  * @param[in] ticketContext Pointer to ticket encryption context
305  * @param[in] prngAlgo PRNG algorithm
306  * @param[in] prngContext Pointer to the PRNG context
307  * @return Error code
308  **/
309 
311  const PrngAlgo *prngAlgo, void *prngContext)
312 {
313  error_t error;
315 
316  //Point to the current ticket encryption state
317  state = &ticketContext->encryptionState;
318 
319  //The set of keys is not valid anymore
320  state->valid = FALSE;
321 
322  //The key name should be randomly generated to avoid collisions between
323  //servers (refer to RFC 5077, section 4)
324  error = prngAlgo->read(prngContext, state->keyName,
326  //Any error to report?
327  if(error)
328  return error;
329 
330  //Generate a random encryption key
331  error = prngAlgo->read(prngContext, state->key, TLS_TICKET_KEY_SIZE);
332  //Any error to report?
333  if(error)
334  return error;
335 
336  //Save current time
337  state->timestamp = osGetSystemTime();
338  //The set of keys is valid
339  state->valid = TRUE;
340 
341  //Successful processing
342  return NO_ERROR;
343 }
344 
345 
346 /**
347  * @brief Check the validity of a given set of keys
348  * @param[in] state Pointer to ticket encryption state
349  **/
350 
352 {
353  systime_t time;
354 
355  //Get current time
356  time = osGetSystemTime();
357 
358  //Valid set of keys?
359  if(state->valid)
360  {
361  //Check lifetime
362  if((time - state->timestamp) >= (2 * TLS_TICKET_LIFETIME))
363  {
364  //Clear ticket keys
365  memset(state, 0, sizeof(TlsTicketEncryptionState));
366  }
367  }
368 }
369 
370 
371 /**
372  * @brief Key name comparison
373  * @param[in] ticket Encrypted ticket
374  * @param[in] ticketLen Length of the encrypted ticket, in bytes
375  * @param[in] state Pointer to ticket encryption state
376  **/
377 
378 bool_t tlsCompareTicketKeyName(const uint8_t *ticket, size_t ticketLen,
379  const TlsTicketEncryptionState *state)
380 {
381  bool_t res;
382 
383  //Initialize flag
384  res = FALSE;
385 
386  //Valid set of keys?
387  if(state->valid)
388  {
389  //The key name serves to identify a particular set of keys used to
390  //protect the ticket (refer to RFC 5077, section 4)
391  if(ticketLen >= TLS_TICKET_KEY_NAME_SIZE)
392  {
393  //Compare key names
394  if(memcmp(ticket, state->keyName, TLS_TICKET_KEY_NAME_SIZE) == 0)
395  {
396  //The key name is valid
397  res = TRUE;
398  }
399  }
400  }
401 
402  //Return comparison result
403  return res;
404 }
405 
406 
407 /**
408  * @brief Properly dispose ticket encryption context
409  * @param[in] ticketContext Pointer to ticket encryption context to be released
410  **/
411 
413 {
414  //Make sure the ticket encryption context is valid
415  if(ticketContext != NULL)
416  {
417  //Release previously allocated resources
418  osDeleteMutex(&ticketContext->mutex);
419 
420  //Erase ticket encryption context
421  memset(ticketContext, 0, sizeof(TlsTicketContext));
422  }
423 }
424 
425 #endif
TLS (Transport Layer Security)
#define TLS_TICKET_KEY_SIZE
Definition: tls_ticket.h:46
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
uint32_t systime_t
Definition: compiler_port.h:44
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
void tlsFreeTicketContext(TlsTicketContext *ticketContext)
Properly dispose ticket encryption context.
Definition: tls_ticket.c:412
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t time
Debugging facilities.
uint8_t res[]
error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
Definition: gcm.c:76
Invalid parameter.
Definition: error.h:45
GcmContext gcmContext
GCM context.
Definition: tls_ticket.h:94
bool_t valid
Valid set of keys.
Definition: tls_ticket.h:77
#define TLS_TICKET_LIFETIME
Definition: tls.h:153
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:188
void tlsCheckTicketKeyLifetime(TlsTicketEncryptionState *state)
Check the validity of a given set of keys.
Definition: tls_ticket.c:351
#define TRUE
Definition: os_port.h:48
TLS session tickets.
OsMutex mutex
Mutex preventing simultaneous access to the context.
Definition: tls_ticket.h:90
Session ticket encryption context.
Definition: tls_ticket.h:88
AesContext aesContext
AES context.
Definition: tls_ticket.h:93
error_t tlsInitTicketContext(TlsTicketContext *ticketContext)
Initialize ticket encryption context.
Definition: tls_ticket.c:48
error_t tlsGenerateTicketKeys(TlsTicketContext *ticketContext, const PrngAlgo *prngAlgo, void *prngContext)
Generate a new set of keys.
Definition: tls_ticket.c:310
uint8_t key[TLS_TICKET_KEY_SIZE]
Encryption key.
Definition: tls_ticket.h:80
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:335
TlsTicketEncryptionState encryptionState
Current set of keys.
Definition: tls_ticket.h:91
Success.
Definition: error.h:42
systime_t timestamp
Generation time.
Definition: tls_ticket.h:78
error_t
Error codes.
Definition: error.h:40
bool_t tlsCompareTicketKeyName(const uint8_t *ticket, size_t ticketLen, const TlsTicketEncryptionState *state)
Key name comparison.
Definition: tls_ticket.c:378
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
uint8_t keyName[TLS_TICKET_KEY_NAME_SIZE]
Key identifier.
Definition: tls_ticket.h:79
uint8_t data[]
Definition: dtls_misc.h:167
Common interface for pseudo-random number generators.
Definition: crypto.h:1091
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen)
Key expansion.
Definition: aes.c:200
#define TLS_TICKET_IV_SIZE
Definition: tls_ticket.h:53
#define AES_CIPHER_ALGO
Definition: aes.h:38
#define TLS_TICKET_KEY_NAME_SIZE
Definition: tls_ticket.h:39
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:203
TlsTicketEncryptionState prevEncryptionState
Previous set of keys.
Definition: tls_ticket.h:92
#define FALSE
Definition: os_port.h:44
#define TlsContext
Definition: tls.h:34
int bool_t
Definition: compiler_port.h:47
Session ticket encryption state.
Definition: tls_ticket.h:75
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
#define TLS_TICKET_TAG_SIZE
Definition: tls_ticket.h:60
PrngAlgoRead read
Definition: crypto.h:1099
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:80