[glib-networking/wip/danw/alpn] gnutls: implement ALPN properties
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/wip/danw/alpn] gnutls: implement ALPN properties
- Date: Wed, 31 May 2017 19:03:47 +0000 (UTC)
commit 355eb0728abd683706c4524a9923da56868d7789
Author: Dan Winship <danw gnome org>
Date: Tue Dec 9 11:09:23 2014 +0100
gnutls: implement ALPN properties
Implement GTlsConnection:advertised-protocols and
:negotiated-protocol.
configure.ac | 4 +-
tls/gnutls/gtlsconnection-gnutls.c | 83 ++++++++++++++++++++++++++++++-
tls/tests/connection.c | 96 ++++++++++++++++++++++++++++++++++++
3 files changed, 179 insertions(+), 4 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 618b182..590ddf9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,8 +33,8 @@ AM_GLIB_GNU_GETTEXT
dnl *****************************
dnl *** Check GLib GIO ***
dnl *****************************
-AM_PATH_GLIB_2_0(2.39.1,,AC_MSG_ERROR(GLIB not found),gio)
-GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_42"
+AM_PATH_GLIB_2_0(2.43.1,,AC_MSG_ERROR(GLIB not found),gio)
+GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_44"
GIO_MODULE_DIR=$($PKG_CONFIG --variable giomoduledir gio-2.0)
AS_IF([test "$GIO_MODULE_DIR" = ""],
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 7436451..72c6594 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -87,7 +87,9 @@ enum
PROP_CERTIFICATE,
PROP_INTERACTION,
PROP_PEER_CERTIFICATE,
- PROP_PEER_CERTIFICATE_ERRORS
+ PROP_PEER_CERTIFICATE_ERRORS,
+ PROP_ADVERTISED_PROTOCOLS,
+ PROP_NEGOTIATED_PROTOCOL,
};
struct _GTlsConnectionGnutlsPrivate
@@ -145,6 +147,9 @@ struct _GTlsConnectionGnutlsPrivate
GTlsInteraction *interaction;
gchar *interaction_id;
+ char **advertised_protocols;
+ char *negotiated_protocol;
+
GMutex op_mutex;
GCancellable *waiting_for_op;
@@ -353,6 +358,9 @@ g_tls_connection_gnutls_finalize (GObject *object)
g_free (gnutls->priv->interaction_id);
g_clear_object (&gnutls->priv->interaction);
+ g_clear_pointer (&gnutls->priv->advertised_protocols, g_strfreev);
+ g_clear_pointer (&gnutls->priv->negotiated_protocol, g_free);
+
g_clear_error (&gnutls->priv->handshake_error);
g_clear_error (&gnutls->priv->read_error);
g_clear_error (&gnutls->priv->write_error);
@@ -424,6 +432,14 @@ g_tls_connection_gnutls_get_property (GObject *object,
g_value_set_flags (value, gnutls->priv->peer_certificate_errors);
break;
+ case PROP_ADVERTISED_PROTOCOLS:
+ g_value_set_boxed (value, gnutls->priv->advertised_protocols);
+ break;
+
+ case PROP_NEGOTIATED_PROTOCOL:
+ g_value_set_string (value, gnutls->priv->negotiated_protocol);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -506,6 +522,11 @@ g_tls_connection_gnutls_set_property (GObject *object,
gnutls->priv->interaction = g_value_dup_object (value);
break;
+ case PROP_ADVERTISED_PROTOCOLS:
+ g_clear_pointer (&gnutls->priv->advertised_protocols, g_strfreev);
+ gnutls->priv->advertised_protocols = g_value_dup_boxed (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -1230,6 +1251,25 @@ handshake_thread (GTask *task,
g_tls_connection_gnutls_set_handshake_priority (gnutls);
+#if (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 2) || (GNUTLS_VERSION_MAJOR > 3)
+ if (gnutls->priv->advertised_protocols)
+ {
+ gnutls_datum_t *protocols;
+ int n_protos, i;
+
+ n_protos = g_strv_length (gnutls->priv->advertised_protocols);
+ protocols = g_new (gnutls_datum_t, n_protos);
+ for (i = 0; gnutls->priv->advertised_protocols[i]; i++)
+ {
+ protocols[i].size = strlen (gnutls->priv->advertised_protocols[i]);
+ protocols[i].data = g_memdup (gnutls->priv->advertised_protocols[i], protocols[i].size);
+ }
+ gnutls_alpn_set_protocols (gnutls->priv->session,
+ protocols, n_protos, 0);
+ g_free (protocols);
+ }
+#endif
+
BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, TRUE, cancellable);
ret = gnutls_handshake (gnutls->priv->session);
if (ret == GNUTLS_E_GOT_APPLICATION_DATA)
@@ -1308,7 +1348,23 @@ accept_peer_certificate (GTlsConnectionGnutls *gnutls,
static void
begin_handshake (GTlsConnectionGnutls *gnutls)
{
+ g_object_freeze_notify (G_OBJECT (gnutls));
+ if (gnutls->priv->peer_certificate)
+ {
+ g_clear_object (&gnutls->priv->peer_certificate);
+ gnutls->priv->peer_certificate_errors = 0;
+ g_object_notify (G_OBJECT (gnutls), "peer-certificate");
+ g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
+ }
+ if (gnutls->priv->negotiated_protocol)
+ {
+ g_clear_pointer (&gnutls->priv->negotiated_protocol, g_free);
+ g_object_notify (G_OBJECT (gnutls), "negotiated-protocol");
+ }
+
G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->begin_handshake (gnutls);
+
+ g_object_thaw_notify (G_OBJECT (gnutls));
}
static gboolean
@@ -1326,7 +1382,12 @@ finish_handshake (GTlsConnectionGnutls *gnutls,
peer_certificate_errors = gnutls->priv->peer_certificate_errors_tmp;
gnutls->priv->peer_certificate_errors_tmp = 0;
- if (g_task_propagate_boolean (task, error) && peer_certificate)
+ if (!g_task_propagate_boolean (task, error))
+ g_clear_object (&peer_certificate);
+
+ g_object_freeze_notify (G_OBJECT (gnutls));
+
+ if (!*error && peer_certificate)
{
if (!accept_peer_certificate (gnutls, peer_certificate,
peer_certificate_errors))
@@ -1341,6 +1402,22 @@ finish_handshake (GTlsConnectionGnutls *gnutls,
g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
}
+#if (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 2) || (GNUTLS_VERSION_MAJOR > 3)
+ if (!*error && gnutls->priv->advertised_protocols)
+ {
+ gnutls_datum_t protocol;
+
+ if (gnutls_alpn_get_selected_protocol (gnutls->priv->session, &protocol) == 0 &&
+ protocol.size > 0)
+ {
+ gnutls->priv->negotiated_protocol = g_strndup (protocol.data, protocol.size);
+ g_object_notify (G_OBJECT (gnutls), "negotiated-protocol");
+ }
+ }
+#endif
+
+ g_object_thaw_notify (G_OBJECT (gnutls));
+
if (*error && gnutls->priv->started_handshake)
gnutls->priv->handshake_error = g_error_copy (*error);
@@ -1768,6 +1845,8 @@ g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction");
g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE, "peer-certificate");
g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
+ g_object_class_override_property (gobject_class, PROP_ADVERTISED_PROTOCOLS, "advertised-protocols");
+ g_object_class_override_property (gobject_class, PROP_NEGOTIATED_PROTOCOL, "negotiated-protocol");
}
static void
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index 6bcb9c2..544450a 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -72,6 +72,7 @@ typedef struct {
GError *server_error;
gboolean server_should_close;
gboolean server_running;
+ const char * const *server_protocols;
char buf[128];
gssize nread, nwrote;
@@ -277,6 +278,12 @@ on_incoming_connection (GSocketService *service,
if (test->database)
g_tls_connection_set_database (G_TLS_CONNECTION (test->server_connection), test->database);
+ if (test->server_protocols)
+ {
+ g_tls_connection_set_advertised_protocols (G_TLS_CONNECTION (test->server_connection),
+ test->server_protocols);
+ }
+
stream = g_io_stream_get_output_stream (test->server_connection);
g_output_stream_write_async (stream, TEST_DATA,
@@ -1462,6 +1469,86 @@ test_fallback_subprocess (TestConnection *test,
g_assert_no_error (error);
}
+static void
+test_alpn (TestConnection *test,
+ const char * const *client_protocols,
+ const char * const *server_protocols,
+ const char *negotiated_protocol)
+{
+#if (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 2) || (GNUTLS_VERSION_MAJOR > 3)
+ GIOStream *connection;
+ GError *error = NULL;
+
+ test->server_protocols = server_protocols;
+
+ test->database = g_tls_file_database_new (tls_test_file_path ("ca-roots.pem"), &error);
+ g_assert_no_error (error);
+ g_assert (test->database);
+
+ connection = start_async_server_and_connect_to_it (test, G_TLS_AUTHENTICATION_NONE, TRUE);
+ test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+ g_assert_no_error (error);
+ g_object_unref (connection);
+
+ if (client_protocols)
+ {
+ g_tls_connection_set_advertised_protocols (G_TLS_CONNECTION (test->client_connection),
+ client_protocols);
+ }
+
+ g_tls_connection_set_database (G_TLS_CONNECTION (test->client_connection), test->database);
+
+ read_test_data_async (test);
+ g_main_loop_run (test->loop);
+
+ g_assert_no_error (test->read_error);
+ g_assert_no_error (test->server_error);
+
+ g_assert_cmpstr (g_tls_connection_get_negotiated_protocol (G_TLS_CONNECTION (test->server_connection)),
==, negotiated_protocol);
+ g_assert_cmpstr (g_tls_connection_get_negotiated_protocol (G_TLS_CONNECTION (test->client_connection)),
==, negotiated_protocol);
+#else
+ g_test_skip ("no support for ALPN in this gnutls version");
+#endif
+}
+
+static void
+test_alpn_match (TestConnection *test,
+ gconstpointer data)
+{
+ const char * const client_protocols[] = { "one", "two", "three", NULL };
+ const char * const server_protocols[] = { "four", "seven", "nine", "two", NULL };
+
+ test_alpn (test, client_protocols, server_protocols, "two");
+}
+
+static void
+test_alpn_no_match (TestConnection *test,
+ gconstpointer data)
+{
+ const char * const client_protocols[] = { "one", "two", "three", NULL };
+ const char * const server_protocols[] = { "four", "seven", "nine", NULL };
+
+ test_alpn (test, client_protocols, server_protocols, NULL);
+}
+
+static void
+test_alpn_client_only (TestConnection *test,
+ gconstpointer data)
+{
+ const char * const client_protocols[] = { "one", "two", "three", NULL };
+
+ test_alpn (test, client_protocols, NULL, NULL);
+}
+
+static void
+test_alpn_server_only (TestConnection *test,
+ gconstpointer data)
+{
+ const char * const server_protocols[] = { "four", "seven", "nine", "two", NULL };
+
+ test_alpn (test, NULL, server_protocols, NULL);
+}
+
int
main (int argc,
char *argv[])
@@ -1544,6 +1631,15 @@ main (int argc,
TestConnection, NULL,
setup_connection, test_fallback_subprocess, teardown_connection);
+ g_test_add ("/tls/connection/alpn/match", TestConnection, NULL,
+ setup_connection, test_alpn_match, teardown_connection);
+ g_test_add ("/tls/connection/alpn/no-match", TestConnection, NULL,
+ setup_connection, test_alpn_no_match, teardown_connection);
+ g_test_add ("/tls/connection/alpn/client-only", TestConnection, NULL,
+ setup_connection, test_alpn_client_only, teardown_connection);
+ g_test_add ("/tls/connection/alpn/server-only", TestConnection, NULL,
+ setup_connection, test_alpn_server_only, teardown_connection);
+
ret = g_test_run();
/* for valgrinding */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]