static void append_alpn(gnutls_session_t session) { gnutls_datum_t protocol; int ret; char str[64]; snprintf(str, sizeof(str), "myproto"); protocol.data = (void*)str; protocol.size = strlen(str); ret = gnutls_alpn_set_protocols(session, &protocol, 1, 0); if (ret < 0) { gnutls_perror(ret); exit(1); } }
static int gnutls_SessionOpen(vlc_tls_creds_t *creds, vlc_tls_t *tls, int type, gnutls_certificate_credentials_t x509, vlc_tls_t *sock, const char *const *alpn) { gnutls_session_t session; const char *errp; int val; val = gnutls_init (&session, type); if (val != 0) { msg_Err(creds, "cannot initialize TLS session: %s", gnutls_strerror(val)); return VLC_EGENERIC; } char *priorities = var_InheritString(creds, "gnutls-priorities"); if (unlikely(priorities == NULL)) goto error; val = gnutls_priority_set_direct (session, priorities, &errp); if (val < 0) msg_Err(creds, "cannot set TLS priorities \"%s\": %s", errp, gnutls_strerror(val)); free (priorities); if (val < 0) goto error; val = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509); if (val < 0) { msg_Err(creds, "cannot set TLS session credentials: %s", gnutls_strerror(val)); goto error; } if (alpn != NULL) { gnutls_datum_t *protv = NULL; unsigned protc = 0; while (*alpn != NULL) { gnutls_datum_t *n = realloc(protv, sizeof (*protv) * (protc + 1)); if (unlikely(n == NULL)) { free(protv); goto error; } protv = n; protv[protc].data = (void *)*alpn; protv[protc].size = strlen(*alpn); protc++; alpn++; } val = gnutls_alpn_set_protocols (session, protv, protc, 0); free (protv); } gnutls_transport_set_ptr(session, sock); gnutls_transport_set_vec_push_function(session, vlc_gnutls_writev); gnutls_transport_set_pull_function(session, vlc_gnutls_read); tls->sys = session; tls->get_fd = gnutls_GetFD; tls->readv = gnutls_Recv; tls->writev = gnutls_Send; tls->shutdown = gnutls_Shutdown; tls->close = gnutls_Close; return VLC_SUCCESS; error: gnutls_deinit (session); return VLC_EGENERIC; }
static void client(int fd, const char *protocol0, const char *protocol1, const char *protocol2) { gnutls_session_t session; int ret; gnutls_datum_t proto; gnutls_anon_client_credentials_t anoncred; /* Need to enable anonymous KX specifically. */ global_init(); if (debug) { gnutls_global_set_log_function(client_log_func); gnutls_global_set_log_level(4711); } gnutls_anon_allocate_client_credentials(&anoncred); /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT); /* Use default priorities */ gnutls_priority_set_direct(session, "NONE:+VERS-TLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL", NULL); if (protocol1) { gnutls_datum_t t[3]; t[0].data = (void *) protocol0; t[0].size = strlen(protocol0); t[1].data = (void *) protocol1; t[1].size = strlen(protocol1); t[2].data = (void *) protocol2; t[2].size = strlen(protocol2); ret = gnutls_alpn_set_protocols(session, t, 3, 0); if (ret < 0) { gnutls_perror(ret); exit(1); } } /* put the anonymous credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); gnutls_transport_set_int(session, fd); /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { fail("client: Handshake failed\n"); gnutls_perror(ret); exit(1); } else { if (debug) success("client: Handshake was completed\n"); } if (debug) success("client: TLS version is: %s\n", gnutls_protocol_get_name (gnutls_protocol_get_version(session))); ret = gnutls_alpn_get_selected_protocol(session, &proto); if (ret < 0) { gnutls_perror(ret); exit(1); } if (debug) { fprintf(stderr, "selected protocol: %.*s\n", (int) proto.size, proto.data); } gnutls_bye(session, GNUTLS_SHUT_WR); close(fd); gnutls_deinit(session); gnutls_anon_free_client_credentials(anoncred); gnutls_global_deinit(); }
static void server(int fd, const char *protocol1, const char *protocol2, const char *expected) { int ret; gnutls_session_t session; gnutls_anon_server_credentials_t anoncred; gnutls_datum_t t[2]; gnutls_datum_t selected; /* this must be called once in the program */ global_init(); if (debug) { gnutls_global_set_log_function(server_log_func); gnutls_global_set_log_level(4711); } gnutls_anon_allocate_server_credentials(&anoncred); gnutls_init(&session, GNUTLS_SERVER); /* avoid calling all the priority functions, since the defaults * are adequate. */ gnutls_priority_set_direct(session, "NONE:+VERS-TLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL", NULL); t[0].data = (void *) protocol1; t[0].size = strlen(protocol1); t[1].data = (void *) protocol2; t[1].size = strlen(protocol2); ret = gnutls_alpn_set_protocols(session, t, 2, GNUTLS_ALPN_SERVER_PRECEDENCE); if (ret < 0) { gnutls_perror(ret); exit(1); } gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); gnutls_transport_set_int(session, fd); do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { close(fd); gnutls_deinit(session); fail("server: Handshake has failed (%s)\n\n", gnutls_strerror(ret)); terminate(); } if (debug) success("server: Handshake was completed\n"); if (debug) success("server: TLS version is: %s\n", gnutls_protocol_get_name (gnutls_protocol_get_version(session))); ret = gnutls_alpn_get_selected_protocol(session, &selected); if (ret < 0) { gnutls_perror(ret); exit(1); } if (debug) { success("Protocol: %.*s\n", (int) selected.size, selected.data); } if (selected.size != strlen(expected) || memcmp(selected.data, expected, selected.size) != 0) { fail("did not select the expected protocol (selected %.*s, expected %s)\n", selected.size, selected.data, expected); exit(1); } /* do not wait for the peer to close the connection. */ gnutls_bye(session, GNUTLS_SHUT_WR); close(fd); gnutls_deinit(session); gnutls_anon_free_server_credentials(anoncred); gnutls_global_deinit(); if (debug) success("server: finished\n"); }
static CURLcode gtls_connect_step1(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; gnutls_session_t session; int rc; void *ssl_sessionid; size_t ssl_idsize; bool sni = TRUE; /* default is SNI enabled */ #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT static const int cipher_priority[] = { /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, but this code path is only ever used for ver. < 2.12.0. GNUTLS_CIPHER_AES_128_GCM, GNUTLS_CIPHER_AES_256_GCM, */ GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_CIPHER_3DES_CBC, }; static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; static int protocol_priority[] = { 0, 0, 0, 0 }; #else #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" /* If GnuTLS was compiled without support for SRP it will error out if SRP is requested in the priority string, so treat it specially */ #define GNUTLS_SRP "+SRP" const char* prioritylist; const char *err = NULL; #endif if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ return CURLE_OK; if(!gtls_inited) Curl_gtls_init(); /* GnuTLS only supports SSLv3 and TLSv1 */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } #ifdef USE_TLS_SRP if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); rc = gnutls_srp_allocate_client_credentials( &conn->ssl[sockindex].srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_allocate_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_OUT_OF_MEMORY; } rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex]. srp_client_cred, data->set.ssl.username, data->set.ssl.password); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_set_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_BAD_FUNCTION_ARGUMENT; } } #endif if(data->set.ssl.CAfile) { /* set the trusted CA cert bundle file */ gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, data->set.ssl.CAfile, GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); if(data->set.ssl.verifypeer) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", rc, data->set.ssl.CAfile); } #ifdef HAS_CAPATH if(data->set.ssl.CApath) { /* set the trusted CA cert directory */ rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred, data->set.ssl.CApath, GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); if(data->set.ssl.verifypeer) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", rc, data->set.ssl.CApath); } #endif #ifdef CURL_CA_FALLBACK /* use system ca certificate store as fallback */ if(data->set.ssl.verifypeer && !(data->set.ssl.CAfile || data->set.ssl.CApath)) { gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred); } #endif if(data->set.ssl.CRLfile) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, data->set.ssl.CRLfile, GNUTLS_X509_FMT_PEM); if(rc < 0) { failf(data, "error reading crl file %s (%s)", data->set.ssl.CRLfile, gnutls_strerror(rc)); return CURLE_SSL_CRL_BADFILE; } else infof(data, "found %d CRL in %s\n", rc, data->set.ssl.CRLfile); } /* Initialize TLS session as a client */ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* convenient assign */ session = conn->ssl[sockindex].session; if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && #endif sni && (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, strlen(conn->host.name)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); /* Use default priorities */ rc = gnutls_set_default_priority(session); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT rc = gnutls_cipher_set_priority(session, cipher_priority); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; /* Sets the priority on the certificate types supported by gnutls. Priority is higher for types specified before others. After specifying the types you want, you must append a 0. */ rc = gnutls_certificate_type_set_priority(session, cert_type_priority); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; if(data->set.ssl.cipher_list != NULL) { failf(data, "can't pass a custom cipher list to older GnuTLS" " versions"); return CURLE_SSL_CONNECT_ERROR; } switch (data->set.ssl.version) { case CURL_SSLVERSION_SSLv3: protocol_priority[0] = GNUTLS_SSL3; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: protocol_priority[0] = GNUTLS_TLS1_0; protocol_priority[1] = GNUTLS_TLS1_1; protocol_priority[2] = GNUTLS_TLS1_2; break; case CURL_SSLVERSION_TLSv1_0: protocol_priority[0] = GNUTLS_TLS1_0; break; case CURL_SSLVERSION_TLSv1_1: protocol_priority[0] = GNUTLS_TLS1_1; break; case CURL_SSLVERSION_TLSv1_2: protocol_priority[0] = GNUTLS_TLS1_2; break; case CURL_SSLVERSION_SSLv2: default: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; break; } rc = gnutls_protocol_set_priority(session, protocol_priority); if(rc != GNUTLS_E_SUCCESS) { failf(data, "Did you pass a valid GnuTLS cipher list?"); return CURLE_SSL_CONNECT_ERROR; } #else /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ switch (data->set.ssl.version) { case CURL_SSLVERSION_SSLv3: prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; sni = false; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_0: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.0:" GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_1: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.1:" GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_2: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.2:" GNUTLS_SRP; break; case CURL_SSLVERSION_SSLv2: default: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; break; } rc = gnutls_priority_set_direct(session, prioritylist, &err); if((rc == GNUTLS_E_INVALID_REQUEST) && err) { if(!strcmp(err, GNUTLS_SRP)) { /* This GnuTLS was probably compiled without support for SRP. * Note that fact and try again without it. */ int validprioritylen = curlx_uztosi(err - prioritylist); char *prioritycopy = strdup(prioritylist); if(!prioritycopy) return CURLE_OUT_OF_MEMORY; infof(data, "This GnuTLS does not support SRP\n"); if(validprioritylen) /* Remove the :+SRP */ prioritycopy[validprioritylen - 1] = 0; rc = gnutls_priority_set_direct(session, prioritycopy, &err); free(prioritycopy); } } if(rc != GNUTLS_E_SUCCESS) { failf(data, "Error %d setting GnuTLS cipher list starting with %s", rc, err); return CURLE_SSL_CONNECT_ERROR; } #endif #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { int cur = 0; gnutls_datum_t protocols[2]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) { protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; cur++; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; protocols[cur].size = ALPN_HTTP_1_1_LENGTH; cur++; infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); gnutls_alpn_set_protocols(session, protocols, cur, 0); } #endif if(data->set.str[STRING_CERT]) { if(data->set.str[STRING_KEY_PASSWD]) { #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 const unsigned int supported_key_encryption_algorithms = GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | GNUTLS_PKCS_USE_PBES2_AES_256; rc = gnutls_certificate_set_x509_key_file2( conn->ssl[sockindex].cred, data->set.str[STRING_CERT], data->set.str[STRING_KEY] ? data->set.str[STRING_KEY] : data->set.str[STRING_CERT], do_file_type(data->set.str[STRING_CERT_TYPE]), data->set.str[STRING_KEY_PASSWD], supported_key_encryption_algorithms); if(rc != GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 potentially-encrypted key file: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } #else failf(data, "gnutls lacks support for encrypted key files"); return CURLE_SSL_CONNECT_ERROR; #endif } else { rc = gnutls_certificate_set_x509_key_file( conn->ssl[sockindex].cred, data->set.str[STRING_CERT], data->set.str[STRING_KEY] ? data->set.str[STRING_KEY] : data->set.str[STRING_CERT], do_file_type(data->set.str[STRING_CERT_TYPE]) ); if(rc != GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 key or certificate file: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } } #ifdef USE_TLS_SRP /* put the credentials to the current session */ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, conn->ssl[sockindex].srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } else #endif { rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, conn->ssl[sockindex].cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } /* set the connection handle (file descriptor for the socket) */ gnutls_transport_set_ptr(session, GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); /* register callback functions to send and receive data. */ gnutls_transport_set_push_function(session, Curl_gtls_push); gnutls_transport_set_pull_function(session, Curl_gtls_pull); /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); #ifdef HAS_OCSP if(data->set.ssl.verifystatus) { rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } } #endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { /* we got a session id, use it! */ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); /* Informational message */ infof (data, "SSL re-using session ID\n"); } return CURLE_OK; }
static gboolean mod_gnutls_con_new(liConnection *con, int fd) { liEventLoop *loop = &con->wrk->loop; liServer *srv = con->srv; mod_context *ctx = con->srv_sock->data; mod_connection_ctx *conctx; gnutls_session_t session; int r; if (GNUTLS_E_SUCCESS > (r = gnutls_init(&session, GNUTLS_SERVER))) { ERROR(srv, "gnutls_init (%s): %s", gnutls_strerror_name(r), gnutls_strerror(r)); return FALSE; } mod_gnutls_context_acquire(ctx); if (GNUTLS_E_SUCCESS > (r = gnutls_priority_set(session, ctx->server_priority))) { ERROR(srv, "gnutls_priority_set (%s): %s", gnutls_strerror_name(r), gnutls_strerror(r)); goto fail; } if (GNUTLS_E_SUCCESS > (r = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctx->server_cert))) { ERROR(srv, "gnutls_credentials_set (%s): %s", gnutls_strerror_name(r), gnutls_strerror(r)); goto fail; } if (NULL != ctx->session_db) { gnutls_db_set_ptr(session, ctx->session_db); gnutls_db_set_remove_function(session, session_db_remove_cb); gnutls_db_set_retrieve_function(session, session_db_retrieve_cb); gnutls_db_set_store_function(session, session_db_store_cb); } #ifdef HAVE_SESSION_TICKET if (GNUTLS_E_SUCCESS > (r = gnutls_session_ticket_enable_server(session, &ctx->ticket_key))) { ERROR(srv, "gnutls_session_ticket_enable_server (%s): %s", gnutls_strerror_name(r), gnutls_strerror(r)); goto fail; } #endif #ifdef GNUTLS_ALPN_MAND { static const gnutls_datum_t proto_http1 = { (unsigned char*) CONST_STR_LEN("http/1.1") }; gnutls_alpn_set_protocols(session, &proto_http1, 1, 0); } #endif conctx = g_slice_new0(mod_connection_ctx); conctx->session = session; conctx->sock_stream = li_iostream_new(con->wrk, fd, tcp_io_cb, conctx); conctx->client_hello_stream = li_ssl_client_hello_stream(&con->wrk->loop, gnutls_client_hello_cb, conctx); #ifdef USE_SNI li_job_init(&conctx->sni_job, sni_job_cb); conctx->sni_jobref = li_job_ref(&con->wrk->loop.jobqueue, &conctx->sni_job); #endif li_stream_connect(&conctx->sock_stream->stream_in, conctx->client_hello_stream); conctx->tls_filter = li_gnutls_filter_new(srv, con->wrk, &filter_callbacks, conctx, conctx->session, conctx->client_hello_stream, &conctx->sock_stream->stream_out); conctx->con = con; conctx->ctx = ctx; con->con_sock.data = conctx; con->con_sock.callbacks = &gnutls_tcp_cbs; con->con_sock.raw_out = li_stream_plug_new(loop); con->con_sock.raw_in = li_stream_plug_new(loop); con->info.is_ssl = TRUE; return TRUE; fail: gnutls_deinit(session); mod_gnutls_context_release(ctx); return FALSE; }