efl_net_{server,dialer}_ssl: TCP + SSL easy to use.

in the previous commit we're manually upgrading an existing TCP socket
to SSL. It is desired since some protocols need to negotiate, like
STARTTLS and the likes

Now we offer 2 classes that does autostart SSL once the socket is
ready.
This commit is contained in:
Gustavo Sverzut Barbieri 2016-11-01 01:31:56 -02:00
parent 973f2c29b5
commit 1ee201e078
2 changed files with 125 additions and 0 deletions

View File

@ -324,6 +324,10 @@ static const Ecore_Getopt options = {
"If set will change the base chunk size used while reading."),
ECORE_GETOPT_STORE_DOUBLE('t', "inactivity-timeout",
"If greater than zero, specifies the number of seconds without any reads or writes that the copier will be timed out."),
ECORE_GETOPT_STORE_FALSE(0, "no-ssl-verify",
"Disables SSL verify, to use with self-signed certificates and the likes"),
ECORE_GETOPT_VERSION('V', "version"),
ECORE_GETOPT_COPYRIGHT('C', "copyright"),
ECORE_GETOPT_LICENSE('L', "license"),
@ -339,6 +343,7 @@ static const Ecore_Getopt options = {
#ifndef _WIN32
"unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n"
#endif
"ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
"",
"input-file"),
ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
@ -354,6 +359,7 @@ static const Ecore_Getopt options = {
#ifndef _WIN32
"unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n"
#endif
"ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
"",
"output-file"),
ECORE_GETOPT_SENTINEL
@ -369,6 +375,7 @@ main(int argc, char **argv)
unsigned long buffer_limit = 0;
unsigned long read_chunk_size = 0;
double timeout = 0.0;
Eina_Bool ssl_verify = EINA_TRUE;
Eina_Bool quit_option = EINA_FALSE;
Ecore_Getopt_Value values[] = {
ECORE_GETOPT_VALUE_STR(line_delimiter),
@ -376,6 +383,8 @@ main(int argc, char **argv)
ECORE_GETOPT_VALUE_ULONG(read_chunk_size),
ECORE_GETOPT_VALUE_DOUBLE(timeout),
ECORE_GETOPT_VALUE_BOOL(ssl_verify),
/* standard block to provide version, copyright, license and help */
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
@ -572,6 +581,36 @@ main(int argc, char **argv)
}
}
#endif
else if (strncmp(input_fname, "ssl://", strlen("ssl://")) == 0)
{
/*
* Since Efl.Net.Socket implements the required interfaces,
* they can be used here as well.
*/
const char *address = input_fname + strlen("ssl://");
Eina_Error err;
input = efl_add(EFL_NET_DIALER_SSL_CLASS, ecore_main_loop_get(),
efl_event_callback_array_add(efl_added, input_cbs(), NULL), /* optional */
efl_event_callback_array_add(efl_added, dialer_cbs(), NULL) /* optional */
);
if (!input)
{
fprintf(stderr, "ERROR: could not create SSL Dialer.\n");
retval = EXIT_FAILURE;
goto end;
}
efl_net_socket_ssl_verify_mode_set(input, ssl_verify ? EFL_NET_SSL_VERIFY_MODE_REQUIRED : EFL_NET_SSL_VERIFY_MODE_NONE);
efl_net_socket_ssl_hostname_verify_set(input, ssl_verify);
err = efl_net_dialer_dial(input, address);
if (err)
{
fprintf(stderr, "ERROR: could not SSL dial %s: %s\n",
address, eina_error_msg_get(err));
goto end_input;
}
}
else
{
/* regular file, open with flags: read-only and close-on-exec */
@ -787,6 +826,36 @@ main(int argc, char **argv)
}
}
#endif
else if (strncmp(output_fname, "ssl://", strlen("ssl://")) == 0)
{
/*
* Since Efl.Net.Socket implements the required interfaces,
* they can be used here as well.
*/
const char *address = output_fname + strlen("ssl://");
Eina_Error err;
output = efl_add(EFL_NET_DIALER_SSL_CLASS, ecore_main_loop_get(),
efl_event_callback_array_add(efl_added, output_cbs(), NULL), /* optional */
efl_event_callback_array_add(efl_added, dialer_cbs(), NULL) /* optional */
);
if (!output)
{
fprintf(stderr, "ERROR: could not create SSL Dialer.\n");
retval = EXIT_FAILURE;
goto end_input;
}
efl_net_socket_ssl_verify_mode_set(output, ssl_verify ? EFL_NET_SSL_VERIFY_MODE_REQUIRED : EFL_NET_SSL_VERIFY_MODE_NONE);
efl_net_socket_ssl_hostname_verify_set(output, ssl_verify);
err = efl_net_dialer_dial(output, address);
if (err)
{
fprintf(stderr, "ERROR: could not SSL dial %s: %s\n",
address, eina_error_msg_get(err));
goto end_output;
}
}
else
{
/* regular file, open with flags: write-only, close-on-exec,

View File

@ -474,12 +474,21 @@ EFL_CALLBACKS_ARRAY_DEFINE(server_cbs,
static const char * protocols[] = {
"tcp",
"udp",
"ssl",
#ifndef _WIN32
"unix",
#endif
NULL
};
static const char *ciphers_strs[] = {
"auto",
"sslv3",
"tlsv1",
"tlsv1.1",
"tlsv1.2",
NULL
};
static const Ecore_Getopt options = {
"efl_net_server_example", /* program name */
@ -518,6 +527,13 @@ static const Ecore_Getopt options = {
"Disable multicast loopback."),
ECORE_GETOPT_APPEND('M', "udp-multicast-group", "Join a multicast group in the form 'IP@INTERFACE', with optional '@INTERFACE', where INTERFACE is the IP address of the interface to join the multicast.", ECORE_GETOPT_TYPE_STR),
ECORE_GETOPT_CATEGORY("ssl", "SSL options"),
ECORE_GETOPT_CHOICE('c', "ssl-cipher", "Cipher to use, defaults to 'auto'", ciphers_strs),
ECORE_GETOPT_APPEND(0, "ssl-certificate", "certificate path to use.", ECORE_GETOPT_TYPE_STR),
ECORE_GETOPT_APPEND(0, "ssl-private-key", "private key path to use.", ECORE_GETOPT_TYPE_STR),
ECORE_GETOPT_APPEND(0, "ssl-crl", "certificate revogation list to use.", ECORE_GETOPT_TYPE_STR),
ECORE_GETOPT_APPEND(0, "ssl-ca", "certificate authorities path to use.", ECORE_GETOPT_TYPE_STR),
ECORE_GETOPT_CHOICE_METAVAR(0, NULL, "The server protocol.", "protocol",
protocols),
ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
@ -543,6 +559,11 @@ main(int argc, char **argv)
Eina_Bool ipv6_only = EINA_TRUE;
Eina_Bool udp_dont_route = EINA_FALSE;
Eina_Bool udp_mcast_loopback = EINA_TRUE;
Eina_List *certificates = NULL;
Eina_List *private_keys = NULL;
Eina_List *crls = NULL;
Eina_List *cas = NULL;
char *cipher_choice = NULL;
Eina_Bool quit_option = EINA_FALSE;
Ecore_Getopt_Value values[] = {
ECORE_GETOPT_VALUE_BOOL(echo),
@ -563,6 +584,13 @@ main(int argc, char **argv)
ECORE_GETOPT_VALUE_BOOL(udp_mcast_loopback),
ECORE_GETOPT_VALUE_LIST(udp_mcast_groups),
ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: ssl */
ECORE_GETOPT_VALUE_STR(cipher_choice),
ECORE_GETOPT_VALUE_LIST(certificates),
ECORE_GETOPT_VALUE_LIST(private_keys),
ECORE_GETOPT_VALUE_LIST(crls),
ECORE_GETOPT_VALUE_LIST(cas),
/* positional argument */
ECORE_GETOPT_VALUE_STR(protocol),
ECORE_GETOPT_VALUE_STR(address),
@ -603,6 +631,7 @@ main(int argc, char **argv)
if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS;
else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS;
else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS;
#ifndef _WIN32
else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
#endif
@ -642,6 +671,33 @@ main(int argc, char **argv)
EINA_LIST_FOREACH(udp_mcast_groups, lst, str)
efl_net_server_udp_multicast_join(server, str);
}
else if (cls == EFL_NET_SERVER_SSL_CLASS)
{
Eo *ssl_ctx;
Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO;
if (cipher_choice)
{
if (strcmp(cipher_choice, "auto") == 0)
cipher = EFL_NET_SSL_CIPHER_AUTO;
else if (strcmp(cipher_choice, "sslv3") == 0)
cipher = EFL_NET_SSL_CIPHER_SSLV3;
else if (strcmp(cipher_choice, "tlsv1") == 0)
cipher = EFL_NET_SSL_CIPHER_TLSV1;
else if (strcmp(cipher_choice, "tlsv1.1") == 0)
cipher = EFL_NET_SSL_CIPHER_TLSV1_1;
else if (strcmp(cipher_choice, "tlsv1.2") == 0)
cipher = EFL_NET_SSL_CIPHER_TLSV1_2;
}
ssl_ctx = efl_add(EFL_NET_SSL_CONTEXT_CLASS, NULL,
efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(certificates)),
efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(private_keys)),
efl_net_ssl_context_certificate_revogation_lists_set(efl_added, eina_list_iterator_new(crls)),
efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(cas)),
efl_net_ssl_context_setup(efl_added, cipher, EINA_FALSE /* a server! */));
efl_net_server_ssl_context_set(server, ssl_ctx);
}
#ifndef _WIN32
else if (cls == EFL_NET_SERVER_UNIX_CLASS)
{