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
This commit is contained in:
Aleix Conchillo Flaqué 2014-02-16 17:39:35 -08:00 committed by Sebastian Dröge
parent 9121b16aa0
commit 0a115bd31f
2 changed files with 126 additions and 1 deletions

View file

@ -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);

View file

@ -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,