From 55ee752c12855793d21c8bb44fe6996dbc91aeed Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sun, 24 Oct 2010 11:49:45 -0400 Subject: [PATCH] wocky-tls: specify peername at session creation time This is how gio TLS does it, among other reasons because it lets you use the SNI extension to tell the server which certificate it should present. https://bugs.freedesktop.org/show_bug.cgi?id=31447 --- examples/connect.c | 2 +- tests/wocky-tls-test.c | 2 +- wocky/wocky-tls-connector.c | 8 ++++-- wocky/wocky-tls-handler.c | 18 +++++++-------- wocky/wocky-tls-handler.h | 2 - wocky/wocky-tls.c | 49 ++++++++++++++++++++++++++++++++++++------ wocky/wocky-tls.h | 4 +- 7 files changed, 59 insertions(+), 26 deletions(-) diff --git a/examples/connect.c b/examples/connect.c index a1fc43b..2f2b9e8 100644 --- a/examples/connect.c +++ b/examples/connect.c @@ -166,7 +166,7 @@ tcp_start_tls_recv_cb (GObject *source, g_object_unref (conn); - ssl_session = wocky_tls_session_new (G_IO_STREAM (tcp)); + ssl_session = wocky_tls_session_new (G_IO_STREAM (tcp), server); ssl = wocky_tls_session_handshake (ssl_session, NULL, &error); if (ssl == NULL) diff --git a/tests/wocky-tls-test.c b/tests/wocky-tls-test.c index ba6defb..44667a5 100644 --- a/tests/wocky-tls-test.c +++ b/tests/wocky-tls-test.c @@ -235,7 +235,7 @@ test_openssl_handshake_rw (void) { ssl_test_t ssl_test = { NULL, } ; test_data_t *test = setup_test (); - WockyTLSSession *client = wocky_tls_session_new (test->stream->stream0); + WockyTLSSession *client = wocky_tls_session_new (test->stream->stream0, NULL); WockyTLSSession *server = wocky_tls_session_server_new ( test->stream->stream1, 1024, TLS_SERVER_KEY_FILE, TLS_SERVER_CRT_FILE); gsize expected = TEST_SSL_DATA_LEN * 5; diff --git a/wocky/wocky-tls-connector.c b/wocky/wocky-tls-connector.c index 9d89406..c383dda 100644 --- a/wocky/wocky-tls-connector.c +++ b/wocky/wocky-tls-connector.c @@ -246,7 +246,8 @@ do_handshake (WockyTLSConnector *self) g_object_get (self->priv->connection, "base-stream", &base_stream, NULL); g_assert (base_stream != NULL); - self->priv->session = wocky_tls_session_new (base_stream); + self->priv->session = wocky_tls_session_new (base_stream, + self->priv->peername); g_object_unref (base_stream); @@ -327,7 +328,7 @@ session_handshake_cb (GObject *source, g_object_unref (tls_conn); wocky_tls_handler_verify_async (self->priv->handler, - self->priv->session, self->priv->peername, + self->priv->session, tls_handler_verify_async_cb, self); } @@ -379,7 +380,8 @@ starttls_recv_cb (GObject *source, g_object_get (self->priv->connection, "base-stream", &base_stream, NULL); g_assert (base_stream != NULL); - self->priv->session = wocky_tls_session_new (base_stream); + self->priv->session = wocky_tls_session_new (base_stream, + self->priv->peername); g_object_unref (base_stream); diff --git a/wocky/wocky-tls-handler.c b/wocky/wocky-tls-handler.c index 5023831..ade2e1f 100644 --- a/wocky/wocky-tls-handler.c +++ b/wocky/wocky-tls-handler.c @@ -30,7 +30,6 @@ static void real_verify_async (WockyTLSHandler *self, WockyTLSSession *tls_session, - const gchar *peername, GAsyncReadyCallback callback, gpointer user_data); @@ -147,14 +146,13 @@ wocky_tls_handler_init (WockyTLSHandler *self) static void real_verify_async (WockyTLSHandler *self, WockyTLSSession *tls_session, - const gchar *peername, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; glong flags = WOCKY_TLS_VERIFY_NORMAL; WockyTLSCertStatus status = WOCKY_TLS_CERT_UNKNOWN_ERROR; - const gchar *verify_peername = NULL; + gchar *peername; result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, wocky_tls_handler_verify_async); @@ -166,13 +164,12 @@ real_verify_async (WockyTLSHandler *self, */ if (self->priv->ignore_ssl_errors) flags = WOCKY_TLS_VERIFY_LENIENT; - else - verify_peername = peername; - DEBUG ("Verifying certificate (peername: %s)", - (verify_peername == NULL) ? "-" : verify_peername); + g_object_get (G_OBJECT (tls_session), "peername", &peername, NULL); - wocky_tls_session_verify_peer (tls_session, verify_peername, flags, &status); + DEBUG ("Verifying certificate (peername: %s)", peername); + + wocky_tls_session_verify_peer (tls_session, flags, &status); if (status != WOCKY_TLS_CERT_OK) { @@ -225,6 +222,7 @@ real_verify_async (WockyTLSHandler *self, g_simple_async_result_complete_in_idle (result); g_object_unref (result); + g_free (peername); return; } else @@ -239,6 +237,7 @@ real_verify_async (WockyTLSHandler *self, g_simple_async_result_complete_in_idle (result); g_object_unref (result); + g_free (peername); } static gboolean @@ -252,13 +251,12 @@ real_verify_finish (WockyTLSHandler *self, void wocky_tls_handler_verify_async (WockyTLSHandler *self, WockyTLSSession *session, - const gchar *peername, GAsyncReadyCallback callback, gpointer user_data) { WockyTLSHandlerClass *klass = WOCKY_TLS_HANDLER_GET_CLASS (self); - klass->verify_async_func (self, session, peername, callback, user_data); + klass->verify_async_func (self, session, callback, user_data); } gboolean diff --git a/wocky/wocky-tls-handler.h b/wocky/wocky-tls-handler.h index 3bef7b4..6ff87ee 100644 --- a/wocky/wocky-tls-handler.h +++ b/wocky/wocky-tls-handler.h @@ -33,7 +33,6 @@ typedef struct _WockyTLSHandlerPrivate WockyTLSHandlerPrivate; typedef void (*WockyTLSHandlerVerifyAsyncFunc) (WockyTLSHandler *self, WockyTLSSession *tls_session, - const gchar *peername, GAsyncReadyCallback callback, gpointer user_data); @@ -75,7 +74,6 @@ WockyTLSHandler * wocky_tls_handler_new (gboolean ignore_ssl_errors); void wocky_tls_handler_verify_async (WockyTLSHandler *self, WockyTLSSession *tls_session, - const gchar *peername, GAsyncReadyCallback callback, gpointer user_data); gboolean wocky_tls_handler_verify_finish (WockyTLSHandler *self, diff --git a/wocky/wocky-tls.c b/wocky/wocky-tls.c index ca77e5c..b43dc0e 100644 --- a/wocky/wocky-tls.c +++ b/wocky/wocky-tls.c @@ -82,6 +82,7 @@ enum { PROP_S_NONE, PROP_S_STREAM, + PROP_S_PEERNAME, PROP_S_SERVER, PROP_S_DHBITS, PROP_S_KEYFILE, @@ -183,6 +184,9 @@ struct OPAQUE_TYPE__WockyTLSSession GError *error; gboolean async; + /* tls client support */ + gchar *peername; + /* tls server support */ gboolean server; gnutls_dh_params_t dh_params; @@ -661,7 +665,6 @@ wocky_tls_session_get_peers_certificate (WockyTLSSession *session, int wocky_tls_session_verify_peer (WockyTLSSession *session, - const gchar *peername, WockyTLSVerificationLevel level, WockyTLSCertStatus *status) { @@ -744,7 +747,7 @@ wocky_tls_session_verify_peer (WockyTLSSession *session, /* if we get this far, we have a structurally valid certificate * * signed by _someone_: check the hostname matches the peername */ - if (peername != NULL) + if (session->peername != NULL && level != WOCKY_TLS_VERIFY_LENIENT) switch (gnutls_certificate_type_get (session->session)) { gnutls_x509_crt_t x509; @@ -759,8 +762,8 @@ wocky_tls_session_verify_peer (WockyTLSSession *session, gnutls_certificate_get_peers (session->session, &cls); gnutls_x509_crt_import (x509, &peers[0], GNUTLS_X509_FMT_DER); - rval = gnutls_x509_crt_check_hostname (x509, peername); - DEBUG ("gnutls_x509_crt_check_hostname: %s -> %d", peername, rval); + rval = gnutls_x509_crt_check_hostname (x509, session->peername); + DEBUG ("gnutls_x509_crt_check_hostname: %s -> %d", session->peername, rval); rval = (rval == 0) ? -1 : GNUTLS_E_SUCCESS; peer_name_ok = (rval == GNUTLS_E_SUCCESS); @@ -775,8 +778,8 @@ wocky_tls_session_verify_peer (WockyTLSSession *session, gnutls_certificate_get_peers (session->session, &cls); gnutls_openpgp_crt_import (opgp, &peers[0], GNUTLS_OPENPGP_FMT_RAW); - rval = gnutls_openpgp_crt_check_hostname (opgp, peername); - DEBUG ("gnutls_openpgp_crt_check_hostname: %s -> %d",peername,rval); + rval = gnutls_openpgp_crt_check_hostname (opgp, session->peername); + DEBUG ("gnutls_openpgp_crt_check_hostname: %s -> %d",session->peername,rval); rval = (rval == 0) ? -1 : GNUTLS_E_SUCCESS; peer_name_ok = (rval == GNUTLS_E_SUCCESS); @@ -1357,6 +1360,9 @@ wocky_tls_session_set_property (GObject *object, guint prop_id, case PROP_S_STREAM: session->stream = g_value_dup_object (value); break; + case PROP_S_PEERNAME: + session->peername = g_value_dup_string (value); + break; case PROP_S_SERVER: session->server = g_value_get_boolean (value); break; @@ -1374,6 +1380,22 @@ wocky_tls_session_set_property (GObject *object, guint prop_id, } } +static void +wocky_tls_session_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + WockyTLSSession *session = WOCKY_TLS_SESSION (object); + + switch (prop_id) + { + case PROP_S_PEERNAME: + g_value_set_string (value, session->peername); + break; + default: + g_assert_not_reached (); + } +} + static const char * tls_options (void) { @@ -1492,6 +1514,9 @@ wocky_tls_session_dispose (GObject *object) { WockyTLSSession *session = WOCKY_TLS_SESSION (object); + g_free (session->peername); + session->peername = NULL; + g_free (session->key_file); session->key_file = NULL; @@ -1507,6 +1532,7 @@ wocky_tls_session_dispose (GObject *object) static void wocky_tls_session_class_init (GObjectClass *class) { + class->get_property = wocky_tls_session_get_property; class->set_property = wocky_tls_session_set_property; class->constructed = wocky_tls_session_constructed; class->finalize = wocky_tls_session_finalize; @@ -1519,6 +1545,13 @@ wocky_tls_session_class_init (GObjectClass *class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + g_object_class_install_property (class, PROP_S_PEERNAME, + g_param_spec_string ("peername", "peer name", + "Peer host/domain name", + NULL, G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + g_object_class_install_property (class, PROP_S_SERVER, g_param_spec_boolean ("server", "server", "whether this is a server", @@ -1659,10 +1692,12 @@ wocky_tls_connection_class_init (WockyTLSConnectionClass *class) } WockyTLSSession * -wocky_tls_session_new (GIOStream *stream) +wocky_tls_session_new (GIOStream *stream, + const gchar *peername) { return g_object_new (WOCKY_TYPE_TLS_SESSION, "base-stream", stream, + "peername", peername, "server", FALSE, NULL); } diff --git a/wocky/wocky-tls.h b/wocky/wocky-tls.h index e4fce23..95eea55 100644 --- a/wocky/wocky-tls.h +++ b/wocky/wocky-tls.h @@ -81,7 +81,6 @@ GType wocky_tls_connection_get_type (void); GType wocky_tls_session_get_type (void); int wocky_tls_session_verify_peer (WockyTLSSession *session, - const gchar *peername, WockyTLSVerificationLevel level, WockyTLSCertStatus *status); GPtrArray *wocky_tls_session_get_peers_certificate (WockyTLSSession *session, @@ -104,7 +103,8 @@ wocky_tls_session_handshake_finish (WockyTLSSession *session, void wocky_tls_session_add_ca (WockyTLSSession *session, const gchar *path); void wocky_tls_session_add_crl (WockyTLSSession *session, const gchar *path); -WockyTLSSession *wocky_tls_session_new (GIOStream *stream); +WockyTLSSession *wocky_tls_session_new (GIOStream *stream, + const gchar *peername); WockyTLSSession *wocky_tls_session_server_new (GIOStream *stream, guint dhbits, -- 1.7.3.1