18dbcf02cSchristos /*
28dbcf02cSchristos * TLS interface functions and an internal TLS implementation
3*0d69f216Schristos * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
48dbcf02cSchristos *
562a52023Schristos * This software may be distributed under the terms of the BSD license.
662a52023Schristos * See README for more details.
78dbcf02cSchristos *
88dbcf02cSchristos * This file interface functions for hostapd/wpa_supplicant to use the
98dbcf02cSchristos * integrated TLSv1 implementation.
108dbcf02cSchristos */
118dbcf02cSchristos
128dbcf02cSchristos #include "includes.h"
138dbcf02cSchristos
148dbcf02cSchristos #include "common.h"
158dbcf02cSchristos #include "tls.h"
168dbcf02cSchristos #include "tls/tlsv1_client.h"
178dbcf02cSchristos #include "tls/tlsv1_server.h"
188dbcf02cSchristos
198dbcf02cSchristos
208dbcf02cSchristos static int tls_ref_count = 0;
218dbcf02cSchristos
228dbcf02cSchristos struct tls_global {
238dbcf02cSchristos int server;
248dbcf02cSchristos struct tlsv1_credentials *server_cred;
258dbcf02cSchristos int check_crl;
26928750b6Schristos
27928750b6Schristos void (*event_cb)(void *ctx, enum tls_event ev,
28928750b6Schristos union tls_event_data *data);
29928750b6Schristos void *cb_ctx;
30928750b6Schristos int cert_in_cb;
318dbcf02cSchristos };
328dbcf02cSchristos
338dbcf02cSchristos struct tls_connection {
348dbcf02cSchristos struct tlsv1_client *client;
358dbcf02cSchristos struct tlsv1_server *server;
3636d97821Schristos struct tls_global *global;
378dbcf02cSchristos };
388dbcf02cSchristos
398dbcf02cSchristos
tls_init(const struct tls_config * conf)408dbcf02cSchristos void * tls_init(const struct tls_config *conf)
418dbcf02cSchristos {
428dbcf02cSchristos struct tls_global *global;
438dbcf02cSchristos
448dbcf02cSchristos if (tls_ref_count == 0) {
458dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
468dbcf02cSchristos if (tlsv1_client_global_init())
478dbcf02cSchristos return NULL;
488dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
498dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
508dbcf02cSchristos if (tlsv1_server_global_init())
518dbcf02cSchristos return NULL;
528dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
538dbcf02cSchristos }
548dbcf02cSchristos tls_ref_count++;
558dbcf02cSchristos
568dbcf02cSchristos global = os_zalloc(sizeof(*global));
578dbcf02cSchristos if (global == NULL)
588dbcf02cSchristos return NULL;
59928750b6Schristos if (conf) {
60928750b6Schristos global->event_cb = conf->event_cb;
61928750b6Schristos global->cb_ctx = conf->cb_ctx;
62928750b6Schristos global->cert_in_cb = conf->cert_in_cb;
63928750b6Schristos }
648dbcf02cSchristos
658dbcf02cSchristos return global;
668dbcf02cSchristos }
678dbcf02cSchristos
tls_deinit(void * ssl_ctx)688dbcf02cSchristos void tls_deinit(void *ssl_ctx)
698dbcf02cSchristos {
708dbcf02cSchristos struct tls_global *global = ssl_ctx;
718dbcf02cSchristos tls_ref_count--;
728dbcf02cSchristos if (tls_ref_count == 0) {
738dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
748dbcf02cSchristos tlsv1_client_global_deinit();
758dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
768dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
778dbcf02cSchristos tlsv1_server_global_deinit();
788dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
798dbcf02cSchristos }
80928750b6Schristos #ifdef CONFIG_TLS_INTERNAL_SERVER
81928750b6Schristos tlsv1_cred_free(global->server_cred);
82928750b6Schristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
838dbcf02cSchristos os_free(global);
848dbcf02cSchristos }
858dbcf02cSchristos
868dbcf02cSchristos
tls_get_errors(void * tls_ctx)878dbcf02cSchristos int tls_get_errors(void *tls_ctx)
888dbcf02cSchristos {
898dbcf02cSchristos return 0;
908dbcf02cSchristos }
918dbcf02cSchristos
928dbcf02cSchristos
tls_connection_init(void * tls_ctx)938dbcf02cSchristos struct tls_connection * tls_connection_init(void *tls_ctx)
948dbcf02cSchristos {
958dbcf02cSchristos struct tls_connection *conn;
968dbcf02cSchristos struct tls_global *global = tls_ctx;
978dbcf02cSchristos
988dbcf02cSchristos conn = os_zalloc(sizeof(*conn));
998dbcf02cSchristos if (conn == NULL)
1008dbcf02cSchristos return NULL;
10136d97821Schristos conn->global = global;
1028dbcf02cSchristos
1038dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
1048dbcf02cSchristos if (!global->server) {
1058dbcf02cSchristos conn->client = tlsv1_client_init();
1068dbcf02cSchristos if (conn->client == NULL) {
1078dbcf02cSchristos os_free(conn);
1088dbcf02cSchristos return NULL;
1098dbcf02cSchristos }
110928750b6Schristos tlsv1_client_set_cb(conn->client, global->event_cb,
111928750b6Schristos global->cb_ctx, global->cert_in_cb);
1128dbcf02cSchristos }
1138dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
1148dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
1158dbcf02cSchristos if (global->server) {
1168dbcf02cSchristos conn->server = tlsv1_server_init(global->server_cred);
1178dbcf02cSchristos if (conn->server == NULL) {
1188dbcf02cSchristos os_free(conn);
1198dbcf02cSchristos return NULL;
1208dbcf02cSchristos }
1218dbcf02cSchristos }
1228dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
1238dbcf02cSchristos
1248dbcf02cSchristos return conn;
1258dbcf02cSchristos }
1268dbcf02cSchristos
1278dbcf02cSchristos
12836d97821Schristos #ifdef CONFIG_TESTING_OPTIONS
12936d97821Schristos #ifdef CONFIG_TLS_INTERNAL_SERVER
tls_connection_set_test_flags(struct tls_connection * conn,u32 flags)13036d97821Schristos void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags)
13136d97821Schristos {
13236d97821Schristos if (conn->server)
13336d97821Schristos tlsv1_server_set_test_flags(conn->server, flags);
13436d97821Schristos }
13536d97821Schristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
13636d97821Schristos #endif /* CONFIG_TESTING_OPTIONS */
13736d97821Schristos
13836d97821Schristos
tls_connection_set_log_cb(struct tls_connection * conn,void (* log_cb)(void * ctx,const char * msg),void * ctx)13936d97821Schristos void tls_connection_set_log_cb(struct tls_connection *conn,
14036d97821Schristos void (*log_cb)(void *ctx, const char *msg),
14136d97821Schristos void *ctx)
14236d97821Schristos {
14336d97821Schristos #ifdef CONFIG_TLS_INTERNAL_SERVER
14436d97821Schristos if (conn->server)
14536d97821Schristos tlsv1_server_set_log_cb(conn->server, log_cb, ctx);
14636d97821Schristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
14736d97821Schristos }
14836d97821Schristos
14936d97821Schristos
tls_connection_deinit(void * tls_ctx,struct tls_connection * conn)1508dbcf02cSchristos void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
1518dbcf02cSchristos {
1528dbcf02cSchristos if (conn == NULL)
1538dbcf02cSchristos return;
1548dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
1558dbcf02cSchristos if (conn->client)
1568dbcf02cSchristos tlsv1_client_deinit(conn->client);
1578dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
1588dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
1598dbcf02cSchristos if (conn->server)
1608dbcf02cSchristos tlsv1_server_deinit(conn->server);
1618dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
1628dbcf02cSchristos os_free(conn);
1638dbcf02cSchristos }
1648dbcf02cSchristos
1658dbcf02cSchristos
tls_connection_established(void * tls_ctx,struct tls_connection * conn)1668dbcf02cSchristos int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
1678dbcf02cSchristos {
1688dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
1698dbcf02cSchristos if (conn->client)
1708dbcf02cSchristos return tlsv1_client_established(conn->client);
1718dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
1728dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
1738dbcf02cSchristos if (conn->server)
1748dbcf02cSchristos return tlsv1_server_established(conn->server);
1758dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
1768dbcf02cSchristos return 0;
1778dbcf02cSchristos }
1788dbcf02cSchristos
1798dbcf02cSchristos
tls_connection_peer_serial_num(void * tls_ctx,struct tls_connection * conn)180ebb5671cSchristos char * tls_connection_peer_serial_num(void *tls_ctx,
181ebb5671cSchristos struct tls_connection *conn)
182ebb5671cSchristos {
183ebb5671cSchristos /* TODO */
184ebb5671cSchristos return NULL;
185ebb5671cSchristos }
186ebb5671cSchristos
187ebb5671cSchristos
tls_connection_shutdown(void * tls_ctx,struct tls_connection * conn)1888dbcf02cSchristos int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
1898dbcf02cSchristos {
1908dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
1918dbcf02cSchristos if (conn->client)
1928dbcf02cSchristos return tlsv1_client_shutdown(conn->client);
1938dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
1948dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
1958dbcf02cSchristos if (conn->server)
1968dbcf02cSchristos return tlsv1_server_shutdown(conn->server);
1978dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
1988dbcf02cSchristos return -1;
1998dbcf02cSchristos }
2008dbcf02cSchristos
2018dbcf02cSchristos
tls_connection_set_params(void * tls_ctx,struct tls_connection * conn,const struct tls_connection_params * params)2028dbcf02cSchristos int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
2038dbcf02cSchristos const struct tls_connection_params *params)
2048dbcf02cSchristos {
2058dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
2068dbcf02cSchristos struct tlsv1_credentials *cred;
2078dbcf02cSchristos
2088dbcf02cSchristos if (conn->client == NULL)
2098dbcf02cSchristos return -1;
2108dbcf02cSchristos
211928750b6Schristos if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
212928750b6Schristos wpa_printf(MSG_INFO,
213928750b6Schristos "TLS: tls_ext_cert_check=1 not supported");
214928750b6Schristos return -1;
215928750b6Schristos }
216928750b6Schristos
2178dbcf02cSchristos cred = tlsv1_cred_alloc();
2188dbcf02cSchristos if (cred == NULL)
2198dbcf02cSchristos return -1;
2208dbcf02cSchristos
2219a53cbbeSchristos if (params->subject_match) {
2229a53cbbeSchristos wpa_printf(MSG_INFO, "TLS: subject_match not supported");
223928750b6Schristos tlsv1_cred_free(cred);
2249a53cbbeSchristos return -1;
2259a53cbbeSchristos }
2269a53cbbeSchristos
2279a53cbbeSchristos if (params->altsubject_match) {
2289a53cbbeSchristos wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
229928750b6Schristos tlsv1_cred_free(cred);
2309a53cbbeSchristos return -1;
2319a53cbbeSchristos }
2329a53cbbeSchristos
2339a53cbbeSchristos if (params->suffix_match) {
2349a53cbbeSchristos wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
235928750b6Schristos tlsv1_cred_free(cred);
2369a53cbbeSchristos return -1;
2379a53cbbeSchristos }
2389a53cbbeSchristos
2399a53cbbeSchristos if (params->domain_match) {
2409a53cbbeSchristos wpa_printf(MSG_INFO, "TLS: domain_match not supported");
241928750b6Schristos tlsv1_cred_free(cred);
2429a53cbbeSchristos return -1;
2439a53cbbeSchristos }
2449a53cbbeSchristos
2459a53cbbeSchristos if (params->openssl_ciphers) {
246928750b6Schristos wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported");
247928750b6Schristos tlsv1_cred_free(cred);
2489a53cbbeSchristos return -1;
2499a53cbbeSchristos }
2509a53cbbeSchristos
251*0d69f216Schristos if (params->openssl_ecdh_curves) {
252*0d69f216Schristos wpa_printf(MSG_INFO, "TLS: openssl_ecdh_curves not supported");
253*0d69f216Schristos tlsv1_cred_free(cred);
254*0d69f216Schristos return -1;
255*0d69f216Schristos }
256*0d69f216Schristos
2578dbcf02cSchristos if (tlsv1_set_ca_cert(cred, params->ca_cert,
2588dbcf02cSchristos params->ca_cert_blob, params->ca_cert_blob_len,
2598dbcf02cSchristos params->ca_path)) {
2608dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
2618dbcf02cSchristos "certificates");
2628dbcf02cSchristos tlsv1_cred_free(cred);
2638dbcf02cSchristos return -1;
2648dbcf02cSchristos }
2658dbcf02cSchristos
2668dbcf02cSchristos if (tlsv1_set_cert(cred, params->client_cert,
2678dbcf02cSchristos params->client_cert_blob,
2688dbcf02cSchristos params->client_cert_blob_len)) {
2698dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to configure client "
2708dbcf02cSchristos "certificate");
2718dbcf02cSchristos tlsv1_cred_free(cred);
2728dbcf02cSchristos return -1;
2738dbcf02cSchristos }
2748dbcf02cSchristos
2758dbcf02cSchristos if (tlsv1_set_private_key(cred, params->private_key,
2768dbcf02cSchristos params->private_key_passwd,
2778dbcf02cSchristos params->private_key_blob,
2788dbcf02cSchristos params->private_key_blob_len)) {
2798dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to load private key");
2808dbcf02cSchristos tlsv1_cred_free(cred);
2818dbcf02cSchristos return -1;
2828dbcf02cSchristos }
2838dbcf02cSchristos
2848dbcf02cSchristos if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
2858dbcf02cSchristos params->dh_blob_len)) {
2868dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
2878dbcf02cSchristos tlsv1_cred_free(cred);
2888dbcf02cSchristos return -1;
2898dbcf02cSchristos }
2908dbcf02cSchristos
2918dbcf02cSchristos if (tlsv1_client_set_cred(conn->client, cred) < 0) {
2928dbcf02cSchristos tlsv1_cred_free(cred);
2938dbcf02cSchristos return -1;
2948dbcf02cSchristos }
2958dbcf02cSchristos
296928750b6Schristos tlsv1_client_set_flags(conn->client, params->flags);
29742669be3Schristos
2988dbcf02cSchristos return 0;
2998dbcf02cSchristos #else /* CONFIG_TLS_INTERNAL_CLIENT */
3008dbcf02cSchristos return -1;
3018dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
3028dbcf02cSchristos }
3038dbcf02cSchristos
3048dbcf02cSchristos
tls_global_set_params(void * tls_ctx,const struct tls_connection_params * params)3058dbcf02cSchristos int tls_global_set_params(void *tls_ctx,
3068dbcf02cSchristos const struct tls_connection_params *params)
3078dbcf02cSchristos {
3088dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
3098dbcf02cSchristos struct tls_global *global = tls_ctx;
3108dbcf02cSchristos struct tlsv1_credentials *cred;
3118dbcf02cSchristos
312*0d69f216Schristos if (params->check_cert_subject)
313*0d69f216Schristos return -1; /* not yet supported */
314*0d69f216Schristos
3158dbcf02cSchristos /* Currently, global parameters are only set when running in server
3168dbcf02cSchristos * mode. */
3178dbcf02cSchristos global->server = 1;
3188dbcf02cSchristos tlsv1_cred_free(global->server_cred);
3198dbcf02cSchristos global->server_cred = cred = tlsv1_cred_alloc();
3208dbcf02cSchristos if (cred == NULL)
3218dbcf02cSchristos return -1;
3228dbcf02cSchristos
3238dbcf02cSchristos if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
3248dbcf02cSchristos params->ca_cert_blob_len, params->ca_path)) {
3258dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
3268dbcf02cSchristos "certificates");
3278dbcf02cSchristos return -1;
3288dbcf02cSchristos }
3298dbcf02cSchristos
3308dbcf02cSchristos if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
3318dbcf02cSchristos params->client_cert_blob_len)) {
3328dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to configure server "
3338dbcf02cSchristos "certificate");
3348dbcf02cSchristos return -1;
3358dbcf02cSchristos }
3368dbcf02cSchristos
3378dbcf02cSchristos if (tlsv1_set_private_key(cred, params->private_key,
3388dbcf02cSchristos params->private_key_passwd,
3398dbcf02cSchristos params->private_key_blob,
3408dbcf02cSchristos params->private_key_blob_len)) {
3418dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to load private key");
3428dbcf02cSchristos return -1;
3438dbcf02cSchristos }
3448dbcf02cSchristos
3458dbcf02cSchristos if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
3468dbcf02cSchristos params->dh_blob_len)) {
3478dbcf02cSchristos wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
3488dbcf02cSchristos return -1;
3498dbcf02cSchristos }
3508dbcf02cSchristos
351928750b6Schristos if (params->ocsp_stapling_response)
352928750b6Schristos cred->ocsp_stapling_response =
353928750b6Schristos os_strdup(params->ocsp_stapling_response);
354928750b6Schristos if (params->ocsp_stapling_response_multi)
355928750b6Schristos cred->ocsp_stapling_response_multi =
356928750b6Schristos os_strdup(params->ocsp_stapling_response_multi);
357928750b6Schristos
3588dbcf02cSchristos return 0;
3598dbcf02cSchristos #else /* CONFIG_TLS_INTERNAL_SERVER */
3608dbcf02cSchristos return -1;
3618dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
3628dbcf02cSchristos }
3638dbcf02cSchristos
3648dbcf02cSchristos
tls_global_set_verify(void * tls_ctx,int check_crl,int strict)365*0d69f216Schristos int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
3668dbcf02cSchristos {
3678dbcf02cSchristos struct tls_global *global = tls_ctx;
3688dbcf02cSchristos global->check_crl = check_crl;
3698dbcf02cSchristos return 0;
3708dbcf02cSchristos }
3718dbcf02cSchristos
3728dbcf02cSchristos
tls_connection_set_verify(void * tls_ctx,struct tls_connection * conn,int verify_peer,unsigned int flags,const u8 * session_ctx,size_t session_ctx_len)3738dbcf02cSchristos int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
374928750b6Schristos int verify_peer, unsigned int flags,
375928750b6Schristos const u8 *session_ctx, size_t session_ctx_len)
3768dbcf02cSchristos {
3778dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
3788dbcf02cSchristos if (conn->server)
3798dbcf02cSchristos return tlsv1_server_set_verify(conn->server, verify_peer);
3808dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
3818dbcf02cSchristos return -1;
3828dbcf02cSchristos }
3838dbcf02cSchristos
3848dbcf02cSchristos
tls_connection_get_random(void * tls_ctx,struct tls_connection * conn,struct tls_random * data)385928750b6Schristos int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
386928750b6Schristos struct tls_random *data)
3878dbcf02cSchristos {
3888dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
3898dbcf02cSchristos if (conn->client)
390928750b6Schristos return tlsv1_client_get_random(conn->client, data);
3918dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
3928dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
3938dbcf02cSchristos if (conn->server)
394928750b6Schristos return tlsv1_server_get_random(conn->server, data);
3958dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
3968dbcf02cSchristos return -1;
3978dbcf02cSchristos }
3988dbcf02cSchristos
3998dbcf02cSchristos
tls_get_keyblock_size(struct tls_connection * conn)400928750b6Schristos static int tls_get_keyblock_size(struct tls_connection *conn)
4018dbcf02cSchristos {
4028dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
403928750b6Schristos if (conn->client)
404928750b6Schristos return tlsv1_client_get_keyblock_size(conn->client);
405928750b6Schristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
406928750b6Schristos #ifdef CONFIG_TLS_INTERNAL_SERVER
407928750b6Schristos if (conn->server)
408928750b6Schristos return tlsv1_server_get_keyblock_size(conn->server);
409928750b6Schristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
410928750b6Schristos return -1;
411928750b6Schristos }
412928750b6Schristos
413928750b6Schristos
tls_connection_prf(void * tls_ctx,struct tls_connection * conn,const char * label,const u8 * context,size_t context_len,int server_random_first,int skip_keyblock,u8 * out,size_t out_len)414928750b6Schristos static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
415*0d69f216Schristos const char *label, const u8 *context,
416*0d69f216Schristos size_t context_len, int server_random_first,
417928750b6Schristos int skip_keyblock, u8 *out, size_t out_len)
418928750b6Schristos {
419928750b6Schristos int ret = -1, skip = 0;
420928750b6Schristos u8 *tmp_out = NULL;
421928750b6Schristos u8 *_out = out;
422928750b6Schristos
423928750b6Schristos if (skip_keyblock) {
424928750b6Schristos skip = tls_get_keyblock_size(conn);
425928750b6Schristos if (skip < 0)
426928750b6Schristos return -1;
427928750b6Schristos tmp_out = os_malloc(skip + out_len);
428928750b6Schristos if (!tmp_out)
429928750b6Schristos return -1;
430928750b6Schristos _out = tmp_out;
431928750b6Schristos }
432928750b6Schristos
433928750b6Schristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
4348dbcf02cSchristos if (conn->client) {
435*0d69f216Schristos ret = tlsv1_client_prf(conn->client, label, context,
436*0d69f216Schristos context_len, server_random_first,
437928750b6Schristos _out, skip + out_len);
4388dbcf02cSchristos }
4398dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
4408dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
4418dbcf02cSchristos if (conn->server) {
442*0d69f216Schristos ret = tlsv1_server_prf(conn->server, label, context,
443*0d69f216Schristos context_len, server_random_first,
444928750b6Schristos _out, skip + out_len);
4458dbcf02cSchristos }
4468dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
447928750b6Schristos if (ret == 0 && skip_keyblock)
448928750b6Schristos os_memcpy(out, _out + skip, out_len);
449928750b6Schristos bin_clear_free(tmp_out, skip);
450928750b6Schristos
451928750b6Schristos return ret;
452928750b6Schristos }
453928750b6Schristos
454928750b6Schristos
tls_connection_export_key(void * tls_ctx,struct tls_connection * conn,const char * label,const u8 * context,size_t context_len,u8 * out,size_t out_len)455928750b6Schristos int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
456*0d69f216Schristos const char *label, const u8 *context,
457*0d69f216Schristos size_t context_len, u8 *out, size_t out_len)
458928750b6Schristos {
459*0d69f216Schristos return tls_connection_prf(tls_ctx, conn, label, context, context_len,
460*0d69f216Schristos 0, 0, out, out_len);
461928750b6Schristos }
462928750b6Schristos
463928750b6Schristos
tls_connection_get_eap_fast_key(void * tls_ctx,struct tls_connection * conn,u8 * out,size_t out_len)464928750b6Schristos int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
465928750b6Schristos u8 *out, size_t out_len)
466928750b6Schristos {
467*0d69f216Schristos return tls_connection_prf(tls_ctx, conn, "key expansion", NULL, 0,
468*0d69f216Schristos 1, 1, out, out_len);
4698dbcf02cSchristos }
4708dbcf02cSchristos
4718dbcf02cSchristos
tls_connection_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)4728dbcf02cSchristos struct wpabuf * tls_connection_handshake(void *tls_ctx,
4738dbcf02cSchristos struct tls_connection *conn,
4748dbcf02cSchristos const struct wpabuf *in_data,
4758dbcf02cSchristos struct wpabuf **appl_data)
4768dbcf02cSchristos {
47762a52023Schristos return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
47862a52023Schristos NULL);
47962a52023Schristos }
48062a52023Schristos
48162a52023Schristos
tls_connection_handshake2(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data,int * need_more_data)48262a52023Schristos struct wpabuf * tls_connection_handshake2(void *tls_ctx,
48362a52023Schristos struct tls_connection *conn,
48462a52023Schristos const struct wpabuf *in_data,
48562a52023Schristos struct wpabuf **appl_data,
48662a52023Schristos int *need_more_data)
48762a52023Schristos {
4888dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
4898dbcf02cSchristos u8 *res, *ad;
4908dbcf02cSchristos size_t res_len, ad_len;
4918dbcf02cSchristos struct wpabuf *out;
4928dbcf02cSchristos
4938dbcf02cSchristos if (conn->client == NULL)
4948dbcf02cSchristos return NULL;
4958dbcf02cSchristos
4968dbcf02cSchristos ad = NULL;
4978dbcf02cSchristos res = tlsv1_client_handshake(conn->client,
4988dbcf02cSchristos in_data ? wpabuf_head(in_data) : NULL,
4998dbcf02cSchristos in_data ? wpabuf_len(in_data) : 0,
50062a52023Schristos &res_len, &ad, &ad_len, need_more_data);
5018dbcf02cSchristos if (res == NULL)
5028dbcf02cSchristos return NULL;
5038dbcf02cSchristos out = wpabuf_alloc_ext_data(res, res_len);
5048dbcf02cSchristos if (out == NULL) {
5058dbcf02cSchristos os_free(res);
5068dbcf02cSchristos os_free(ad);
5078dbcf02cSchristos return NULL;
5088dbcf02cSchristos }
5098dbcf02cSchristos if (appl_data) {
5108dbcf02cSchristos if (ad) {
5118dbcf02cSchristos *appl_data = wpabuf_alloc_ext_data(ad, ad_len);
5128dbcf02cSchristos if (*appl_data == NULL)
5138dbcf02cSchristos os_free(ad);
5148dbcf02cSchristos } else
5158dbcf02cSchristos *appl_data = NULL;
5168dbcf02cSchristos } else
5178dbcf02cSchristos os_free(ad);
5188dbcf02cSchristos
5198dbcf02cSchristos return out;
5208dbcf02cSchristos #else /* CONFIG_TLS_INTERNAL_CLIENT */
5218dbcf02cSchristos return NULL;
5228dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
5238dbcf02cSchristos }
5248dbcf02cSchristos
5258dbcf02cSchristos
tls_connection_server_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)5268dbcf02cSchristos struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
5278dbcf02cSchristos struct tls_connection *conn,
5288dbcf02cSchristos const struct wpabuf *in_data,
5298dbcf02cSchristos struct wpabuf **appl_data)
5308dbcf02cSchristos {
5318dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
5328dbcf02cSchristos u8 *res;
5338dbcf02cSchristos size_t res_len;
5348dbcf02cSchristos struct wpabuf *out;
5358dbcf02cSchristos
5368dbcf02cSchristos if (conn->server == NULL)
5378dbcf02cSchristos return NULL;
5388dbcf02cSchristos
5398dbcf02cSchristos if (appl_data)
5408dbcf02cSchristos *appl_data = NULL;
5418dbcf02cSchristos
5428dbcf02cSchristos res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data),
5438dbcf02cSchristos wpabuf_len(in_data), &res_len);
5448dbcf02cSchristos if (res == NULL && tlsv1_server_established(conn->server))
5458dbcf02cSchristos return wpabuf_alloc(0);
5468dbcf02cSchristos if (res == NULL)
5478dbcf02cSchristos return NULL;
5488dbcf02cSchristos out = wpabuf_alloc_ext_data(res, res_len);
5498dbcf02cSchristos if (out == NULL) {
5508dbcf02cSchristos os_free(res);
5518dbcf02cSchristos return NULL;
5528dbcf02cSchristos }
5538dbcf02cSchristos
5548dbcf02cSchristos return out;
5558dbcf02cSchristos #else /* CONFIG_TLS_INTERNAL_SERVER */
5568dbcf02cSchristos return NULL;
5578dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
5588dbcf02cSchristos }
5598dbcf02cSchristos
5608dbcf02cSchristos
tls_connection_encrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)5618dbcf02cSchristos struct wpabuf * tls_connection_encrypt(void *tls_ctx,
5628dbcf02cSchristos struct tls_connection *conn,
5638dbcf02cSchristos const struct wpabuf *in_data)
5648dbcf02cSchristos {
5658dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
5668dbcf02cSchristos if (conn->client) {
5678dbcf02cSchristos struct wpabuf *buf;
5688dbcf02cSchristos int res;
5698dbcf02cSchristos buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
5708dbcf02cSchristos if (buf == NULL)
5718dbcf02cSchristos return NULL;
5728dbcf02cSchristos res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data),
5738dbcf02cSchristos wpabuf_len(in_data),
5748dbcf02cSchristos wpabuf_mhead(buf),
5758dbcf02cSchristos wpabuf_size(buf));
5768dbcf02cSchristos if (res < 0) {
5778dbcf02cSchristos wpabuf_free(buf);
5788dbcf02cSchristos return NULL;
5798dbcf02cSchristos }
5808dbcf02cSchristos wpabuf_put(buf, res);
5818dbcf02cSchristos return buf;
5828dbcf02cSchristos }
5838dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
5848dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
5858dbcf02cSchristos if (conn->server) {
5868dbcf02cSchristos struct wpabuf *buf;
5878dbcf02cSchristos int res;
5888dbcf02cSchristos buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
5898dbcf02cSchristos if (buf == NULL)
5908dbcf02cSchristos return NULL;
5918dbcf02cSchristos res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data),
5928dbcf02cSchristos wpabuf_len(in_data),
5938dbcf02cSchristos wpabuf_mhead(buf),
5948dbcf02cSchristos wpabuf_size(buf));
5958dbcf02cSchristos if (res < 0) {
5968dbcf02cSchristos wpabuf_free(buf);
5978dbcf02cSchristos return NULL;
5988dbcf02cSchristos }
5998dbcf02cSchristos wpabuf_put(buf, res);
6008dbcf02cSchristos return buf;
6018dbcf02cSchristos }
6028dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
6038dbcf02cSchristos return NULL;
6048dbcf02cSchristos }
6058dbcf02cSchristos
6068dbcf02cSchristos
tls_connection_decrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)6078dbcf02cSchristos struct wpabuf * tls_connection_decrypt(void *tls_ctx,
6088dbcf02cSchristos struct tls_connection *conn,
6098dbcf02cSchristos const struct wpabuf *in_data)
6108dbcf02cSchristos {
61162a52023Schristos return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
61262a52023Schristos }
61362a52023Schristos
61462a52023Schristos
tls_connection_decrypt2(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,int * need_more_data)61562a52023Schristos struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
61662a52023Schristos struct tls_connection *conn,
61762a52023Schristos const struct wpabuf *in_data,
61862a52023Schristos int *need_more_data)
61962a52023Schristos {
62062a52023Schristos if (need_more_data)
62162a52023Schristos *need_more_data = 0;
62262a52023Schristos
6238dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
6248dbcf02cSchristos if (conn->client) {
62562a52023Schristos return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
6268dbcf02cSchristos wpabuf_len(in_data),
62762a52023Schristos need_more_data);
6288dbcf02cSchristos }
6298dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
6308dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
6318dbcf02cSchristos if (conn->server) {
6328dbcf02cSchristos struct wpabuf *buf;
6338dbcf02cSchristos int res;
6348dbcf02cSchristos buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
6358dbcf02cSchristos if (buf == NULL)
6368dbcf02cSchristos return NULL;
6378dbcf02cSchristos res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data),
6388dbcf02cSchristos wpabuf_len(in_data),
6398dbcf02cSchristos wpabuf_mhead(buf),
6408dbcf02cSchristos wpabuf_size(buf));
6418dbcf02cSchristos if (res < 0) {
6428dbcf02cSchristos wpabuf_free(buf);
6438dbcf02cSchristos return NULL;
6448dbcf02cSchristos }
6458dbcf02cSchristos wpabuf_put(buf, res);
6468dbcf02cSchristos return buf;
6478dbcf02cSchristos }
6488dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
6498dbcf02cSchristos return NULL;
6508dbcf02cSchristos }
6518dbcf02cSchristos
6528dbcf02cSchristos
tls_connection_resumed(void * tls_ctx,struct tls_connection * conn)6538dbcf02cSchristos int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
6548dbcf02cSchristos {
6558dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
6568dbcf02cSchristos if (conn->client)
6578dbcf02cSchristos return tlsv1_client_resumed(conn->client);
6588dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
6598dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
6608dbcf02cSchristos if (conn->server)
6618dbcf02cSchristos return tlsv1_server_resumed(conn->server);
6628dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
6638dbcf02cSchristos return -1;
6648dbcf02cSchristos }
6658dbcf02cSchristos
6668dbcf02cSchristos
tls_connection_set_cipher_list(void * tls_ctx,struct tls_connection * conn,u8 * ciphers)6678dbcf02cSchristos int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
6688dbcf02cSchristos u8 *ciphers)
6698dbcf02cSchristos {
6708dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
6718dbcf02cSchristos if (conn->client)
6728dbcf02cSchristos return tlsv1_client_set_cipher_list(conn->client, ciphers);
6738dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
6748dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
6758dbcf02cSchristos if (conn->server)
6768dbcf02cSchristos return tlsv1_server_set_cipher_list(conn->server, ciphers);
6778dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
6788dbcf02cSchristos return -1;
6798dbcf02cSchristos }
6808dbcf02cSchristos
6818dbcf02cSchristos
tls_get_version(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)682928750b6Schristos int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
683928750b6Schristos char *buf, size_t buflen)
684928750b6Schristos {
685928750b6Schristos if (conn == NULL)
686928750b6Schristos return -1;
687928750b6Schristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
688928750b6Schristos if (conn->client)
689928750b6Schristos return tlsv1_client_get_version(conn->client, buf, buflen);
690928750b6Schristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
691928750b6Schristos return -1;
692928750b6Schristos }
693928750b6Schristos
694928750b6Schristos
tls_get_cipher(void * tls_ctx,struct tls_connection * conn,char * buf,size_t buflen)6958dbcf02cSchristos int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
6968dbcf02cSchristos char *buf, size_t buflen)
6978dbcf02cSchristos {
6988dbcf02cSchristos if (conn == NULL)
6998dbcf02cSchristos return -1;
7008dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
7018dbcf02cSchristos if (conn->client)
7028dbcf02cSchristos return tlsv1_client_get_cipher(conn->client, buf, buflen);
7038dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
7048dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
7058dbcf02cSchristos if (conn->server)
7068dbcf02cSchristos return tlsv1_server_get_cipher(conn->server, buf, buflen);
7078dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
7088dbcf02cSchristos return -1;
7098dbcf02cSchristos }
7108dbcf02cSchristos
7118dbcf02cSchristos
tls_connection_enable_workaround(void * tls_ctx,struct tls_connection * conn)7128dbcf02cSchristos int tls_connection_enable_workaround(void *tls_ctx,
7138dbcf02cSchristos struct tls_connection *conn)
7148dbcf02cSchristos {
7158dbcf02cSchristos return -1;
7168dbcf02cSchristos }
7178dbcf02cSchristos
7188dbcf02cSchristos
tls_connection_client_hello_ext(void * tls_ctx,struct tls_connection * conn,int ext_type,const u8 * data,size_t data_len)7198dbcf02cSchristos int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
7208dbcf02cSchristos int ext_type, const u8 *data,
7218dbcf02cSchristos size_t data_len)
7228dbcf02cSchristos {
7238dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
7248dbcf02cSchristos if (conn->client) {
7258dbcf02cSchristos return tlsv1_client_hello_ext(conn->client, ext_type,
7268dbcf02cSchristos data, data_len);
7278dbcf02cSchristos }
7288dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
7298dbcf02cSchristos return -1;
7308dbcf02cSchristos }
7318dbcf02cSchristos
7328dbcf02cSchristos
tls_connection_get_failed(void * tls_ctx,struct tls_connection * conn)7338dbcf02cSchristos int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
7348dbcf02cSchristos {
735*0d69f216Schristos #ifdef CONFIG_TLS_INTERNAL_SERVER
736*0d69f216Schristos if (conn->server)
737*0d69f216Schristos return tlsv1_server_get_failed(conn->server);
738*0d69f216Schristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
7398dbcf02cSchristos return 0;
7408dbcf02cSchristos }
7418dbcf02cSchristos
7428dbcf02cSchristos
tls_connection_get_read_alerts(void * tls_ctx,struct tls_connection * conn)7438dbcf02cSchristos int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
7448dbcf02cSchristos {
745*0d69f216Schristos #ifdef CONFIG_TLS_INTERNAL_SERVER
746*0d69f216Schristos if (conn->server)
747*0d69f216Schristos return tlsv1_server_get_read_alerts(conn->server);
748*0d69f216Schristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
7498dbcf02cSchristos return 0;
7508dbcf02cSchristos }
7518dbcf02cSchristos
7528dbcf02cSchristos
tls_connection_get_write_alerts(void * tls_ctx,struct tls_connection * conn)7538dbcf02cSchristos int tls_connection_get_write_alerts(void *tls_ctx,
7548dbcf02cSchristos struct tls_connection *conn)
7558dbcf02cSchristos {
756*0d69f216Schristos #ifdef CONFIG_TLS_INTERNAL_SERVER
757*0d69f216Schristos if (conn->server)
758*0d69f216Schristos return tlsv1_server_get_write_alerts(conn->server);
759*0d69f216Schristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
7608dbcf02cSchristos return 0;
7618dbcf02cSchristos }
7628dbcf02cSchristos
7638dbcf02cSchristos
tls_connection_set_session_ticket_cb(void * tls_ctx,struct tls_connection * conn,tls_session_ticket_cb cb,void * ctx)7648dbcf02cSchristos int tls_connection_set_session_ticket_cb(void *tls_ctx,
7658dbcf02cSchristos struct tls_connection *conn,
7668dbcf02cSchristos tls_session_ticket_cb cb,
7678dbcf02cSchristos void *ctx)
7688dbcf02cSchristos {
7698dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_CLIENT
7708dbcf02cSchristos if (conn->client) {
7718dbcf02cSchristos tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
7728dbcf02cSchristos return 0;
7738dbcf02cSchristos }
7748dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_CLIENT */
7758dbcf02cSchristos #ifdef CONFIG_TLS_INTERNAL_SERVER
7768dbcf02cSchristos if (conn->server) {
7778dbcf02cSchristos tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
7788dbcf02cSchristos return 0;
7798dbcf02cSchristos }
7808dbcf02cSchristos #endif /* CONFIG_TLS_INTERNAL_SERVER */
7818dbcf02cSchristos return -1;
7828dbcf02cSchristos }
7839a53cbbeSchristos
7849a53cbbeSchristos
tls_get_library_version(char * buf,size_t buf_len)7859a53cbbeSchristos int tls_get_library_version(char *buf, size_t buf_len)
7869a53cbbeSchristos {
7879a53cbbeSchristos return os_snprintf(buf, buf_len, "internal");
7889a53cbbeSchristos }
789928750b6Schristos
790928750b6Schristos
tls_connection_set_success_data(struct tls_connection * conn,struct wpabuf * data)791928750b6Schristos void tls_connection_set_success_data(struct tls_connection *conn,
792928750b6Schristos struct wpabuf *data)
793928750b6Schristos {
794928750b6Schristos }
795928750b6Schristos
796928750b6Schristos
tls_connection_set_success_data_resumed(struct tls_connection * conn)797928750b6Schristos void tls_connection_set_success_data_resumed(struct tls_connection *conn)
798928750b6Schristos {
799928750b6Schristos }
800928750b6Schristos
801928750b6Schristos
802928750b6Schristos const struct wpabuf *
tls_connection_get_success_data(struct tls_connection * conn)803928750b6Schristos tls_connection_get_success_data(struct tls_connection *conn)
804928750b6Schristos {
805928750b6Schristos return NULL;
806928750b6Schristos }
807928750b6Schristos
808928750b6Schristos
tls_connection_remove_session(struct tls_connection * conn)809928750b6Schristos void tls_connection_remove_session(struct tls_connection *conn)
810928750b6Schristos {
811928750b6Schristos }
812