97a195f353f280dea51b8675f1968bbcb0fb2573
[libeap.git] / src / tls / tlsv1_client.c
1 /*
2  * TLSv1 client (RFC 2246)
3  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "sha1.h"
19 #include "tls.h"
20 #include "tlsv1_common.h"
21 #include "tlsv1_record.h"
22 #include "tlsv1_client.h"
23 #include "tlsv1_client_i.h"
24
25 /* TODO:
26  * Support for a message fragmented across several records (RFC 2246, 6.2.1)
27  */
28
29
30 void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
31 {
32         conn->alert_level = level;
33         conn->alert_description = description;
34 }
35
36
37 void tlsv1_client_free_dh(struct tlsv1_client *conn)
38 {
39         os_free(conn->dh_p);
40         os_free(conn->dh_g);
41         os_free(conn->dh_ys);
42         conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
43 }
44
45
46 int tls_derive_pre_master_secret(u8 *pre_master_secret)
47 {
48         WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
49         if (os_get_random(pre_master_secret + 2,
50                           TLS_PRE_MASTER_SECRET_LEN - 2))
51                 return -1;
52         return 0;
53 }
54
55
56 int tls_derive_keys(struct tlsv1_client *conn,
57                     const u8 *pre_master_secret, size_t pre_master_secret_len)
58 {
59         u8 seed[2 * TLS_RANDOM_LEN];
60         u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
61         u8 *pos;
62         size_t key_block_len;
63
64         if (pre_master_secret) {
65                 wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
66                                 pre_master_secret, pre_master_secret_len);
67                 os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
68                 os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
69                           TLS_RANDOM_LEN);
70                 if (tls_prf(pre_master_secret, pre_master_secret_len,
71                             "master secret", seed, 2 * TLS_RANDOM_LEN,
72                             conn->master_secret, TLS_MASTER_SECRET_LEN)) {
73                         wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
74                                    "master_secret");
75                         return -1;
76                 }
77                 wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
78                                 conn->master_secret, TLS_MASTER_SECRET_LEN);
79         }
80
81         os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
82         os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
83         key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
84                              conn->rl.iv_size);
85         if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
86                     "key expansion", seed, 2 * TLS_RANDOM_LEN,
87                     key_block, key_block_len)) {
88                 wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
89                 return -1;
90         }
91         wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
92                         key_block, key_block_len);
93
94         pos = key_block;
95
96         /* client_write_MAC_secret */
97         os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
98         pos += conn->rl.hash_size;
99         /* server_write_MAC_secret */
100         os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
101         pos += conn->rl.hash_size;
102
103         /* client_write_key */
104         os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
105         pos += conn->rl.key_material_len;
106         /* server_write_key */
107         os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
108         pos += conn->rl.key_material_len;
109
110         /* client_write_IV */
111         os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
112         pos += conn->rl.iv_size;
113         /* server_write_IV */
114         os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
115         pos += conn->rl.iv_size;
116
117         return 0;
118 }
119
120
121 /**
122  * tlsv1_client_handshake - Process TLS handshake
123  * @conn: TLSv1 client connection data from tlsv1_client_init()
124  * @in_data: Input data from TLS peer
125  * @in_len: Input data length
126  * @out_len: Length of the output buffer.
127  * Returns: Pointer to output data, %NULL on failure
128  */
129 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
130                             const u8 *in_data, size_t in_len,
131                             size_t *out_len, u8 **appl_data,
132                             size_t *appl_data_len)
133 {
134         const u8 *pos, *end;
135         u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
136         size_t in_msg_len;
137         int no_appl_data;
138
139         if (conn->state == CLIENT_HELLO) {
140                 if (in_len)
141                         return NULL;
142                 return tls_send_client_hello(conn, out_len);
143         }
144
145         if (in_data == NULL || in_len == 0)
146                 return NULL;
147
148         pos = in_data;
149         end = in_data + in_len;
150         in_msg = os_malloc(in_len);
151         if (in_msg == NULL)
152                 return NULL;
153
154         /* Each received packet may include multiple records */
155         while (pos < end) {
156                 in_msg_len = in_len;
157                 if (tlsv1_record_receive(&conn->rl, pos, end - pos,
158                                          in_msg, &in_msg_len, &alert)) {
159                         wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
160                                    "record failed");
161                         tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
162                         goto failed;
163                 }
164                 ct = pos[0];
165
166                 in_pos = in_msg;
167                 in_end = in_msg + in_msg_len;
168
169                 /* Each received record may include multiple messages of the
170                  * same ContentType. */
171                 while (in_pos < in_end) {
172                         in_msg_len = in_end - in_pos;
173                         if (tlsv1_client_process_handshake(conn, ct, in_pos,
174                                                            &in_msg_len,
175                                                            appl_data,
176                                                            appl_data_len) < 0)
177                                 goto failed;
178                         in_pos += in_msg_len;
179                 }
180
181                 pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
182         }
183
184         os_free(in_msg);
185         in_msg = NULL;
186
187         no_appl_data = appl_data == NULL || *appl_data == NULL;
188         msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
189
190 failed:
191         os_free(in_msg);
192         if (conn->alert_level) {
193                 conn->state = FAILED;
194                 os_free(msg);
195                 msg = tlsv1_client_send_alert(conn, conn->alert_level,
196                                               conn->alert_description,
197                                               out_len);
198         } else if (msg == NULL) {
199                 msg = os_zalloc(1);
200                 *out_len = 0;
201         }
202
203         return msg;
204 }
205
206
207 /**
208  * tlsv1_client_encrypt - Encrypt data into TLS tunnel
209  * @conn: TLSv1 client connection data from tlsv1_client_init()
210  * @in_data: Pointer to plaintext data to be encrypted
211  * @in_len: Input buffer length
212  * @out_data: Pointer to output buffer (encrypted TLS data)
213  * @out_len: Maximum out_data length 
214  * Returns: Number of bytes written to out_data, -1 on failure
215  *
216  * This function is used after TLS handshake has been completed successfully to
217  * send data in the encrypted tunnel.
218  */
219 int tlsv1_client_encrypt(struct tlsv1_client *conn,
220                          const u8 *in_data, size_t in_len,
221                          u8 *out_data, size_t out_len)
222 {
223         size_t rlen;
224
225         wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
226                         in_data, in_len);
227
228         os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
229
230         if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
231                               out_data, out_len, in_len, &rlen) < 0) {
232                 wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
233                 tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
234                           TLS_ALERT_INTERNAL_ERROR);
235                 return -1;
236         }
237
238         return rlen;
239 }
240
241
242 /**
243  * tlsv1_client_decrypt - Decrypt data from TLS tunnel
244  * @conn: TLSv1 client connection data from tlsv1_client_init()
245  * @in_data: Pointer to input buffer (encrypted TLS data)
246  * @in_len: Input buffer length
247  * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
248  * @out_len: Maximum out_data length
249  * Returns: Number of bytes written to out_data, -1 on failure
250  *
251  * This function is used after TLS handshake has been completed successfully to
252  * receive data from the encrypted tunnel.
253  */
254 int tlsv1_client_decrypt(struct tlsv1_client *conn,
255                          const u8 *in_data, size_t in_len,
256                          u8 *out_data, size_t out_len)
257 {
258         const u8 *in_end, *pos;
259         int res;
260         u8 alert, *out_end, *out_pos;
261         size_t olen;
262
263         pos = in_data;
264         in_end = in_data + in_len;
265         out_pos = out_data;
266         out_end = out_data + out_len;
267
268         while (pos < in_end) {
269                 if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
270                         wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
271                                    "0x%x", pos[0]);
272                         tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
273                                   TLS_ALERT_UNEXPECTED_MESSAGE);
274                         return -1;
275                 }
276
277                 olen = out_end - out_pos;
278                 res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
279                                            out_pos, &olen, &alert);
280                 if (res < 0) {
281                         wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
282                                    "failed");
283                         tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
284                         return -1;
285                 }
286                 out_pos += olen;
287                 if (out_pos > out_end) {
288                         wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
289                                    "for processing the received record");
290                         tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
291                                   TLS_ALERT_INTERNAL_ERROR);
292                         return -1;
293                 }
294
295                 pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
296         }
297
298         return out_pos - out_data;
299 }
300
301
302 /**
303  * tlsv1_client_global_init - Initialize TLSv1 client
304  * Returns: 0 on success, -1 on failure
305  *
306  * This function must be called before using any other TLSv1 client functions.
307  */
308 int tlsv1_client_global_init(void)
309 {
310         return crypto_global_init();
311 }
312
313
314 /**
315  * tlsv1_client_global_deinit - Deinitialize TLSv1 client
316  *
317  * This function can be used to deinitialize the TLSv1 client that was
318  * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
319  * can be called after this before calling tlsv1_client_global_init() again.
320  */
321 void tlsv1_client_global_deinit(void)
322 {
323         crypto_global_deinit();
324 }
325
326
327 /**
328  * tlsv1_client_init - Initialize TLSv1 client connection
329  * Returns: Pointer to TLSv1 client connection data or %NULL on failure
330  */
331 struct tlsv1_client * tlsv1_client_init(void)
332 {
333         struct tlsv1_client *conn;
334         size_t count;
335         u16 *suites;
336
337         conn = os_zalloc(sizeof(*conn));
338         if (conn == NULL)
339                 return NULL;
340
341         conn->state = CLIENT_HELLO;
342
343         if (tls_verify_hash_init(&conn->verify) < 0) {
344                 wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
345                            "hash");
346                 os_free(conn);
347                 return NULL;
348         }
349
350         count = 0;
351         suites = conn->cipher_suites;
352 #ifndef CONFIG_CRYPTO_INTERNAL
353         suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
354 #endif /* CONFIG_CRYPTO_INTERNAL */
355         suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
356         suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
357         suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
358         suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
359         conn->num_cipher_suites = count;
360
361         return conn;
362 }
363
364
365 /**
366  * tlsv1_client_deinit - Deinitialize TLSv1 client connection
367  * @conn: TLSv1 client connection data from tlsv1_client_init()
368  */
369 void tlsv1_client_deinit(struct tlsv1_client *conn)
370 {
371         crypto_public_key_free(conn->server_rsa_key);
372         tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
373         tlsv1_record_change_write_cipher(&conn->rl);
374         tlsv1_record_change_read_cipher(&conn->rl);
375         tls_verify_hash_free(&conn->verify);
376         os_free(conn->client_hello_ext);
377         tlsv1_client_free_dh(conn);
378         tlsv1_cred_free(conn->cred);
379         os_free(conn);
380 }
381
382
383 /**
384  * tlsv1_client_established - Check whether connection has been established
385  * @conn: TLSv1 client connection data from tlsv1_client_init()
386  * Returns: 1 if connection is established, 0 if not
387  */
388 int tlsv1_client_established(struct tlsv1_client *conn)
389 {
390         return conn->state == ESTABLISHED;
391 }
392
393
394 /**
395  * tlsv1_client_prf - Use TLS-PRF to derive keying material
396  * @conn: TLSv1 client connection data from tlsv1_client_init()
397  * @label: Label (e.g., description of the key) for PRF
398  * @server_random_first: seed is 0 = client_random|server_random,
399  * 1 = server_random|client_random
400  * @out: Buffer for output data from TLS-PRF
401  * @out_len: Length of the output buffer
402  * Returns: 0 on success, -1 on failure
403  */
404 int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
405                      int server_random_first, u8 *out, size_t out_len)
406 {
407         u8 seed[2 * TLS_RANDOM_LEN];
408
409         if (conn->state != ESTABLISHED)
410                 return -1;
411
412         if (server_random_first) {
413                 os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
414                 os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
415                           TLS_RANDOM_LEN);
416         } else {
417                 os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
418                 os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
419                           TLS_RANDOM_LEN);
420         }
421
422         return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
423                        label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
424 }
425
426
427 /**
428  * tlsv1_client_get_cipher - Get current cipher name
429  * @conn: TLSv1 client connection data from tlsv1_client_init()
430  * @buf: Buffer for the cipher name
431  * @buflen: buf size
432  * Returns: 0 on success, -1 on failure
433  *
434  * Get the name of the currently used cipher.
435  */
436 int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
437                             size_t buflen)
438 {
439         char *cipher;
440
441         switch (conn->rl.cipher_suite) {
442         case TLS_RSA_WITH_RC4_128_MD5:
443                 cipher = "RC4-MD5";
444                 break;
445         case TLS_RSA_WITH_RC4_128_SHA:
446                 cipher = "RC4-SHA";
447                 break;
448         case TLS_RSA_WITH_DES_CBC_SHA:
449                 cipher = "DES-CBC-SHA";
450                 break;
451         case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
452                 cipher = "DES-CBC3-SHA";
453                 break;
454         case TLS_DH_anon_WITH_AES_128_CBC_SHA:
455                 cipher = "ADH-AES-128-SHA";
456                 break;
457         case TLS_RSA_WITH_AES_256_CBC_SHA:
458                 cipher = "AES-256-SHA";
459                 break;
460         case TLS_RSA_WITH_AES_128_CBC_SHA:
461                 cipher = "AES-128-SHA";
462                 break;
463         default:
464                 return -1;
465         }
466
467         if (os_strlcpy(buf, cipher, buflen) >= buflen)
468                 return -1;
469         return 0;
470 }
471
472
473 /**
474  * tlsv1_client_shutdown - Shutdown TLS connection
475  * @conn: TLSv1 client connection data from tlsv1_client_init()
476  * Returns: 0 on success, -1 on failure
477  */
478 int tlsv1_client_shutdown(struct tlsv1_client *conn)
479 {
480         conn->state = CLIENT_HELLO;
481
482         if (tls_verify_hash_init(&conn->verify) < 0) {
483                 wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
484                            "hash");
485                 return -1;
486         }
487
488         tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
489         tlsv1_record_change_write_cipher(&conn->rl);
490         tlsv1_record_change_read_cipher(&conn->rl);
491
492         conn->certificate_requested = 0;
493         crypto_public_key_free(conn->server_rsa_key);
494         conn->server_rsa_key = NULL;
495         conn->session_resumed = 0;
496
497         return 0;
498 }
499
500
501 /**
502  * tlsv1_client_resumed - Was session resumption used
503  * @conn: TLSv1 client connection data from tlsv1_client_init()
504  * Returns: 1 if current session used session resumption, 0 if not
505  */
506 int tlsv1_client_resumed(struct tlsv1_client *conn)
507 {
508         return !!conn->session_resumed;
509 }
510
511
512 /**
513  * tlsv1_client_hello_ext - Set TLS extension for ClientHello
514  * @conn: TLSv1 client connection data from tlsv1_client_init()
515  * @ext_type: Extension type
516  * @data: Extension payload (%NULL to remove extension)
517  * @data_len: Extension payload length
518  * Returns: 0 on success, -1 on failure
519  */
520 int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
521                            const u8 *data, size_t data_len)
522 {
523         u8 *pos;
524
525         conn->session_ticket_included = 0;
526         os_free(conn->client_hello_ext);
527         conn->client_hello_ext = NULL;
528         conn->client_hello_ext_len = 0;
529
530         if (data == NULL || data_len == 0)
531                 return 0;
532
533         pos = conn->client_hello_ext = os_malloc(6 + data_len);
534         if (pos == NULL)
535                 return -1;
536
537         WPA_PUT_BE16(pos, 4 + data_len);
538         pos += 2;
539         WPA_PUT_BE16(pos, ext_type);
540         pos += 2;
541         WPA_PUT_BE16(pos, data_len);
542         pos += 2;
543         os_memcpy(pos, data, data_len);
544         conn->client_hello_ext_len = 6 + data_len;
545
546         if (ext_type == TLS_EXT_PAC_OPAQUE) {
547                 conn->session_ticket_included = 1;
548                 wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
549         }
550
551         return 0;
552 }
553
554
555 /**
556  * tlsv1_client_get_keys - Get master key and random data from TLS connection
557  * @conn: TLSv1 client connection data from tlsv1_client_init()
558  * @keys: Structure of key/random data (filled on success)
559  * Returns: 0 on success, -1 on failure
560  */
561 int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
562 {
563         os_memset(keys, 0, sizeof(*keys));
564         if (conn->state == CLIENT_HELLO)
565                 return -1;
566
567         keys->client_random = conn->client_random;
568         keys->client_random_len = TLS_RANDOM_LEN;
569
570         if (conn->state != SERVER_HELLO) {
571                 keys->server_random = conn->server_random;
572                 keys->server_random_len = TLS_RANDOM_LEN;
573                 keys->master_key = conn->master_secret;
574                 keys->master_key_len = TLS_MASTER_SECRET_LEN;
575         }
576
577         return 0;
578 }
579
580
581 /**
582  * tlsv1_client_get_keyblock_size - Get TLS key_block size
583  * @conn: TLSv1 client connection data from tlsv1_client_init()
584  * Returns: Size of the key_block for the negotiated cipher suite or -1 on
585  * failure
586  */
587 int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
588 {
589         if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
590                 return -1;
591
592         return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
593                     conn->rl.iv_size);
594 }
595
596
597 /**
598  * tlsv1_client_set_cipher_list - Configure acceptable cipher suites
599  * @conn: TLSv1 client connection data from tlsv1_client_init()
600  * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
601  * (TLS_CIPHER_*).
602  * Returns: 0 on success, -1 on failure
603  */
604 int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
605 {
606 #ifdef EAP_FAST
607         size_t count;
608         u16 *suites;
609
610         /* TODO: implement proper configuration of cipher suites */
611         if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
612                 count = 0;
613                 suites = conn->cipher_suites;
614 #ifndef CONFIG_CRYPTO_INTERNAL
615                 suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
616 #endif /* CONFIG_CRYPTO_INTERNAL */
617                 suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
618                 suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
619                 suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
620                 suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
621                 conn->num_cipher_suites = count;
622         }
623
624         return 0;
625 #else /* EAP_FAST */
626         return -1;
627 #endif /* EAP_FAST */
628 }
629
630
631 /**
632  * tlsv1_client_set_cred - Set client credentials
633  * @conn: TLSv1 client connection data from tlsv1_client_init()
634  * @cred: Credentials from tlsv1_cred_alloc()
635  * Returns: 0 on success, -1 on failure
636  *
637  * On success, the client takes ownership of the credentials block and caller
638  * must not free it. On failure, caller is responsible for freeing the
639  * credential block.
640  */
641 int tlsv1_client_set_cred(struct tlsv1_client *conn,
642                           struct tlsv1_credentials *cred)
643 {
644         tlsv1_cred_free(conn->cred);
645         conn->cred = cred;
646         return 0;
647 }
648
649
650 void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
651                                         tlsv1_client_session_ticket_cb cb,
652                                         void *ctx)
653 {
654         wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
655                    cb, ctx);
656         conn->session_ticket_cb = cb;
657         conn->session_ticket_cb_ctx = ctx;
658 }