From 0a115bd31f77a6b4b38127937c562f4145f8ccfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Sun, 16 Feb 2014 17:39:35 -0800 Subject: [PATCH] rtspconnection: allow specifying a certificate database Two new functions have been added, gst_rtsp_connection_set_tls_database() and gst_rtsp_connection_get_tls_database(). The certificate database will be used when a certificate can't be verified with the default database. https://bugzilla.gnome.org/show_bug.cgi?id=724393 --- gst-libs/gst/rtsp/gstrtspconnection.c | 124 ++++++++++++++++++++++++++ gst-libs/gst/rtsp/gstrtspconnection.h | 3 +- 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/rtsp/gstrtspconnection.c b/gst-libs/gst/rtsp/gstrtspconnection.c index 1f5a938c8d..3936418563 100644 --- a/gst-libs/gst/rtsp/gstrtspconnection.c +++ b/gst-libs/gst/rtsp/gstrtspconnection.c @@ -151,6 +151,9 @@ struct _GstRTSPConnection gchar *passwd; GHashTable *auth_params; + /* TLS */ + GTlsDatabase *tls_database; + DecodeCtx ctx; DecodeCtx *ctxp; @@ -195,6 +198,66 @@ build_reset (GstRTSPBuilder * builder) memset (builder, 0, sizeof (GstRTSPBuilder)); } +static gboolean +tls_accept_certificate (GTlsConnection * conn, GTlsCertificate * peer_cert, + GTlsCertificateFlags errors, GstRTSPConnection * rtspconn) +{ + GError *error = NULL; + gboolean accept = FALSE; + + if (rtspconn->tls_database) { + GSocketConnectable *peer_identity; + GTlsCertificateFlags validation_flags; + + GST_DEBUG ("TLS peer certificate not accepted, checking user database..."); + + peer_identity = + g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION + (conn)); + + errors = + g_tls_database_verify_chain (rtspconn->tls_database, peer_cert, + G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER, peer_identity, + g_tls_connection_get_interaction (conn), G_TLS_DATABASE_VERIFY_NONE, + NULL, &error); + + if (error) + goto verify_error; + + validation_flags = gst_rtsp_connection_get_tls_validation_flags (rtspconn); + + accept = ((errors & validation_flags) == 0); + if (accept) + GST_DEBUG ("Peer certificate accepted"); + else + GST_DEBUG ("Peer certificate not accepted (errors: 0x%08X)", errors); + } + + return accept; + +/* ERRORS */ +verify_error: + { + GST_ERROR ("An error occurred while verifying the peer certificate: %s", + error->message); + g_clear_error (&error); + return FALSE; + } +} + +static void +socket_client_event (GSocketClient * client, GSocketClientEvent event, + GSocketConnectable * connectable, GIOStream * connection, + GstRTSPConnection * rtspconn) +{ + if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING) { + GST_DEBUG ("TLS handshaking about to start..."); + + g_signal_connect (connection, "accept-certificate", + (GCallback) tls_accept_certificate, rtspconn); + } +} + /** * gst_rtsp_connection_create: * @url: a #GstRTSPUrl @@ -225,6 +288,9 @@ gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn) if (url->transports & GST_RTSP_LOWER_TRANS_TLS) g_socket_client_set_tls (newconn->client, TRUE); + g_signal_connect (newconn->client, "event", (GCallback) socket_client_event, + newconn); + newconn->url = gst_rtsp_url_copy (url); newconn->timer = g_timer_new (); newconn->timeout = 60; @@ -493,6 +559,62 @@ gst_rtsp_connection_get_tls_validation_flags (GstRTSPConnection * conn) return g_socket_client_get_tls_validation_flags (conn->client); } +/** + * gst_rtsp_connection_set_tls_database: + * @conn: a #GstRTSPConnection + * @database: a #GTlsDatabase + * + * Sets the anchor certificate authorities database. This certificate + * database will be used to verify the server's certificate in case it + * can't be verified with the default certificate database first. + * + * Since: 1.4 + */ +void +gst_rtsp_connection_set_tls_database (GstRTSPConnection * conn, + GTlsDatabase * database) +{ + GTlsDatabase *old_db; + + g_return_if_fail (conn != NULL); + + if (database) + g_object_ref (database); + + old_db = conn->tls_database; + conn->tls_database = database; + + if (old_db) + g_object_unref (old_db); +} + +/** + * gst_rtsp_connection_get_tls_database: + * @conn: a #GstRTSPConnection + * + * Gets the anchor certificate authorities database that will be used + * after a server certificate can't be verified with the default + * certificate database. + * + * Returns: (transfer full): the anchor certificate authorities database, or NULL if no + * database has been previously set. Use g_object_unref() to release the + * certificate database. + * + * Since: 1.4 + */ +GTlsDatabase * +gst_rtsp_connection_get_tls_database (GstRTSPConnection * conn) +{ + GTlsDatabase *result; + + g_return_val_if_fail (conn != NULL, NULL); + + if ((result = conn->tls_database)) + g_object_ref (result); + + return result; +} + static GstRTSPResult setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout, gchar * uri) { @@ -2147,6 +2269,8 @@ gst_rtsp_connection_free (GstRTSPConnection * conn) g_object_unref (conn->cancellable); if (conn->client) g_object_unref (conn->client); + if (conn->tls_database) + g_object_unref (conn->tls_database); g_timer_destroy (conn->timer); gst_rtsp_url_free (conn->url); diff --git a/gst-libs/gst/rtsp/gstrtspconnection.h b/gst-libs/gst/rtsp/gstrtspconnection.h index 87faae2861..5d1129d45f 100644 --- a/gst-libs/gst/rtsp/gstrtspconnection.h +++ b/gst-libs/gst/rtsp/gstrtspconnection.h @@ -76,7 +76,8 @@ GstRTSPResult gst_rtsp_connection_free (GstRTSPConnection *conn); GTlsConnection * gst_rtsp_connection_get_tls (GstRTSPConnection * conn, GError ** error); gboolean gst_rtsp_connection_set_tls_validation_flags (GstRTSPConnection * conn, GTlsCertificateFlags flags); GTlsCertificateFlags gst_rtsp_connection_get_tls_validation_flags (GstRTSPConnection * conn); - +void gst_rtsp_connection_set_tls_database (GstRTSPConnection * conn, GTlsDatabase * database); +GTlsDatabase * gst_rtsp_connection_get_tls_database (GstRTSPConnection * conn); /* sending/receiving raw bytes */ GstRTSPResult gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data,