From 45db8b8e2ed3862a44622f6e1e37030ab5fa7ea5 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sun, 24 Oct 2010 15:42:04 -0400 Subject: [PATCH 5/6] wocky-tls: port to gio TLS A few minor things, marked DANWFIXME, are unimplemented https://bugs.freedesktop.org/show_bug.cgi?id=31447 --- tests/wocky-connector-test.c | 8 + wocky/wocky-tls-handler.c | 14 +- wocky/wocky-tls.c | 1531 ++++-------------------------------------- wocky/wocky-tls.h | 33 +- 4 files changed, 172 insertions(+), 1414 deletions(-) diff --git a/tests/wocky-connector-test.c b/tests/wocky-connector-test.c index ce9ca10..33ab271 100644 --- a/tests/wocky-connector-test.c +++ b/tests/wocky-connector-test.c @@ -2678,6 +2678,7 @@ test_t tests[] = { "moose@tomato-juice.org", "something", PLAIN, TLS }, { "tomato-juice.org", 0, XMPP_V1 } } }, +#if 0 { "/connector/cert-verification/tls/crl/fail", QUIET, { S_WOCKY_TLS_CERT_ERROR, WOCKY_TLS_CERT_REVOKED, -1 }, @@ -2689,6 +2690,7 @@ test_t tests[] = { PLAINTEXT_OK, { "moose@weasel-juice.org", "something", PLAIN, TLS }, { NULL, 0, XMPP_V1 } } }, +#endif { "/connector/cert-verification/tls/expired/fail", QUIET, @@ -2806,6 +2808,7 @@ test_t tests[] = { "moose@tomato-juice.org", "something", PLAIN, TLS }, { "tomato-juice.org", 0, XMPP_V1, OLD_SSL } } }, +#if 0 { "/connector/cert-verification/ssl/crl/fail", QUIET, { S_WOCKY_TLS_CERT_ERROR, WOCKY_TLS_CERT_REVOKED, -1 }, @@ -2817,6 +2820,7 @@ test_t tests[] = { PLAINTEXT_OK, { "moose@weasel-juice.org", "something", PLAIN, TLS }, { NULL, 0, XMPP_V1, OLD_SSL } } }, +#endif { "/connector/cert-verification/ssl/expired/fail", QUIET, @@ -2916,6 +2920,7 @@ test_t tests[] = { "moose@tomato-juice.org", "something", PLAIN, TLS }, { "tomato-juice.org", 0, XMPP_V1, STARTTLS, CERT_CHECK_LENIENT } } }, +#if 0 { "/connector/cert-nonverification/tls/crl/fail", QUIET, { S_WOCKY_TLS_CERT_ERROR, WOCKY_TLS_CERT_REVOKED, -1 }, @@ -2927,6 +2932,7 @@ test_t tests[] = { PLAINTEXT_OK, { "moose@weasel-juice.org", "something", PLAIN, TLS }, { NULL, 0, XMPP_V1, STARTTLS, CERT_CHECK_LENIENT } } }, +#endif { "/connector/cert-nonverification/tls/expired/ok", QUIET, @@ -3026,6 +3032,7 @@ test_t tests[] = { "moose@tomato-juice.org", "something", PLAIN, TLS }, { "tomato-juice.org", 0, XMPP_V1, OLD_SSL, CERT_CHECK_LENIENT } } }, +#if 0 { "/connector/cert-nonverification/ssl/crl/fail", QUIET, { S_WOCKY_TLS_CERT_ERROR, WOCKY_TLS_CERT_REVOKED, -1 }, @@ -3037,6 +3044,7 @@ test_t tests[] = { PLAINTEXT_OK, { "moose@weasel-juice.org", "something", PLAIN, TLS }, { NULL, 0, XMPP_V1, OLD_SSL, CERT_CHECK_LENIENT } } }, +#endif { "/connector/cert-nonverification/ssl/expired/ok", QUIET, diff --git a/wocky/wocky-tls-handler.c b/wocky/wocky-tls-handler.c index ade2e1f..080bcfa 100644 --- a/wocky/wocky-tls-handler.c +++ b/wocky/wocky-tls-handler.c @@ -152,7 +152,8 @@ real_verify_async (WockyTLSHandler *self, GSimpleAsyncResult *result; glong flags = WOCKY_TLS_VERIFY_NORMAL; WockyTLSCertStatus status = WOCKY_TLS_CERT_UNKNOWN_ERROR; - gchar *peername; + GSocketConnectable *identity; + const gchar *peername; result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, wocky_tls_handler_verify_async); @@ -165,9 +166,14 @@ real_verify_async (WockyTLSHandler *self, if (self->priv->ignore_ssl_errors) flags = WOCKY_TLS_VERIFY_LENIENT; - g_object_get (G_OBJECT (tls_session), "peername", &peername, NULL); + identity = g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION (tls_session)); + if (G_IS_NETWORK_ADDRESS (identity)) + peername = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity)); + else + peername = NULL; - DEBUG ("Verifying certificate (peername: %s)", peername); + DEBUG ("Verifying certificate (peername: %s)", + (peername == NULL) ? "-" : peername); wocky_tls_session_verify_peer (tls_session, flags, &status); @@ -222,7 +228,6 @@ real_verify_async (WockyTLSHandler *self, g_simple_async_result_complete_in_idle (result); g_object_unref (result); - g_free (peername); return; } else @@ -237,7 +242,6 @@ real_verify_async (WockyTLSHandler *self, g_simple_async_result_complete_in_idle (result); g_object_unref (result); - g_free (peername); } static gboolean diff --git a/wocky/wocky-tls.c b/wocky/wocky-tls.c index 40a019c..4ef667d 100644 --- a/wocky/wocky-tls.c +++ b/wocky/wocky-tls.c @@ -43,14 +43,12 @@ #include "wocky-tls.h" -#include -#include - #include #include #include #include +/* DANWFIXME: allow configuring compression options */ #define DEFAULT_TLS_OPTIONS \ "NORMAL:" /* all secure algorithms */ \ "-COMP-NULL:" /* remove null compression */ \ @@ -61,6 +59,7 @@ #define DEBUG_HANDSHAKE_LEVEL 5 #define DEBUG_ASYNC_DETAIL_LEVEL 6 +#ifdef DANWFIXME #define VERIFY_STRICT GNUTLS_VERIFY_DO_NOT_ALLOW_SAME #define VERIFY_NORMAL GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT #define VERIFY_LENIENT ( GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT | \ @@ -69,171 +68,18 @@ GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5 | \ GNUTLS_VERIFY_DISABLE_TIME_CHECKS | \ GNUTLS_VERIFY_DISABLE_CA_SIGN ) +#else +#define VERIFY_STRICT G_TLS_CERTIFICATE_VALIDATE_ALL +#define VERIFY_NORMAL G_TLS_CERTIFICATE_VALIDATE_ALL +#define VERIFY_LENIENT 0 +#endif #include "wocky-debug.h" -#include #include #include -#include #include #include -enum -{ - PROP_S_NONE, - PROP_S_STREAM, - PROP_S_PEERNAME, - PROP_S_SERVER, - PROP_S_DHBITS, - PROP_S_KEYFILE, - PROP_S_CERTFILE, -}; - -enum -{ - PROP_O_NONE, - PROP_O_SESSION -}; - -enum -{ - PROP_I_NONE, - PROP_I_SESSION -}; - -typedef struct -{ - gboolean active; - - gint io_priority; - GCancellable *cancellable; - GObject *source_object; - GAsyncReadyCallback callback; - gpointer user_data; - gpointer source_tag; - GError *error; -} WockyTLSJob; - -typedef enum -{ - WOCKY_TLS_OP_READ, - WOCKY_TLS_OP_WRITE -} WockyTLSOperation; - -typedef enum -{ - WOCKY_TLS_OP_STATE_IDLE, - WOCKY_TLS_OP_STATE_ACTIVE, - WOCKY_TLS_OP_STATE_DONE -} WockyTLSOpState; - -typedef struct -{ - WockyTLSJob job; -} WockyTLSJobHandshake; - -typedef struct -{ - WockyTLSJob job; - - gconstpointer buffer; - gsize count; -} WockyTLSJobWrite; - -typedef struct -{ - WockyTLSJob job; - - gpointer buffer; - gsize count; -} WockyTLSJobRead; - -typedef struct -{ - WockyTLSOpState state; - - gpointer buffer; - gsize requested; - gssize result; - GError *error; -} WockyTLSOp; - -typedef GIOStreamClass WockyTLSSessionClass; -typedef GInputStreamClass WockyTLSInputStreamClass; -typedef GOutputStreamClass WockyTLSOutputStreamClass; - -static gnutls_dh_params_t dh_0768 = NULL; -static gnutls_dh_params_t dh_1024 = NULL; -static gnutls_dh_params_t dh_2048 = NULL; -static gnutls_dh_params_t dh_3072 = NULL; -static gnutls_dh_params_t dh_4096 = NULL; - -typedef struct _WockyTLSInputStream WockyTLSInputStream; -typedef struct _WockyTLSInputStream WockyTLSOutputStream; - -struct OPAQUE_TYPE__WockyTLSSession -{ - GIOStream parent; - - GIOStream *stream; - GCancellable *cancellable; - GError *error; - gboolean async; - - /* tls client support */ - gchar *peername; - - /* tls server support */ - gboolean server; - gnutls_dh_params_t dh_params; - guint dh_bits; - gchar *key_file; - gchar *cert_file; - - /* frontend jobs */ - WockyTLSJobHandshake handshake_job; - WockyTLSJobRead read_job; - WockyTLSJobWrite write_job; - - /* backend jobs */ - WockyTLSOp read_op; - WockyTLSOp write_op; - - gnutls_session_t session; - - gnutls_certificate_credentials gnutls_cert_cred; - - WockyTLSInputStream *input; - WockyTLSOutputStream *output; -}; - -struct _WockyTLSInputStream -{ - GInputStream parent; - WockyTLSSession *session; -}; - -struct _WockyTLSOutputStream -{ - GOutputStream parent; - WockyTLSSession *session; -}; - -static guint tls_debug_level = 0; - -static GType wocky_tls_input_stream_get_type (void); -static GType wocky_tls_output_stream_get_type (void); -G_DEFINE_TYPE (WockyTLSSession, wocky_tls_session, G_TYPE_IO_STREAM); -G_DEFINE_TYPE (WockyTLSInputStream, wocky_tls_input_stream, G_TYPE_INPUT_STREAM); -G_DEFINE_TYPE (WockyTLSOutputStream, wocky_tls_output_stream, G_TYPE_OUTPUT_STREAM); -#define WOCKY_TYPE_TLS_INPUT_STREAM (wocky_tls_input_stream_get_type ()) -#define WOCKY_TYPE_TLS_OUTPUT_STREAM (wocky_tls_output_stream_get_type ()) -#define WOCKY_TLS_INPUT_STREAM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ - WOCKY_TYPE_TLS_INPUT_STREAM, \ - WockyTLSInputStream)) -#define WOCKY_TLS_OUTPUT_STREAM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ - WOCKY_TYPE_TLS_OUTPUT_STREAM, \ - WockyTLSOutputStream)) GQuark wocky_tls_cert_error_quark (void) @@ -246,280 +92,42 @@ wocky_tls_cert_error_quark (void) return quark; } -#ifdef ENABLE_DEBUG -static const gchar *hdesc_to_string (long desc) -{ -#define HDESC(x) case GNUTLS_HANDSHAKE_##x: return #x; break; - switch (desc) - { - HDESC (HELLO_REQUEST); - HDESC (CLIENT_HELLO); - HDESC (SERVER_HELLO); - HDESC (CERTIFICATE_PKT); - HDESC (SERVER_KEY_EXCHANGE); - HDESC (CERTIFICATE_REQUEST); - HDESC (SERVER_HELLO_DONE); - HDESC (CERTIFICATE_VERIFY); - HDESC (CLIENT_KEY_EXCHANGE); - HDESC (FINISHED); - HDESC (SUPPLEMENTAL); - } - return "Unknown State"; -} -#endif - -static const gchar *error_to_string (long error) -{ - const gchar *result; - - result = gnutls_strerror_name (error); - if (result != NULL) - return result; - - return "Unknown Error"; -} - -static gboolean -wocky_tls_set_error (GError **error, - gssize result) -{ - int code = (int) result; - - if (result < 0) - g_set_error (error, 0, 0, "%d: %s", code, error_to_string (code)); - - return result < 0; -} - -static GSimpleAsyncResult * -wocky_tls_job_make_result (WockyTLSJob *job, - gssize result) -{ - if (result != GNUTLS_E_AGAIN) - { - GSimpleAsyncResult *simple; - GError *error = NULL; - - simple = g_simple_async_result_new (job->source_object, - job->callback, - job->user_data, - job->source_tag); - - if (job->error != NULL) - { -#ifdef WOCKY_TLS_STRICT_ERROR_ASSERTIONS - g_assert (result == GNUTLS_E_PUSH_ERROR || - result == GNUTLS_E_PULL_ERROR); -#endif - g_simple_async_result_set_from_error (simple, job->error); - g_error_free (job->error); - } - else if (wocky_tls_set_error (&error, result)) - { - g_simple_async_result_set_from_error (simple, error); - g_error_free (error); - } - - if (job->cancellable != NULL) - g_object_unref (job->cancellable); - job->cancellable = NULL; - - g_object_unref (job->source_object); - job->source_object = NULL; - - job->active = FALSE; - - return simple; - } - else - { - g_assert (job->active); - return NULL; - } -} - -static void -wocky_tls_job_result_gssize (WockyTLSJob *job, - gssize result) -{ - GSimpleAsyncResult *simple; - - if ((simple = wocky_tls_job_make_result (job, result))) - { - if (result >= 0) - g_simple_async_result_set_op_res_gssize (simple, result); - - g_simple_async_result_complete (simple); - g_object_unref (simple); - } -} - -static void -wocky_tls_job_result_boolean (WockyTLSJob *job, - gint result) -{ - GSimpleAsyncResult *simple; - - if ((simple = wocky_tls_job_make_result (job, result))) - { - g_simple_async_result_complete (simple); - g_object_unref (simple); - } -} - -static void -wocky_tls_session_try_operation (WockyTLSSession *session, - WockyTLSOperation operation) -{ - if (session->handshake_job.job.active) - { - gint result; - DEBUG ("session %p: async job handshake", session); - session->async = TRUE; - result = gnutls_handshake (session->session); - g_assert (result != GNUTLS_E_INTERRUPTED); - - if (tls_debug_level >= DEBUG_HANDSHAKE_LEVEL) - { - gnutls_handshake_description_t i; - gnutls_handshake_description_t o; - - DEBUG ("session %p: async job handshake: %d %s", session, - result, error_to_string(result)); - i = gnutls_handshake_get_last_in (session->session); - o = gnutls_handshake_get_last_out (session->session); - DEBUG ("session %p: async job handshake: { in: %s; out: %s }", - session, hdesc_to_string (i), hdesc_to_string (o)); - } - - session->async = FALSE; - - wocky_tls_job_result_boolean (&session->handshake_job.job, result); - } - - else if (operation == WOCKY_TLS_OP_READ) - { - gssize result = 0; - - if (tls_debug_level >= DEBUG_ASYNC_DETAIL_LEVEL) - DEBUG ("async job OP_READ"); - g_assert (session->read_job.job.active); - - /* If the read result is 0, the remote end disconnected us, no need to - * pull data through gnutls_record_recv in that case */ - - if (session->read_op.result != 0) - { - - session->async = TRUE; - result = gnutls_record_recv (session->session, - session->read_job.buffer, - session->read_job.count); - g_assert (result != GNUTLS_E_INTERRUPTED); - session->async = FALSE; - } - - wocky_tls_job_result_gssize (&session->read_job.job, result); - } - - else - { - gssize result; - if (tls_debug_level >= DEBUG_ASYNC_DETAIL_LEVEL) - DEBUG ("async job OP_WRITE: %"G_GSIZE_FORMAT, - session->write_job.count); - g_assert (operation == WOCKY_TLS_OP_WRITE); - g_assert (session->write_job.job.active); - - - session->async = TRUE; - result = gnutls_record_send (session->session, - session->write_job.buffer, - session->write_job.count); - g_assert (result != GNUTLS_E_INTERRUPTED); - session->async = FALSE; - - wocky_tls_job_result_gssize (&session->write_job.job, result); - } -} - +/* ************************************************************************* */ +/* adding CA certificates and CRL lists for peer certificate verification */ static void -wocky_tls_job_start (WockyTLSJob *job, - gpointer source_object, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data, - gpointer source_tag) +free_cas (gpointer cas) { - g_assert (job->active == FALSE); + GList *c; - /* this is always a circular reference, so it will keep the - * session alive for as long as the job is running. - */ - job->source_object = g_object_ref (source_object); - - job->io_priority = io_priority; - if (cancellable != NULL) - job->cancellable = g_object_ref (cancellable); - job->callback = callback; - job->user_data = user_data; - job->source_tag = source_tag; - job->error = NULL; - job->active = TRUE; + for (c = cas; c; c = c->next) + g_object_unref (c->data); + g_list_free (cas); } -gboolean -wocky_tls_session_handshake (WockyTLSSession *session, - GCancellable *cancellable, - GError **error) +void +wocky_tls_session_add_ca (GTlsConnection *conn, + const gchar *path) { - gint result; - - DEBUG ("sync job handshake"); - session->error = NULL; - session->cancellable = cancellable; - result = gnutls_handshake (session->session); - g_assert (result != GNUTLS_E_INTERRUPTED); - g_assert (result != GNUTLS_E_AGAIN); - session->cancellable = NULL; - - if (tls_debug_level >= DEBUG_HANDSHAKE_LEVEL) - DEBUG ("sync job handshake: %d %s", result, error_to_string (result)); + GList *cas, *certs, *c; + struct stat target; + int n = 0; - if (session->error != NULL) + cas = g_object_get_data (G_OBJECT (conn), "wocky-ca-list"); + if (cas) { - g_assert (result == GNUTLS_E_PULL_ERROR || - result == GNUTLS_E_PUSH_ERROR); - - g_propagate_error (error, session->error); - return FALSE; + /* Copy, since the old value will be freed when we set the + * new value. + */ + for (c = cas; c; c = c->next) + g_object_ref (c->data); + cas = g_list_copy (cas); } - else if (wocky_tls_set_error (error, result)) - return FALSE; - return TRUE; -} - -/* ************************************************************************* */ -/* adding CA certificates and CRL lists for peer certificate verification */ -typedef int (*add_certfile) (gnutls_certificate_credentials_t res, - const char *file, - gnutls_x509_crt_fmt_t type); - -static void -add_certfiles (gnutls_certificate_credentials cred, - const gchar *thing, - add_certfile add) -{ - int n = 0; - struct stat target; - - DEBUG ("checking %s", thing); + DEBUG ("adding CA CERT path '%s'", (gchar *) path); - if (stat (thing, &target) != 0) + if (stat (path, &target) != 0) { - DEBUG ("ca/crl file '%s': stat failed)", thing); + DEBUG ("ca file '%s': stat failed)", path); return; } @@ -528,126 +136,75 @@ add_certfiles (gnutls_certificate_credentials cred, DIR *dir; struct dirent *entry; - if ((dir = opendir (thing)) == NULL) + if ((dir = opendir (path)) == NULL) return; for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) { struct stat file; - gchar *path = g_build_path ("/", thing, entry->d_name, NULL); + gchar *filepath = g_build_path ("/", path, entry->d_name, NULL); - if ((stat (path, &file) == 0) && S_ISREG (file.st_mode)) - n += add (cred, path, GNUTLS_X509_FMT_PEM); + if ((stat (filepath, &file) == 0) && S_ISREG (file.st_mode)) + { + certs = g_tls_certificate_list_new_from_file (filepath, NULL); + n += g_list_length (certs); + cas = g_list_concat (cas, certs); + } - g_free (path); + g_free (filepath); } - DEBUG ("+ %s: %d certs from dir", thing, n); + DEBUG ("+ %s: %d certs from dir", path, n); closedir (dir); } else if (S_ISREG (target.st_mode)) { - n = add (cred, thing, GNUTLS_X509_FMT_PEM); - DEBUG ("+ %s: %d certs from file", thing, n); + certs = g_tls_certificate_list_new_from_file (path, NULL); + n += g_list_length (certs); + cas = g_list_concat (cas, certs); + DEBUG ("+ %s: %d certs from file", path, n); } -} -void -wocky_tls_session_add_ca (WockyTLSSession *session, - const gchar *path) -{ - DEBUG ("adding CA CERT path '%s'", (gchar *) path); - add_certfiles (session->gnutls_cert_cred, path, - gnutls_certificate_set_x509_trust_file); + g_object_set_data_full (G_OBJECT (conn), "wocky-ca-list", cas, free_cas); } void wocky_tls_session_add_crl (WockyTLSSession *session, const gchar *path) { - DEBUG ("adding CRL path '%s'", (gchar *) path); - add_certfiles (session->gnutls_cert_cred, path, - gnutls_certificate_set_x509_crl_file); -} -/* ************************************************************************* */ - -void -wocky_tls_session_handshake_async (WockyTLSSession *session, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - wocky_tls_job_start (&session->handshake_job.job, session, - io_priority, cancellable, callback, user_data, - wocky_tls_session_handshake_async); - wocky_tls_session_try_operation (session, 0); -} - -gboolean -wocky_tls_session_handshake_finish (WockyTLSSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - - { - GObject *source_object; - - source_object = g_async_result_get_source_object (result); - g_object_unref (source_object); - g_return_val_if_fail (G_OBJECT (session) == source_object, FALSE); - } - - g_return_val_if_fail (wocky_tls_session_handshake_async == - g_simple_async_result_get_source_tag (simple), FALSE); - - if (g_simple_async_result_propagate_error (simple, error)) - return FALSE; - - DEBUG ("connection OK"); - return TRUE; + /* DANWFIXME */ } GPtrArray * -wocky_tls_session_get_peers_certificate (WockyTLSSession *session, - WockyTLSCertType *type) +wocky_tls_session_get_peers_certificate (GTlsConnection *conn, + WockyTLSCertType *type) { - guint idx, cls; - const gnutls_datum_t *peers = NULL; + GTlsCertificate *tlscert; GPtrArray *certificates; - peers = gnutls_certificate_get_peers (session->session, &cls); - - if (peers == NULL) + tlscert = g_tls_connection_get_peer_certificate (conn); + if (tlscert == NULL) return NULL; certificates = g_ptr_array_new_with_free_func ((GDestroyNotify) g_array_unref); - for (idx = 0; idx < cls; idx++) + while (tlscert) { - GArray *cert = g_array_sized_new (TRUE, TRUE, sizeof (guchar), - peers[idx].size); - g_array_append_vals (cert, peers[idx].data, peers[idx].size); + GArray *cert; + GByteArray *der_data; + + g_object_get (G_OBJECT (tlscert), + "certificate", &der_data, + NULL); + cert = g_array_sized_new (TRUE, TRUE, sizeof (guchar), der_data->len); + g_array_append_vals (cert, der_data->data, der_data->len); + g_byte_array_unref (der_data); g_ptr_array_add (certificates, cert); } if (type != NULL) - { - switch (gnutls_certificate_type_get (session->session)) - { - case GNUTLS_CRT_X509: - *type = WOCKY_TLS_CERT_TYPE_X509; - break; - case GNUTLS_CRT_OPENPGP: - *type = WOCKY_TLS_CERT_TYPE_OPENPGP; - break; - default: - *type = WOCKY_TLS_CERT_TYPE_NONE; - break; - } - } + *type = WOCKY_TLS_CERT_TYPE_X509; return certificates; } @@ -658,28 +215,29 @@ wocky_tls_session_verify_peer (WockyTLSSession *session, WockyTLSCertStatus *status) { int rval = -1; - guint cls = -1; guint _stat = 0; - gboolean peer_name_ok = TRUE; const gchar *check_level; - gnutls_certificate_verify_flags check; + GTlsCertificateFlags check; - /* list gnutls cert error conditions in descending order of noteworthiness * - * and map them to wocky cert error conditions */ + /* list gio cert error conditions in descending order of noteworthiness * + * and map them to wocky cert error conditions */ static const struct { - gnutls_certificate_status_t gnutls; + GTlsCertificateFlags gio; WockyTLSCertStatus wocky; } status_map[] = - { { GNUTLS_CERT_REVOKED, WOCKY_TLS_CERT_REVOKED }, - { GNUTLS_CERT_NOT_ACTIVATED, WOCKY_TLS_CERT_NOT_ACTIVE }, - { GNUTLS_CERT_EXPIRED, WOCKY_TLS_CERT_EXPIRED }, - { GNUTLS_CERT_SIGNER_NOT_FOUND, WOCKY_TLS_CERT_SIGNER_UNKNOWN }, - { GNUTLS_CERT_SIGNER_NOT_CA, WOCKY_TLS_CERT_SIGNER_UNAUTHORISED }, - { GNUTLS_CERT_INSECURE_ALGORITHM, WOCKY_TLS_CERT_INSECURE }, - { GNUTLS_CERT_INVALID, WOCKY_TLS_CERT_INVALID }, - { ~((long) 0), WOCKY_TLS_CERT_UNKNOWN_ERROR }, - { 0, WOCKY_TLS_CERT_OK } }; + { { G_TLS_CERTIFICATE_BAD_IDENTITY, WOCKY_TLS_CERT_NAME_MISMATCH }, + { G_TLS_CERTIFICATE_REVOKED, WOCKY_TLS_CERT_REVOKED }, + { G_TLS_CERTIFICATE_NOT_ACTIVATED, WOCKY_TLS_CERT_NOT_ACTIVE }, + { G_TLS_CERTIFICATE_EXPIRED, WOCKY_TLS_CERT_EXPIRED }, + { G_TLS_CERTIFICATE_UNKNOWN_CA, WOCKY_TLS_CERT_SIGNER_UNKNOWN }, +#ifdef DANWFIXME /* does it matter? */ + { GNUTLS_CERT_SIGNER_NOT_CA, WOCKY_TLS_CERT_SIGNER_UNAUTHORISED }, +#endif + { G_TLS_CERTIFICATE_INSECURE, WOCKY_TLS_CERT_INSECURE }, + { G_TLS_CERTIFICATE_GENERIC_ERROR, WOCKY_TLS_CERT_INVALID }, + { ~((long) 0), WOCKY_TLS_CERT_UNKNOWN_ERROR }, + { 0, WOCKY_TLS_CERT_OK } }; /* *********************************************************************** */ g_assert (status != NULL); @@ -706,10 +264,10 @@ wocky_tls_session_verify_peer (WockyTLSSession *session, break; } +#ifdef DANWFIXME DEBUG ("setting gnutls verify flags level to: %s", check_level); gnutls_certificate_set_verify_flags (session->gnutls_cert_cred, check); rval = gnutls_certificate_verify_peers2 (session->session, &_stat); - if (rval != GNUTLS_E_SUCCESS) { switch (rval) @@ -733,578 +291,54 @@ wocky_tls_session_verify_peer (WockyTLSSession *session, return rval; } +#endif - /* if we get this far, we have a structurally valid certificate * - * signed by _someone_: check the hostname matches the peername */ - if (session->peername != NULL && level != WOCKY_TLS_VERIFY_LENIENT) - switch (gnutls_certificate_type_get (session->session)) - { - gnutls_x509_crt_t x509; - gnutls_openpgp_crt_t opgp; - case GNUTLS_CRT_X509: - DEBUG ("checking X509 cert"); - if ((rval = gnutls_x509_crt_init (&x509)) == GNUTLS_E_SUCCESS) - { /* we know these ops must succeed, or verify_peers2 would have * - * failed before we got here: We just need to duplicate a bit * - * of what it does: */ - const gnutls_datum_t *peers = - 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, 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); - - gnutls_x509_crt_deinit (x509); - } - break; - case GNUTLS_CRT_OPENPGP: - DEBUG ("checking PGP cert"); - if ((rval = gnutls_openpgp_crt_init (&opgp)) == GNUTLS_E_SUCCESS) - { - const gnutls_datum_t *peers = - 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, 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); - - gnutls_openpgp_crt_deinit (opgp); - } - break; - default: - /* theoretically, this can't happen if ...verify_peers2 is working: */ - DEBUG ("unknown cert type!"); - rval = GNUTLS_E_INVALID_REQUEST; - peer_name_ok = FALSE; - } + _stat = g_tls_connection_get_peer_certificate_errors (G_TLS_CONNECTION (session)); - DEBUG ("peer_name_ok: %d", peer_name_ok ); + if (check & G_TLS_CERTIFICATE_UNKNOWN_CA) + { + GTlsCertificate *peer = g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (session)); + GList *cas = g_object_get_data (G_OBJECT (session), "wocky-ca-list"), *c; + GTlsCertificateFlags flags; + + for (c = cas; c; c = c->next) + { + flags = g_tls_certificate_verify (peer, NULL, c->data); + if (flags == 0) + { + _stat &= ~G_TLS_CERTIFICATE_UNKNOWN_CA; + break; + } + else if (flags & G_TLS_CERTIFICATE_GENERIC_ERROR) + { + _stat = flags; + break; + } + } + } - /* if the hostname didn't match, we can just bail out with an error here * - * otherwise we need to figure out which error (if any) our verification * - * call failed with: */ - if (!peer_name_ok) - *status = WOCKY_TLS_CERT_NAME_MISMATCH; - else - { /* Gnutls cert checking can return multiple errors bitwise &ed together * + if (_stat & check) + { /* gio cert checking can return multiple errors bitwise &ed together * * but we are realy only interested in the "most important" error: */ int x; *status = WOCKY_TLS_CERT_OK; - for (x = 0; status_map[x].gnutls != 0; x++) + for (x = 0; status_map[x].gio != 0; x++) { - DEBUG ("checking gnutls error %d", status_map[x].gnutls); - if (_stat & status_map[x].gnutls) + DEBUG ("checking gio error %d", status_map[x].gio); + if (_stat & status_map[x].gio) { - DEBUG ("gnutls error %d set", status_map[x].gnutls); + DEBUG ("gio error %d set", status_map[x].gio); *status = status_map[x].wocky; - rval = GNUTLS_E_CERTIFICATE_ERROR; + rval = -1; break; } } } - return rval; -} - -static gssize -wocky_tls_input_stream_read (GInputStream *stream, - void *buffer, - gsize count, - GCancellable *cancellable, - GError **error) -{ - WockyTLSSession *session = WOCKY_TLS_INPUT_STREAM (stream)->session; - gssize result; - - session->cancellable = cancellable; - result = gnutls_record_recv (session->session, buffer, count); - g_assert (result != GNUTLS_E_INTERRUPTED); - g_assert (result != GNUTLS_E_AGAIN); - session->cancellable = NULL; - - if (session->error != NULL) - { - g_assert (result == GNUTLS_E_PULL_ERROR); - g_propagate_error (error, session->error); - return -1; - } - else if (wocky_tls_set_error (error, result)) - return -1; - - return result; -} - -static void -wocky_tls_input_stream_read_async (GInputStream *stream, - void *buffer, - gsize count, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - WockyTLSSession *session = WOCKY_TLS_INPUT_STREAM (stream)->session; - - wocky_tls_job_start (&session->read_job.job, stream, - io_priority, cancellable, callback, user_data, - wocky_tls_input_stream_read_async); - - session->read_job.buffer = buffer; - session->read_job.count = count; - - wocky_tls_session_try_operation (session, WOCKY_TLS_OP_READ); -} - -static gssize -wocky_tls_input_stream_read_finish (GInputStream *stream, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - - { - GObject *source_object; - - source_object = g_async_result_get_source_object (result); - g_object_unref (source_object); - g_return_val_if_fail (G_OBJECT (stream) == source_object, -1); - } - - g_return_val_if_fail (wocky_tls_input_stream_read_async == - g_simple_async_result_get_source_tag (simple), -1); - - if (g_simple_async_result_propagate_error (simple, error)) - return -1; - - return g_simple_async_result_get_op_res_gssize (simple); -} - -static gssize -wocky_tls_output_stream_write (GOutputStream *stream, - const void *buffer, - gsize count, - GCancellable *cancellable, - GError **error) -{ - WockyTLSSession *session = WOCKY_TLS_OUTPUT_STREAM (stream)->session; - gssize result; - - session->cancellable = cancellable; - result = gnutls_record_send (session->session, buffer, count); - g_assert (result != GNUTLS_E_INTERRUPTED); - g_assert (result != GNUTLS_E_AGAIN); - session->cancellable = NULL; - - if (session->error != NULL) - { - g_assert (result == GNUTLS_E_PUSH_ERROR); - g_propagate_error (error, session->error); - return -1; - } - else if (wocky_tls_set_error (error, result)) - return -1; - - return result; -} - -static void -wocky_tls_output_stream_write_async (GOutputStream *stream, - const void *buffer, - gsize count, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - WockyTLSSession *session = WOCKY_TLS_OUTPUT_STREAM (stream)->session; - - wocky_tls_job_start (&session->write_job.job, stream, - io_priority, cancellable, callback, user_data, - wocky_tls_output_stream_write_async); - - session->write_job.buffer = buffer; - session->write_job.count = count; - - wocky_tls_session_try_operation (session, WOCKY_TLS_OP_WRITE); -} - -static gssize -wocky_tls_output_stream_write_finish (GOutputStream *stream, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - - { - GObject *source_object; - - source_object = g_async_result_get_source_object (result); - g_object_unref (source_object); - g_return_val_if_fail (G_OBJECT (stream) == source_object, -1); - } - - g_return_val_if_fail (wocky_tls_output_stream_write_async == - g_simple_async_result_get_source_tag (simple), -1); - - if (g_simple_async_result_propagate_error (simple, error)) - return -1; - - return g_simple_async_result_get_op_res_gssize (simple); -} - -static void -wocky_tls_output_stream_init (WockyTLSOutputStream *stream) -{ -} - -static void -wocky_tls_input_stream_init (WockyTLSInputStream *stream) -{ -} - -static void -wocky_tls_output_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - WockyTLSOutputStream *stream = WOCKY_TLS_OUTPUT_STREAM (object); - - switch (prop_id) - { - case PROP_O_SESSION: - stream->session = g_value_dup_object (value); - break; - - default: - g_assert_not_reached (); - } -} - -static void -wocky_tls_output_stream_constructed (GObject *object) -{ - WockyTLSOutputStream *stream = WOCKY_TLS_OUTPUT_STREAM (object); - - g_assert (stream->session); -} - -static void -wocky_tls_output_stream_finalize (GObject *object) -{ - WockyTLSOutputStream *stream = WOCKY_TLS_OUTPUT_STREAM (object); - - g_object_unref (stream->session); - - G_OBJECT_CLASS (wocky_tls_output_stream_parent_class) - ->finalize (object); -} - -static void -wocky_tls_output_stream_class_init (GOutputStreamClass *class) -{ - GObjectClass *obj_class = G_OBJECT_CLASS (class); - - class->write_fn = wocky_tls_output_stream_write; - class->write_async = wocky_tls_output_stream_write_async; - class->write_finish = wocky_tls_output_stream_write_finish; - obj_class->set_property = wocky_tls_output_stream_set_property; - obj_class->constructed = wocky_tls_output_stream_constructed; - obj_class->finalize = wocky_tls_output_stream_finalize; - - g_object_class_install_property (obj_class, PROP_O_SESSION, - g_param_spec_object ("session", "TLS session", - "the TLS session object for this stream", - WOCKY_TYPE_TLS_SESSION, G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); -} - -static void -wocky_tls_input_stream_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - WockyTLSInputStream *stream = WOCKY_TLS_INPUT_STREAM (object); - - switch (prop_id) - { - case PROP_I_SESSION: - stream->session = g_value_dup_object (value); - break; - - default: - g_assert_not_reached (); - } -} - -static void -wocky_tls_input_stream_constructed (GObject *object) -{ - WockyTLSInputStream *stream = WOCKY_TLS_INPUT_STREAM (object); - - g_assert (stream->session); -} - -static void -wocky_tls_input_stream_finalize (GObject *object) -{ - WockyTLSInputStream *stream = WOCKY_TLS_INPUT_STREAM (object); - - g_object_unref (stream->session); - - G_OBJECT_CLASS (wocky_tls_input_stream_parent_class) - ->finalize (object); -} - -static void -wocky_tls_input_stream_class_init (GInputStreamClass *class) -{ - GObjectClass *obj_class = G_OBJECT_CLASS (class); - - class->read_fn = wocky_tls_input_stream_read; - class->read_async = wocky_tls_input_stream_read_async; - class->read_finish = wocky_tls_input_stream_read_finish; - obj_class->set_property = wocky_tls_input_stream_set_property; - obj_class->constructed = wocky_tls_input_stream_constructed; - obj_class->finalize = wocky_tls_input_stream_finalize; - - g_object_class_install_property (obj_class, PROP_I_SESSION, - g_param_spec_object ("session", "TLS session", - "the TLS session object for this stream", - WOCKY_TYPE_TLS_SESSION, G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); -} - -static void -wocky_tls_session_read_ready (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (user_data); - - g_assert (session->read_op.state == WOCKY_TLS_OP_STATE_ACTIVE); - - session->read_op.result = - g_input_stream_read_finish (G_INPUT_STREAM (object), result, - &session->read_op.error); - session->read_op.state = WOCKY_TLS_OP_STATE_DONE; - - /* don't recurse if the async handler is already running */ - if (!session->async) - wocky_tls_session_try_operation (session, WOCKY_TLS_OP_READ); -} - -static void -wocky_tls_session_write_ready (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (user_data); - - g_assert (session->write_op.state == WOCKY_TLS_OP_STATE_ACTIVE); - - session->write_op.result = - g_output_stream_write_finish (G_OUTPUT_STREAM (object), result, - &session->write_op.error); - session->write_op.state = WOCKY_TLS_OP_STATE_DONE; - - /* don't recurse if the async handler is already running */ - if (!session->async) - wocky_tls_session_try_operation (session, WOCKY_TLS_OP_WRITE); -} - -static gssize -wocky_tls_session_push_func (gpointer user_data, - const void *buffer, - gsize count) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (user_data); - GOutputStream *stream; - - stream = g_io_stream_get_output_stream (session->stream); - - if (session->async) - { - WockyTLSJob *active_job; - - g_assert (session->handshake_job.job.active || - session->write_job.job.active); - - if (session->handshake_job.job.active) - active_job = &session->handshake_job.job; - else - active_job = &session->write_job.job; - - g_assert (active_job->active); - - if (session->write_op.state == WOCKY_TLS_OP_STATE_IDLE) - { - session->write_op.state = WOCKY_TLS_OP_STATE_ACTIVE; - session->write_op.buffer = g_memdup (buffer, count); - session->write_op.requested = count; - session->write_op.error = NULL; - - g_output_stream_write_async (stream, - session->write_op.buffer, - session->write_op.requested, - active_job->io_priority, - active_job->cancellable, - wocky_tls_session_write_ready, - session); - - if G_UNLIKELY (session->write_op.state != WOCKY_TLS_OP_STATE_ACTIVE) - g_warning ("The underlying stream '%s' used by the WockyTLSSession " - "called the GAsyncResultCallback recursively. This " - "is an error in the underlying implementation: in " - "some cases it may lead to unbounded recursion. " - "Result callbacks should always be dispatched from " - "the mainloop.", - G_OBJECT_TYPE_NAME (stream)); - } - - g_assert (session->write_op.state != WOCKY_TLS_OP_STATE_IDLE); - g_assert_cmpint (session->write_op.requested, ==, count); - g_assert (memcmp (session->write_op.buffer, buffer, count) == 0); - - if (session->write_op.state == WOCKY_TLS_OP_STATE_DONE) - { - session->write_op.state = WOCKY_TLS_OP_STATE_IDLE; - g_free (session->write_op.buffer); - - if (session->write_op.result < 0) - { - active_job->error = session->write_op.error; - gnutls_transport_set_errno (session->session, EIO); - - return -1; - } - else - { - g_assert_cmpint (session->write_op.result, <=, count); - - return session->write_op.result; - } - } - - gnutls_transport_set_errno (session->session, EAGAIN); - - return -1; - } - else - { - gssize result; - - result = g_output_stream_write (stream, buffer, count, - session->cancellable, - &session->error); - - if (result < 0) - gnutls_transport_set_errno (session->session, EIO); - - return result; - } -} - -static gssize -wocky_tls_session_pull_func (gpointer user_data, - void *buffer, - gsize count) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (user_data); - GInputStream *stream; - - stream = g_io_stream_get_input_stream (session->stream); - - if (session->async) - { - WockyTLSJob *active_job; - - g_assert (session->handshake_job.job.active || - session->read_job.job.active); - - if (session->handshake_job.job.active) - active_job = &session->handshake_job.job; - else - active_job = &session->read_job.job; - - g_assert (active_job->active); - - if (session->read_op.state == WOCKY_TLS_OP_STATE_IDLE) - { - session->read_op.state = WOCKY_TLS_OP_STATE_ACTIVE; - session->read_op.buffer = g_malloc (count); - session->read_op.requested = count; - session->read_op.error = NULL; - - g_input_stream_read_async (stream, - session->read_op.buffer, - session->read_op.requested, - active_job->io_priority, - active_job->cancellable, - wocky_tls_session_read_ready, - session); - - if G_UNLIKELY (session->read_op.state != WOCKY_TLS_OP_STATE_ACTIVE) - g_warning ("The underlying stream '%s' used by the WockyTLSSession " - "called the GAsyncResultCallback recursively. This " - "is an error in the underlying implementation: in " - "some cases it may lead to unbounded recursion. " - "Result callbacks should always be dispatched from " - "the mainloop.", - G_OBJECT_TYPE_NAME (stream)); - } - - g_assert (session->read_op.state != WOCKY_TLS_OP_STATE_IDLE); - g_assert_cmpint (session->read_op.requested, ==, count); - - if (session->read_op.state == WOCKY_TLS_OP_STATE_DONE) - { - session->read_op.state = WOCKY_TLS_OP_STATE_IDLE; - - if (session->read_op.result < 0) - { - g_free (session->read_op.buffer); - session->read_op.buffer = NULL; - active_job->error = session->read_op.error; - gnutls_transport_set_errno (session->session, EIO); - - return -1; - } - else - { - g_assert_cmpint (session->read_op.result, <=, count); - - memcpy (buffer, - session->read_op.buffer, - session->read_op.result); - g_free (session->read_op.buffer); - session->read_op.buffer = NULL; - - return session->read_op.result; - } - } - - gnutls_transport_set_errno (session->session, EAGAIN); - - return -1; - } - else - { - gssize result; - - result = g_input_stream_read (stream, buffer, count, - session->cancellable, - &session->error); - if (result < 0) - gnutls_transport_set_errno (session->session, EIO); - - return result; - } + return 0; } +#ifdef DANWFIXME static void tls_debug (int level, const char *msg) @@ -1312,316 +346,42 @@ tls_debug (int level, DEBUG ("[%d] [%02d] %s", getpid(), level, msg); } -static void -wocky_tls_session_init (WockyTLSSession *session) -{ - const char *level; - guint lvl = 0; - static gsize initialised; - - if G_UNLIKELY (g_once_init_enter (&initialised)) - { - gnutls_global_init (); - gnutls_global_set_log_function (tls_debug); - g_once_init_leave (&initialised, 1); - } - - if ((level = getenv ("WOCKY_TLS_DEBUG_LEVEL")) != NULL) - lvl = atoi (level); - - tls_debug_level = lvl; - gnutls_global_set_log_level (lvl); -} - -static void -wocky_tls_session_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (object); - - switch (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; - case PROP_S_DHBITS: - session->dh_bits = g_value_get_uint (value); - break; - case PROP_S_KEYFILE: - session->key_file = g_value_dup_string (value); - break; - case PROP_S_CERTFILE: - session->cert_file = g_value_dup_string (value); - break; - default: - g_assert_not_reached (); - } -} - -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) { const char *options = getenv ("WOCKY_GNUTLS_OPTIONS"); return (options != NULL && *options != '\0') ? options : DEFAULT_TLS_OPTIONS; } +#endif -static void -wocky_tls_session_constructed (GObject *object) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (object); - - gboolean server = session->server; - gint code; - const gchar *opt = tls_options (); - const gchar *pos = NULL; - - /* gnutls_handshake_set_private_extensions (session->session, 1); */ - gnutls_certificate_allocate_credentials (&(session->gnutls_cert_cred)); - - /* I think this all needs to be done per connection: conceivably - the DH parameters could be moved to the global section above, - but IANA cryptographer */ - if (server) - { - gnutls_dh_params_t *dhp; - - if ((session->key_file != NULL) && (session->cert_file != NULL)) - { - DEBUG ("cert/key pair: %s/%s", session->cert_file, session->key_file); - gnutls_certificate_set_x509_key_file (session->gnutls_cert_cred, - session->cert_file, - session->key_file, - GNUTLS_X509_FMT_PEM); - } - - switch (session->dh_bits) - { - case 768: - dhp = &dh_0768; - break; - case 1024: - dhp = &dh_1024; - break; - case 2048: - dhp = &dh_2048; - break; - case 3072: - dhp = &dh_3072; - break; - case 4096: - dhp = &dh_4096; - break; - default: - dhp = &dh_1024; - break; - } - - if (*dhp == NULL) - { - DEBUG ("Initialising DH parameters (%d bits)", session->dh_bits); - gnutls_dh_params_init (dhp); - gnutls_dh_params_generate2 (*dhp, session->dh_bits); - } - - session->dh_params = *dhp; - gnutls_certificate_set_dh_params (session->gnutls_cert_cred, *dhp); - gnutls_init (&session->session, GNUTLS_SERVER); - } - else - gnutls_init (&session->session, GNUTLS_CLIENT); - - code = gnutls_priority_set_direct (session->session, opt, &pos); - if (code != GNUTLS_E_SUCCESS) - { - DEBUG ("could not set priority string: %s", error_to_string (code)); - DEBUG (" '%s'", opt); - if (pos >= opt) - DEBUG (" %*s^", (int) (pos - opt), ""); - } - else - { - DEBUG ("priority set to: '%s'", opt); - } - - code = gnutls_credentials_set (session->session, - GNUTLS_CRD_CERTIFICATE, - session->gnutls_cert_cred); - if (code != GNUTLS_E_SUCCESS) - DEBUG ("could not set credentials: %s", error_to_string (code)); - - gnutls_transport_set_push_function (session->session, - wocky_tls_session_push_func); - gnutls_transport_set_pull_function (session->session, - wocky_tls_session_pull_func); - gnutls_transport_set_ptr (session->session, session); - - g_assert (session->stream); -} - -static void -wocky_tls_session_finalize (GObject *object) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (object); - - if (session->input != NULL) - g_object_unref (session->input); - - if (session->output != NULL) - g_object_unref (session->output); - - gnutls_deinit (session->session); - gnutls_certificate_free_credentials (session->gnutls_cert_cred); - g_object_unref (session->stream); - - G_OBJECT_CLASS (wocky_tls_session_parent_class) - ->finalize (object); -} - -static void -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; - - g_free (session->cert_file); - session->cert_file = NULL; - - g_free (session->read_op.buffer); - session->read_op.buffer = NULL; - - G_OBJECT_CLASS (wocky_tls_session_parent_class)->dispose (object); -} - -static gboolean -wocky_tls_session_close (GIOStream *stream, - GCancellable *cancellable, - GError **error) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (stream); - - return g_io_stream_close (session->stream, cancellable, error); -} - -static GInputStream * -wocky_tls_session_get_input_stream (GIOStream *io_stream) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (io_stream); - - if (session->input == NULL) - session->input = g_object_new (WOCKY_TYPE_TLS_INPUT_STREAM, - "session", session, - NULL); - - return (GInputStream *)session->input; -} - -static GOutputStream * -wocky_tls_session_get_output_stream (GIOStream *io_stream) -{ - WockyTLSSession *session = WOCKY_TLS_SESSION (io_stream); - - if (session->output == NULL) - session->output = g_object_new (WOCKY_TYPE_TLS_OUTPUT_STREAM, - "session", session, - NULL); - - return (GOutputStream *)session->output; -} - -static void -wocky_tls_session_class_init (WockyTLSSessionClass *class) +WockyTLSSession * +wocky_tls_session_new (GIOStream *stream, + const char *peername) { - GObjectClass *object_class = G_OBJECT_CLASS (class); - GIOStreamClass *stream_class = G_IO_STREAM_CLASS (class); + GTlsClientConnection *conn; + GSocketConnectable *peer; - object_class->get_property = wocky_tls_session_get_property; - object_class->set_property = wocky_tls_session_set_property; - object_class->constructed = wocky_tls_session_constructed; - object_class->finalize = wocky_tls_session_finalize; - object_class->dispose = wocky_tls_session_dispose; + peer = peername ? g_network_address_new (peername, 0) : NULL; + conn = g_tls_client_connection_new (stream, peer, NULL); + if (peer) + g_object_unref (peer); - stream_class->get_input_stream = wocky_tls_session_get_input_stream; - stream_class->get_output_stream = wocky_tls_session_get_output_stream; - stream_class->close_fn = wocky_tls_session_close; - - g_object_class_install_property (object_class, PROP_S_STREAM, - g_param_spec_object ("base-stream", "base stream", - "the stream that TLS communicates over", - G_TYPE_IO_STREAM, G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + if (!conn) + return NULL; - g_object_class_install_property (object_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_set (G_OBJECT (conn), - g_object_class_install_property (object_class, PROP_S_SERVER, - g_param_spec_boolean ("server", "server", - "whether this is a server", - FALSE, G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + /* FIXME: just use the system certdb rather than + * reimplementing it ourselves. + */ + "use-system-certdb", FALSE, - g_object_class_install_property (object_class, PROP_S_DHBITS, - g_param_spec_uint ("dh-bits", "Diffie-Hellman bits", - "Diffie-Hellmann bits: 768, 1024, 2048, 3072 0r 4096", - 768, 4096, 1024, G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + /* Accept everything; we'll check it afterwards */ + "validation-flags", 0, - g_object_class_install_property (object_class, PROP_S_KEYFILE, - g_param_spec_string ("x509-key", "x509 key", - "x509 PEM key file", - NULL, G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + NULL); - g_object_class_install_property (object_class, PROP_S_CERTFILE, - g_param_spec_string ("x509-cert", "x509 certificate", - "x509 PEM certificate file", - NULL, G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); -} - -WockyTLSSession * -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); + return WOCKY_TLS_SESSION (conn); } /** @@ -1639,15 +399,18 @@ WockyTLSSession * wocky_tls_session_server_new (GIOStream *stream, guint dhbits, const gchar* key, const gchar* cert) { - if (dhbits == 0) - dhbits = 1024; - return g_object_new (WOCKY_TYPE_TLS_SESSION, "base-stream", stream, - "dh-bits", dhbits, "x509-key", key, "x509-cert", cert, - "server", TRUE, - NULL); -} + GTlsServerConnection *conn; + GTlsCertificate *tlscert; + + /* DANWFIXME: dhbits */ -/* this file is "borrowed" from an unmerged gnio feature: */ -/* Local Variables: */ -/* c-file-style: "gnu" */ -/* End: */ + if (key && cert) + tlscert = g_tls_certificate_new_from_files (cert, key, NULL); + else + tlscert = NULL; + conn = g_tls_server_connection_new (stream, tlscert, NULL); + if (tlscert) + g_object_unref (tlscert); + + return WOCKY_TLS_SESSION (conn); +} diff --git a/wocky/wocky-tls.h b/wocky/wocky-tls.h index 85d09b3..bc01c33 100644 --- a/wocky/wocky-tls.h +++ b/wocky/wocky-tls.h @@ -28,11 +28,10 @@ #include -#define WOCKY_TYPE_TLS_SESSION (wocky_tls_session_get_type ()) -#define WOCKY_TLS_SESSION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ - WOCKY_TYPE_TLS_SESSION, WockyTLSSession)) +#define WOCKY_TYPE_TLS_SESSION G_TYPE_TLS_CONNECTION +#define WOCKY_TLS_SESSION(inst) G_TLS_CONNECTION(inst) -typedef struct OPAQUE_TYPE__WockyTLSSession WockyTLSSession; +typedef GTlsConnection WockyTLSSession; typedef enum { @@ -68,30 +67,18 @@ typedef enum { WOCKY_TLS_CERT_TYPE_NONE = 0, WOCKY_TLS_CERT_TYPE_X509, - WOCKY_TLS_CERT_TYPE_OPENPGP, + WOCKY_TLS_CERT_TYPE_OPENPGP, /* DANWFIXME: unused */ } WockyTLSCertType; -GType wocky_tls_session_get_type (void); - int wocky_tls_session_verify_peer (WockyTLSSession *session, WockyTLSVerificationLevel level, WockyTLSCertStatus *status); GPtrArray *wocky_tls_session_get_peers_certificate (WockyTLSSession *session, WockyTLSCertType *type); -gboolean wocky_tls_session_handshake (WockyTLSSession *session, - GCancellable *cancellable, - GError **error); -void -wocky_tls_session_handshake_async (WockyTLSSession *session, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean -wocky_tls_session_handshake_finish (WockyTLSSession *session, - GAsyncResult *result, - GError **error); +#define wocky_tls_session_handshake g_tls_connection_handshake +#define wocky_tls_session_handshake_async g_tls_connection_handshake_async +#define wocky_tls_session_handshake_finish g_tls_connection_handshake_finish void wocky_tls_session_add_ca (WockyTLSSession *session, const gchar *path); void wocky_tls_session_add_crl (WockyTLSSession *session, const gchar *path); @@ -103,9 +90,5 @@ WockyTLSSession *wocky_tls_session_server_new (GIOStream *stream, guint dhbits, const gchar* key, const gchar* cert); -#endif /* _wocky_tls_h_ */ -/* this file is "borrowed" from an unmerged gnio feature: */ -/* Local Variables: */ -/* c-file-style: "gnu" */ -/* End: */ +#endif /* _wocky_tls_h_ */ -- 1.7.3.3