[libsoup/carlosgc/client-side-certs-for-ci] message: add API to handle password protected client certificates
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/carlosgc/client-side-certs-for-ci] message: add API to handle password protected client certificates
- Date: Fri, 30 Apr 2021 08:41:35 +0000 (UTC)
commit d00e9bebdb92dd81c68cdb55d98f7f42bee63aba
Author: Carlos Garcia Campos <cgarcia igalia com>
Date: Tue Apr 27 13:22:27 2021 +0200
message: add API to handle password protected client certificates
Implement GTlsInteraction::ask_password to expose another signal in
SoupMessage to ask the user for ther password.
docs/reference/libsoup-3.0-sections.txt | 1 +
libsoup/auth/soup-tls-interaction.c | 31 ++++++++++++
libsoup/soup-connection.c | 42 +++++++++++++++++
libsoup/soup-connection.h | 25 ++++++----
libsoup/soup-message.c | 84 +++++++++++++++++++++++++++++++++
libsoup/soup-message.h | 11 +++--
6 files changed, 180 insertions(+), 14 deletions(-)
---
diff --git a/docs/reference/libsoup-3.0-sections.txt b/docs/reference/libsoup-3.0-sections.txt
index dc21cd5e..030f6211 100644
--- a/docs/reference/libsoup-3.0-sections.txt
+++ b/docs/reference/libsoup-3.0-sections.txt
@@ -31,6 +31,7 @@ soup_message_get_connection_id
soup_message_get_tls_peer_certificate
soup_message_get_tls_peer_certificate_errors
soup_message_set_tls_client_certificate
+soup_message_set_tls_client_certificate_password
<SUBSECTION>
soup_message_set_first_party
soup_message_get_first_party
diff --git a/libsoup/auth/soup-tls-interaction.c b/libsoup/auth/soup-tls-interaction.c
index 0ade927e..d79289d4 100644
--- a/libsoup/auth/soup-tls-interaction.c
+++ b/libsoup/auth/soup-tls-interaction.c
@@ -51,6 +51,35 @@ soup_tls_interaction_request_certificate_finish (GTlsInteraction *tls_interactio
return task_result != -1 ? task_result : G_TLS_INTERACTION_FAILED;
}
+static void
+soup_tls_interaction_ask_password_async (GTlsInteraction *tls_interaction,
+ GTlsPassword *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SoupTlsInteractionPrivate *priv = soup_tls_interaction_get_instance_private (SOUP_TLS_INTERACTION
(tls_interaction));
+ GTask *task;
+
+ task = g_task_new (tls_interaction, cancellable, callback, user_data);
+ if (priv->conn)
+ soup_connection_request_tls_certificate_password (priv->conn, password, task);
+ else
+ g_task_return_int (task, G_TLS_INTERACTION_FAILED);
+ g_object_unref (task);
+}
+
+static GTlsInteractionResult
+soup_tls_interaction_ask_password_finish (GTlsInteraction *tls_interaction,
+ GAsyncResult *result,
+ GError **error)
+{
+ int task_result;
+
+ task_result = g_task_propagate_int (G_TASK (result), error);
+ return task_result != -1 ? task_result : G_TLS_INTERACTION_FAILED;
+}
+
static void
soup_tls_interaction_finalize (GObject *object)
{
@@ -79,6 +108,8 @@ soup_tls_interaction_class_init (SoupTlsInteractionClass *klass)
interaction_class->request_certificate_async = soup_tls_interaction_request_certificate_async;
interaction_class->request_certificate_finish = soup_tls_interaction_request_certificate_finish;
+ interaction_class->ask_password_async = soup_tls_interaction_ask_password_async;
+ interaction_class->ask_password_finish = soup_tls_interaction_ask_password_finish;
}
GTlsInteraction *
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 5d1f3406..f8dccec2 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -50,6 +50,7 @@ enum {
EVENT,
ACCEPT_CERTIFICATE,
REQUEST_CERTIFICATE,
+ REQUEST_CERTIFICATE_PASSWORD,
DISCONNECTED,
LAST_SIGNAL
};
@@ -225,6 +226,16 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
G_TYPE_BOOLEAN, 2,
G_TYPE_TLS_CLIENT_CONNECTION,
G_TYPE_TASK);
+ signals[REQUEST_CERTIFICATE_PASSWORD] =
+ g_signal_new ("request-certificate-password",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_true_handled, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_TLS_PASSWORD,
+ G_TYPE_TASK);
signals[DISCONNECTED] =
g_signal_new ("disconnected",
G_OBJECT_CLASS_TYPE (object_class),
@@ -1174,6 +1185,37 @@ soup_connection_complete_tls_certificate_request (SoupConnection *conn,
g_object_unref (task);
}
+void
+soup_connection_request_tls_certificate_password (SoupConnection *conn,
+ GTlsPassword *password,
+ GTask *task)
+{
+ SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+ gboolean handled = FALSE;
+
+ if (!G_IS_TLS_CONNECTION (priv->connection)) {
+ g_task_return_int (task, G_TLS_INTERACTION_FAILED);
+ return;
+ }
+
+ g_signal_emit (conn, signals[REQUEST_CERTIFICATE_PASSWORD], 0, password, task, &handled);
+ if (!handled)
+ g_task_return_int (task, G_TLS_INTERACTION_FAILED);
+}
+
+void
+soup_connection_complete_tls_certificate_password_request (SoupConnection *conn,
+ GTask *task)
+{
+ SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
+
+ if (G_IS_TLS_CONNECTION (priv->connection))
+ g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
+ else
+ g_task_return_int (task, G_TLS_INTERACTION_FAILED);
+ g_object_unref (task);
+}
+
guint64
soup_connection_get_id (SoupConnection *conn)
{
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 881a546c..4f58cba2 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -70,16 +70,21 @@ SoupClientMessageIOData *soup_connection_setup_message_io (SoupConnection *co
void soup_connection_message_io_finished (SoupConnection *conn,
SoupMessage *msg);
-GTlsCertificate *soup_connection_get_tls_certificate (SoupConnection *conn);
-GTlsCertificateFlags soup_connection_get_tls_certificate_errors (SoupConnection *conn);
-void soup_connection_request_tls_certificate (SoupConnection *conn,
- GTlsConnection *connection,
- GTask *task);
-void soup_connection_complete_tls_certificate_request (SoupConnection *conn,
- GTlsCertificate *certificate,
- GTask *task);
-void soup_connection_set_tls_client_certificate (SoupConnection *conn,
- GTlsCertificate *certificate);
+GTlsCertificate *soup_connection_get_tls_certificate (SoupConnection *conn);
+GTlsCertificateFlags soup_connection_get_tls_certificate_errors (SoupConnection *conn);
+void soup_connection_request_tls_certificate (SoupConnection *conn,
+ GTlsConnection *connection,
+ GTask *task);
+void soup_connection_complete_tls_certificate_request (SoupConnection *conn,
+ GTlsCertificate *certificate,
+ GTask *task);
+void soup_connection_set_tls_client_certificate (SoupConnection *conn,
+ GTlsCertificate
*certificate);
+void soup_connection_request_tls_certificate_password (SoupConnection *conn,
+ GTlsPassword *password,
+ GTask *task);
+void soup_connection_complete_tls_certificate_password_request (SoupConnection *conn,
+ GTask *task);
guint64 soup_connection_get_id (SoupConnection *conn);
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index c2468f3a..a9b1e1be 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -91,6 +91,7 @@ typedef struct {
GTlsCertificate *tls_client_certificate;
GTask *pending_tls_cert_request;
+ GTask *pending_tls_cert_pass_request;
SoupMessagePriority priority;
@@ -121,6 +122,7 @@ enum {
NETWORK_EVENT,
ACCEPT_CERTIFICATE,
REQUEST_CERTIFICATE,
+ REQUEST_CERTIFICATE_PASSWORD,
HSTS_ENFORCED,
LAST_SIGNAL
@@ -173,6 +175,11 @@ soup_message_finalize (GObject *object)
g_object_unref (priv->pending_tls_cert_request);
}
+ if (priv->pending_tls_cert_pass_request) {
+ g_task_return_int (priv->pending_tls_cert_pass_request, G_TLS_INTERACTION_FAILED);
+ g_object_unref (priv->pending_tls_cert_pass_request);
+ }
+
soup_message_set_connection (msg, NULL);
g_clear_pointer (&priv->uri, g_uri_unref);
@@ -624,6 +631,36 @@ soup_message_class_init (SoupMessageClass *message_class)
G_TYPE_BOOLEAN, 1,
G_TYPE_TLS_CLIENT_CONNECTION);
+ /**
+ * SoupMessage::request-certificate-password:
+ * @msg: the message
+ * @tls_password: the #GTlsPassword
+ *
+ * Emitted during the @msg's connection TLS handshake when
+ * @tls_connection requests a certificate password from the client.
+ * You can set the certificate password on @password, then call
+ * soup_message_tls_client_certificate_password_request_complete() and return %TRUE
+ * to handle the signal synchronously.
+ * It's possible to handle the request asynchornously by calling g_object_ref()
+ * on @password, then returning %TRUE and call
+ * soup_message_tls_client_certificate_password_request_complete() later after
+ * setting the password on @password.
+ * Note that this signal is not emitted if #SoupSession::tls-interaction
+ * was set.
+ *
+ * Returns: %TRUE to handle the request, or %FALSE to make the connection
+ * fail with %G_TLS_ERROR_CERTIFICATE_REQUIRED.
+ */
+ signals[REQUEST_CERTIFICATE_PASSWORD] =
+ g_signal_new ("request-certificate-password",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_true_handled, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 1,
+ G_TYPE_TLS_PASSWORD);
+
/**
* SoupMessage::hsts-enforced:
* @msg: the message
@@ -1424,6 +1461,23 @@ re_emit_request_certificate (SoupMessage *msg,
return handled;
}
+static gboolean
+re_emit_request_certificate_password (SoupMessage *msg,
+ GTlsPassword *password,
+ GTask *task)
+{
+ SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
+ gboolean handled = FALSE;
+
+ priv->pending_tls_cert_pass_request = g_object_ref (task);
+
+ g_signal_emit (msg, signals[REQUEST_CERTIFICATE_PASSWORD], 0, password, &handled);
+ if (!handled)
+ g_clear_object (&priv->pending_tls_cert_pass_request);
+
+ return handled;
+}
+
static void
re_emit_tls_certificate_changed (SoupMessage *msg,
GParamSpec *pspec,
@@ -1482,6 +1536,9 @@ soup_message_set_connection (SoupMessage *msg,
g_signal_connect_object (priv->connection, "request-certificate",
G_CALLBACK (re_emit_request_certificate),
msg, G_CONNECT_SWAPPED);
+ g_signal_connect_object (priv->connection, "request-certificate-password",
+ G_CALLBACK (re_emit_request_certificate_password),
+ msg, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->connection, "notify::tls-certificate",
G_CALLBACK (re_emit_tls_certificate_changed),
msg, G_CONNECT_SWAPPED);
@@ -2174,6 +2231,33 @@ soup_message_set_tls_client_certificate (SoupMessage *msg,
priv->tls_client_certificate = g_object_ref (certificate);
}
+/**
+ * soup_message_tls_client_certificate_password_request_complete:
+ * @msg: a #SoupMessage
+ *
+ * Completes a certificate password request.
+ *
+ * You must call this as a response to #SoupMessage::request-certificate-password
+ * signal, to notify @msg that the #GTlsPassword has already been updated.
+ */
+void
+soup_message_tls_client_certificate_password_request_complete (SoupMessage *msg)
+{
+ SoupMessagePrivate *priv;
+
+ g_return_if_fail (SOUP_IS_MESSAGE (msg));
+
+ priv = soup_message_get_instance_private (msg);
+ if (!priv->pending_tls_cert_pass_request) {
+ g_warning ("soup_message_tls_client_certificate_password_request_complete should only be
called as a response to SoupMessage::request-certificate-password signal");
+ return;
+ }
+
+ g_assert (SOUP_IS_CONNECTION (priv->connection));
+ soup_connection_complete_tls_certificate_password_request (priv->connection,
+ g_steal_pointer
(&priv->pending_tls_cert_pass_request));
+}
+
/**
* SoupMessagePriority:
* @SOUP_MESSAGE_PRIORITY_VERY_LOW: The lowest priority, the messages
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index 5e82145c..216f8f29 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -101,14 +101,17 @@ gboolean soup_message_query_flags (SoupMessage *msg,
SoupMessageFlags flags);
SOUP_AVAILABLE_IN_ALL
-GTlsCertificate *soup_message_get_tls_peer_certificate (SoupMessage *msg);
+GTlsCertificate *soup_message_get_tls_peer_certificate (SoupMessage *msg);
SOUP_AVAILABLE_IN_ALL
-GTlsCertificateFlags soup_message_get_tls_peer_certificate_errors (SoupMessage *msg);
+GTlsCertificateFlags soup_message_get_tls_peer_certificate_errors (SoupMessage *msg);
SOUP_AVAILABLE_IN_ALL
-void soup_message_set_tls_client_certificate (SoupMessage *msg,
- GTlsCertificate *certificate);
+void soup_message_set_tls_client_certificate (SoupMessage *msg,
+ GTlsCertificate
*certificate);
+
+SOUP_AVAILABLE_IN_ALL
+void soup_message_tls_client_certificate_password_request_complete (SoupMessage *msg);
/* Specialized signal handlers */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]