1 | /*
|
---|
2 | * TLS server tickets callbacks implementation
|
---|
3 | *
|
---|
4 | * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
---|
5 | * SPDX-License-Identifier: Apache-2.0
|
---|
6 | *
|
---|
7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may
|
---|
8 | * not use this file except in compliance with the License.
|
---|
9 | * You may obtain a copy of the License at
|
---|
10 | *
|
---|
11 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
12 | *
|
---|
13 | * Unless required by applicable law or agreed to in writing, software
|
---|
14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
---|
15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
16 | * See the License for the specific language governing permissions and
|
---|
17 | * limitations under the License.
|
---|
18 | *
|
---|
19 | * This file is part of mbed TLS (https://tls.mbed.org)
|
---|
20 | */
|
---|
21 |
|
---|
22 | #if !defined(MBEDTLS_CONFIG_FILE)
|
---|
23 | #include "mbedtls/config.h"
|
---|
24 | #else
|
---|
25 | #include MBEDTLS_CONFIG_FILE
|
---|
26 | #endif
|
---|
27 |
|
---|
28 | #if defined(MBEDTLS_SSL_TICKET_C)
|
---|
29 |
|
---|
30 | #if defined(MBEDTLS_PLATFORM_C)
|
---|
31 | #include "mbedtls/platform.h"
|
---|
32 | #else
|
---|
33 | #include <stdlib.h>
|
---|
34 | #define mbedtls_calloc calloc
|
---|
35 | #define mbedtls_free free
|
---|
36 | #endif
|
---|
37 |
|
---|
38 | #include "mbedtls/ssl_ticket.h"
|
---|
39 | #include "mbedtls/platform_util.h"
|
---|
40 |
|
---|
41 | #include <string.h>
|
---|
42 |
|
---|
43 | /*
|
---|
44 | * Initialze context
|
---|
45 | */
|
---|
46 | void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
|
---|
47 | {
|
---|
48 | memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
|
---|
49 |
|
---|
50 | #if defined(MBEDTLS_THREADING_C)
|
---|
51 | mbedtls_mutex_init( &ctx->mutex );
|
---|
52 | #endif
|
---|
53 | }
|
---|
54 |
|
---|
55 | #define MAX_KEY_BYTES 32 /* 256 bits */
|
---|
56 |
|
---|
57 | /*
|
---|
58 | * Generate/update a key
|
---|
59 | */
|
---|
60 | static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx,
|
---|
61 | unsigned char index )
|
---|
62 | {
|
---|
63 | int ret;
|
---|
64 | unsigned char buf[MAX_KEY_BYTES];
|
---|
65 | mbedtls_ssl_ticket_key *key = ctx->keys + index;
|
---|
66 |
|
---|
67 | #if defined(MBEDTLS_HAVE_TIME)
|
---|
68 | key->generation_time = (uint32_t) mbedtls_time( NULL );
|
---|
69 | #endif
|
---|
70 |
|
---|
71 | if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 )
|
---|
72 | return( ret );
|
---|
73 |
|
---|
74 | if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 )
|
---|
75 | return( ret );
|
---|
76 |
|
---|
77 | /* With GCM and CCM, same context can encrypt & decrypt */
|
---|
78 | ret = mbedtls_cipher_setkey( &key->ctx, buf,
|
---|
79 | mbedtls_cipher_get_key_bitlen( &key->ctx ),
|
---|
80 | MBEDTLS_ENCRYPT );
|
---|
81 |
|
---|
82 | mbedtls_platform_zeroize( buf, sizeof( buf ) );
|
---|
83 |
|
---|
84 | return( ret );
|
---|
85 | }
|
---|
86 |
|
---|
87 | /*
|
---|
88 | * Rotate/generate keys if necessary
|
---|
89 | */
|
---|
90 | static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx )
|
---|
91 | {
|
---|
92 | #if !defined(MBEDTLS_HAVE_TIME)
|
---|
93 | ((void) ctx);
|
---|
94 | #else
|
---|
95 | if( ctx->ticket_lifetime != 0 )
|
---|
96 | {
|
---|
97 | uint32_t current_time = (uint32_t) mbedtls_time( NULL );
|
---|
98 | uint32_t key_time = ctx->keys[ctx->active].generation_time;
|
---|
99 |
|
---|
100 | if( current_time >= key_time &&
|
---|
101 | current_time - key_time < ctx->ticket_lifetime )
|
---|
102 | {
|
---|
103 | return( 0 );
|
---|
104 | }
|
---|
105 |
|
---|
106 | ctx->active = 1 - ctx->active;
|
---|
107 |
|
---|
108 | return( ssl_ticket_gen_key( ctx, ctx->active ) );
|
---|
109 | }
|
---|
110 | else
|
---|
111 | #endif /* MBEDTLS_HAVE_TIME */
|
---|
112 | return( 0 );
|
---|
113 | }
|
---|
114 |
|
---|
115 | /*
|
---|
116 | * Setup context for actual use
|
---|
117 | */
|
---|
118 | int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
|
---|
119 | int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
|
---|
120 | mbedtls_cipher_type_t cipher,
|
---|
121 | uint32_t lifetime )
|
---|
122 | {
|
---|
123 | int ret;
|
---|
124 | const mbedtls_cipher_info_t *cipher_info;
|
---|
125 |
|
---|
126 | ctx->f_rng = f_rng;
|
---|
127 | ctx->p_rng = p_rng;
|
---|
128 |
|
---|
129 | ctx->ticket_lifetime = lifetime;
|
---|
130 |
|
---|
131 | cipher_info = mbedtls_cipher_info_from_type( cipher);
|
---|
132 | if( cipher_info == NULL )
|
---|
133 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
134 |
|
---|
135 | if( cipher_info->mode != MBEDTLS_MODE_GCM &&
|
---|
136 | cipher_info->mode != MBEDTLS_MODE_CCM )
|
---|
137 | {
|
---|
138 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
139 | }
|
---|
140 |
|
---|
141 | if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES )
|
---|
142 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
143 |
|
---|
144 | if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 ||
|
---|
145 | ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 )
|
---|
146 | {
|
---|
147 | return( ret );
|
---|
148 | }
|
---|
149 |
|
---|
150 | if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 ||
|
---|
151 | ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 )
|
---|
152 | {
|
---|
153 | return( ret );
|
---|
154 | }
|
---|
155 |
|
---|
156 | return( 0 );
|
---|
157 | }
|
---|
158 |
|
---|
159 | /*
|
---|
160 | * Serialize a session in the following format:
|
---|
161 | * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
|
---|
162 | * n . n+2 peer_cert length = m (0 if no certificate)
|
---|
163 | * n+3 . n+2+m peer cert ASN.1
|
---|
164 | */
|
---|
165 | static int ssl_save_session( const mbedtls_ssl_session *session,
|
---|
166 | unsigned char *buf, size_t buf_len,
|
---|
167 | size_t *olen )
|
---|
168 | {
|
---|
169 | unsigned char *p = buf;
|
---|
170 | size_t left = buf_len;
|
---|
171 | #if defined(MBEDTLS_X509_CRT_PARSE_C)
|
---|
172 | size_t cert_len;
|
---|
173 | #endif /* MBEDTLS_X509_CRT_PARSE_C */
|
---|
174 |
|
---|
175 | if( left < sizeof( mbedtls_ssl_session ) )
|
---|
176 | return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
|
---|
177 |
|
---|
178 | memcpy( p, session, sizeof( mbedtls_ssl_session ) );
|
---|
179 | p += sizeof( mbedtls_ssl_session );
|
---|
180 | left -= sizeof( mbedtls_ssl_session );
|
---|
181 |
|
---|
182 | #if defined(MBEDTLS_X509_CRT_PARSE_C)
|
---|
183 | if( session->peer_cert == NULL )
|
---|
184 | cert_len = 0;
|
---|
185 | else
|
---|
186 | cert_len = session->peer_cert->raw.len;
|
---|
187 |
|
---|
188 | if( left < 3 + cert_len )
|
---|
189 | return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
|
---|
190 |
|
---|
191 | *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );
|
---|
192 | *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF );
|
---|
193 | *p++ = (unsigned char)( ( cert_len ) & 0xFF );
|
---|
194 |
|
---|
195 | if( session->peer_cert != NULL )
|
---|
196 | memcpy( p, session->peer_cert->raw.p, cert_len );
|
---|
197 |
|
---|
198 | p += cert_len;
|
---|
199 | #endif /* MBEDTLS_X509_CRT_PARSE_C */
|
---|
200 |
|
---|
201 | *olen = p - buf;
|
---|
202 |
|
---|
203 | return( 0 );
|
---|
204 | }
|
---|
205 |
|
---|
206 | /*
|
---|
207 | * Unserialise session, see ssl_save_session()
|
---|
208 | */
|
---|
209 | static int ssl_load_session( mbedtls_ssl_session *session,
|
---|
210 | const unsigned char *buf, size_t len )
|
---|
211 | {
|
---|
212 | const unsigned char *p = buf;
|
---|
213 | const unsigned char * const end = buf + len;
|
---|
214 | #if defined(MBEDTLS_X509_CRT_PARSE_C)
|
---|
215 | size_t cert_len;
|
---|
216 | #endif /* MBEDTLS_X509_CRT_PARSE_C */
|
---|
217 |
|
---|
218 | if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
|
---|
219 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
220 |
|
---|
221 | memcpy( session, p, sizeof( mbedtls_ssl_session ) );
|
---|
222 | p += sizeof( mbedtls_ssl_session );
|
---|
223 |
|
---|
224 | #if defined(MBEDTLS_X509_CRT_PARSE_C)
|
---|
225 | if( 3 > (size_t)( end - p ) )
|
---|
226 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
227 |
|
---|
228 | cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
|
---|
229 | p += 3;
|
---|
230 |
|
---|
231 | if( cert_len == 0 )
|
---|
232 | {
|
---|
233 | session->peer_cert = NULL;
|
---|
234 | }
|
---|
235 | else
|
---|
236 | {
|
---|
237 | int ret;
|
---|
238 |
|
---|
239 | if( cert_len > (size_t)( end - p ) )
|
---|
240 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
241 |
|
---|
242 | session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
|
---|
243 |
|
---|
244 | if( session->peer_cert == NULL )
|
---|
245 | return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
|
---|
246 |
|
---|
247 | mbedtls_x509_crt_init( session->peer_cert );
|
---|
248 |
|
---|
249 | if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
|
---|
250 | p, cert_len ) ) != 0 )
|
---|
251 | {
|
---|
252 | mbedtls_x509_crt_free( session->peer_cert );
|
---|
253 | mbedtls_free( session->peer_cert );
|
---|
254 | session->peer_cert = NULL;
|
---|
255 | return( ret );
|
---|
256 | }
|
---|
257 |
|
---|
258 | p += cert_len;
|
---|
259 | }
|
---|
260 | #endif /* MBEDTLS_X509_CRT_PARSE_C */
|
---|
261 |
|
---|
262 | if( p != end )
|
---|
263 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
264 |
|
---|
265 | return( 0 );
|
---|
266 | }
|
---|
267 |
|
---|
268 | /*
|
---|
269 | * Create session ticket, with the following structure:
|
---|
270 | *
|
---|
271 | * struct {
|
---|
272 | * opaque key_name[4];
|
---|
273 | * opaque iv[12];
|
---|
274 | * opaque encrypted_state<0..2^16-1>;
|
---|
275 | * opaque tag[16];
|
---|
276 | * } ticket;
|
---|
277 | *
|
---|
278 | * The key_name, iv, and length of encrypted_state are the additional
|
---|
279 | * authenticated data.
|
---|
280 | */
|
---|
281 | int mbedtls_ssl_ticket_write( void *p_ticket,
|
---|
282 | const mbedtls_ssl_session *session,
|
---|
283 | unsigned char *start,
|
---|
284 | const unsigned char *end,
|
---|
285 | size_t *tlen,
|
---|
286 | uint32_t *ticket_lifetime )
|
---|
287 | {
|
---|
288 | int ret;
|
---|
289 | mbedtls_ssl_ticket_context *ctx = p_ticket;
|
---|
290 | mbedtls_ssl_ticket_key *key;
|
---|
291 | unsigned char *key_name = start;
|
---|
292 | unsigned char *iv = start + 4;
|
---|
293 | unsigned char *state_len_bytes = iv + 12;
|
---|
294 | unsigned char *state = state_len_bytes + 2;
|
---|
295 | unsigned char *tag;
|
---|
296 | size_t clear_len, ciph_len;
|
---|
297 |
|
---|
298 | *tlen = 0;
|
---|
299 |
|
---|
300 | if( ctx == NULL || ctx->f_rng == NULL )
|
---|
301 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
302 |
|
---|
303 | /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag,
|
---|
304 | * in addition to session itself, that will be checked when writing it. */
|
---|
305 | if( end - start < 4 + 12 + 2 + 16 )
|
---|
306 | return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
|
---|
307 |
|
---|
308 | #if defined(MBEDTLS_THREADING_C)
|
---|
309 | if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
|
---|
310 | return( ret );
|
---|
311 | #endif
|
---|
312 |
|
---|
313 | if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
|
---|
314 | goto cleanup;
|
---|
315 |
|
---|
316 | key = &ctx->keys[ctx->active];
|
---|
317 |
|
---|
318 | *ticket_lifetime = ctx->ticket_lifetime;
|
---|
319 |
|
---|
320 | memcpy( key_name, key->name, 4 );
|
---|
321 |
|
---|
322 | if( ( ret = ctx->f_rng( ctx->p_rng, iv, 12 ) ) != 0 )
|
---|
323 | goto cleanup;
|
---|
324 |
|
---|
325 | /* Dump session state */
|
---|
326 | if( ( ret = ssl_save_session( session,
|
---|
327 | state, end - state, &clear_len ) ) != 0 ||
|
---|
328 | (unsigned long) clear_len > 65535 )
|
---|
329 | {
|
---|
330 | goto cleanup;
|
---|
331 | }
|
---|
332 | state_len_bytes[0] = ( clear_len >> 8 ) & 0xff;
|
---|
333 | state_len_bytes[1] = ( clear_len ) & 0xff;
|
---|
334 |
|
---|
335 | /* Encrypt and authenticate */
|
---|
336 | tag = state + clear_len;
|
---|
337 | if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx,
|
---|
338 | iv, 12, key_name, 4 + 12 + 2,
|
---|
339 | state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 )
|
---|
340 | {
|
---|
341 | goto cleanup;
|
---|
342 | }
|
---|
343 | if( ciph_len != clear_len )
|
---|
344 | {
|
---|
345 | ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
|
---|
346 | goto cleanup;
|
---|
347 | }
|
---|
348 |
|
---|
349 | *tlen = 4 + 12 + 2 + 16 + ciph_len;
|
---|
350 |
|
---|
351 | cleanup:
|
---|
352 | #if defined(MBEDTLS_THREADING_C)
|
---|
353 | if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
|
---|
354 | return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
|
---|
355 | #endif
|
---|
356 |
|
---|
357 | return( ret );
|
---|
358 | }
|
---|
359 |
|
---|
360 | /*
|
---|
361 | * Select key based on name
|
---|
362 | */
|
---|
363 | static mbedtls_ssl_ticket_key *ssl_ticket_select_key(
|
---|
364 | mbedtls_ssl_ticket_context *ctx,
|
---|
365 | const unsigned char name[4] )
|
---|
366 | {
|
---|
367 | unsigned char i;
|
---|
368 |
|
---|
369 | for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ )
|
---|
370 | if( memcmp( name, ctx->keys[i].name, 4 ) == 0 )
|
---|
371 | return( &ctx->keys[i] );
|
---|
372 |
|
---|
373 | return( NULL );
|
---|
374 | }
|
---|
375 |
|
---|
376 | /*
|
---|
377 | * Load session ticket (see mbedtls_ssl_ticket_write for structure)
|
---|
378 | */
|
---|
379 | int mbedtls_ssl_ticket_parse( void *p_ticket,
|
---|
380 | mbedtls_ssl_session *session,
|
---|
381 | unsigned char *buf,
|
---|
382 | size_t len )
|
---|
383 | {
|
---|
384 | int ret;
|
---|
385 | mbedtls_ssl_ticket_context *ctx = p_ticket;
|
---|
386 | mbedtls_ssl_ticket_key *key;
|
---|
387 | unsigned char *key_name = buf;
|
---|
388 | unsigned char *iv = buf + 4;
|
---|
389 | unsigned char *enc_len_p = iv + 12;
|
---|
390 | unsigned char *ticket = enc_len_p + 2;
|
---|
391 | unsigned char *tag;
|
---|
392 | size_t enc_len, clear_len;
|
---|
393 |
|
---|
394 | if( ctx == NULL || ctx->f_rng == NULL )
|
---|
395 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
396 |
|
---|
397 | /* See mbedtls_ssl_ticket_write() */
|
---|
398 | if( len < 4 + 12 + 2 + 16 )
|
---|
399 | return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
|
---|
400 |
|
---|
401 | #if defined(MBEDTLS_THREADING_C)
|
---|
402 | if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
|
---|
403 | return( ret );
|
---|
404 | #endif
|
---|
405 |
|
---|
406 | if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 )
|
---|
407 | goto cleanup;
|
---|
408 |
|
---|
409 | enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
|
---|
410 | tag = ticket + enc_len;
|
---|
411 |
|
---|
412 | if( len != 4 + 12 + 2 + enc_len + 16 )
|
---|
413 | {
|
---|
414 | ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
|
---|
415 | goto cleanup;
|
---|
416 | }
|
---|
417 |
|
---|
418 | /* Select key */
|
---|
419 | if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL )
|
---|
420 | {
|
---|
421 | /* We can't know for sure but this is a likely option unless we're
|
---|
422 | * under attack - this is only informative anyway */
|
---|
423 | ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
|
---|
424 | goto cleanup;
|
---|
425 | }
|
---|
426 |
|
---|
427 | /* Decrypt and authenticate */
|
---|
428 | if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx, iv, 12,
|
---|
429 | key_name, 4 + 12 + 2, ticket, enc_len,
|
---|
430 | ticket, &clear_len, tag, 16 ) ) != 0 )
|
---|
431 | {
|
---|
432 | if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
|
---|
433 | ret = MBEDTLS_ERR_SSL_INVALID_MAC;
|
---|
434 |
|
---|
435 | goto cleanup;
|
---|
436 | }
|
---|
437 | if( clear_len != enc_len )
|
---|
438 | {
|
---|
439 | ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
|
---|
440 | goto cleanup;
|
---|
441 | }
|
---|
442 |
|
---|
443 | /* Actually load session */
|
---|
444 | if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
|
---|
445 | goto cleanup;
|
---|
446 |
|
---|
447 | #if defined(MBEDTLS_HAVE_TIME)
|
---|
448 | {
|
---|
449 | /* Check for expiration */
|
---|
450 | mbedtls_time_t current_time = mbedtls_time( NULL );
|
---|
451 |
|
---|
452 | if( current_time < session->start ||
|
---|
453 | (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime )
|
---|
454 | {
|
---|
455 | ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
|
---|
456 | goto cleanup;
|
---|
457 | }
|
---|
458 | }
|
---|
459 | #endif
|
---|
460 |
|
---|
461 | cleanup:
|
---|
462 | #if defined(MBEDTLS_THREADING_C)
|
---|
463 | if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
|
---|
464 | return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
|
---|
465 | #endif
|
---|
466 |
|
---|
467 | return( ret );
|
---|
468 | }
|
---|
469 |
|
---|
470 | /*
|
---|
471 | * Free context
|
---|
472 | */
|
---|
473 | void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx )
|
---|
474 | {
|
---|
475 | mbedtls_cipher_free( &ctx->keys[0].ctx );
|
---|
476 | mbedtls_cipher_free( &ctx->keys[1].ctx );
|
---|
477 |
|
---|
478 | #if defined(MBEDTLS_THREADING_C)
|
---|
479 | mbedtls_mutex_free( &ctx->mutex );
|
---|
480 | #endif
|
---|
481 |
|
---|
482 | mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
|
---|
483 | }
|
---|
484 |
|
---|
485 | #endif /* MBEDTLS_SSL_TICKET_C */
|
---|