[glib-networking] openssl: update SSL structure when certificate is changed
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] openssl: update SSL structure when certificate is changed
- Date: Fri, 15 Feb 2019 08:03:04 +0000 (UTC)
commit 3f5c05e381b5c180f912a2ba2a6aae66a17de970
Author: Fredrik Ternerot <fredrikt axis com>
Date: Mon Feb 11 15:36:12 2019 +0100
openssl: update SSL structure when certificate is changed
Set server certificate on SSL structure every time the certificate is
changed. Previously the certificate was set during initialization only.
This solves the problem when GTlsServerConnection is created without a
certificate and g_tls_connection_set_certificate() is used to supply the
certificate after creation time.
Also modify the connection unittest to cover this use case by setting
the server certificate after initialization when the default certificate
is used.
Fixes #55
tls/openssl/gtlsserverconnection-openssl.c | 134 ++++++++++++++++++-----------
tls/tests/connection.c | 19 ++--
2 files changed, 91 insertions(+), 62 deletions(-)
---
diff --git a/tls/openssl/gtlsserverconnection-openssl.c b/tls/openssl/gtlsserverconnection-openssl.c
index 60f9659..ff7419e 100644
--- a/tls/openssl/gtlsserverconnection-openssl.c
+++ b/tls/openssl/gtlsserverconnection-openssl.c
@@ -74,6 +74,67 @@ g_tls_server_connection_openssl_finalize (GObject *object)
G_OBJECT_CLASS (g_tls_server_connection_openssl_parent_class)->finalize (object);
}
+static gboolean
+ssl_set_certificate (SSL *ssl,
+ GTlsCertificate *cert,
+ GError **error)
+{
+ EVP_PKEY *key;
+ X509 *x;
+ GTlsCertificate *issuer;
+
+ key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
+
+ if (key == NULL)
+ {
+ g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Certificate has no private key"));
+ return FALSE;
+ }
+
+ /* Note, order is important. If a certificate has been set previously,
+ * OpenSSL requires that the new certificate is set _before_ the new
+ * private key is set. */
+ x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert));
+ if (SSL_use_certificate (ssl, x) <= 0)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("There is a problem with the certificate: %s"),
+ ERR_error_string (ERR_get_error (), NULL));
+ return FALSE;
+ }
+
+ if (SSL_use_PrivateKey (ssl, key) <= 0)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("There is a problem with the certificate private key: %s"),
+ ERR_error_string (ERR_get_error (), NULL));
+ return FALSE;
+ }
+
+ if (SSL_clear_chain_certs (ssl) == 0)
+ g_warning ("There was a problem clearing the chain certificates: %s",
+ ERR_error_string (ERR_get_error (), NULL));
+
+ /* Add all the issuers to create the full certificate chain */
+ for (issuer = g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (cert));
+ issuer != NULL;
+ issuer = g_tls_certificate_get_issuer (issuer))
+ {
+ X509 *issuer_x;
+
+ /* Be careful here and duplicate the certificate since the context
+ * will take the ownership
+ */
+ issuer_x = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (issuer)));
+ if (SSL_add0_chain_cert (ssl, issuer_x) == 0)
+ g_warning ("There was a problem adding the chain certificate: %s",
+ ERR_error_string (ERR_get_error (), NULL));
+ }
+
+ return TRUE;
+}
+
static void
g_tls_server_connection_openssl_get_property (GObject *object,
guint prop_id,
@@ -90,7 +151,7 @@ g_tls_server_connection_openssl_get_property (GObject *object,
case PROP_AUTHENTICATION_MODE:
g_value_set_enum (value, priv->authentication_mode);
break;
-
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -168,6 +229,21 @@ g_tls_server_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection)
return priv->ssl;
}
+static void
+on_certificate_changed (GObject *object,
+ GParamSpec *spec,
+ gpointer user_data)
+{
+ SSL *ssl;
+ GTlsCertificate *cert;
+
+ ssl = g_tls_server_connection_openssl_get_ssl (G_TLS_CONNECTION_OPENSSL (object));
+ cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (object));
+
+ if (ssl && cert)
+ ssl_set_certificate (ssl, cert, NULL);
+}
+
static void
g_tls_server_connection_openssl_class_init (GTlsServerConnectionOpensslClass *klass)
{
@@ -313,56 +389,6 @@ g_tls_server_connection_openssl_initable_init (GInitable *initable,
SSL_CTX_set_options (priv->ssl_ctx, options);
- cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (initable));
- if (cert != NULL)
- {
- EVP_PKEY *key;
- X509 *x;
- GTlsCertificate *issuer;
-
- key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
-
- if (key == NULL)
- {
- g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Certificate has no private key"));
- return FALSE;
- }
-
- if (SSL_CTX_use_PrivateKey (priv->ssl_ctx, key) <= 0)
- {
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("There is a problem with the certificate private key: %s"),
- ERR_error_string (ERR_get_error (), NULL));
- return FALSE;
- }
-
- x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert));
- if (SSL_CTX_use_certificate (priv->ssl_ctx, x) <= 0)
- {
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("There is a problem with the certificate: %s"),
- ERR_error_string (ERR_get_error (), NULL));
- return FALSE;
- }
-
- /* Add all the issuers to create the full certificate chain */
- for (issuer = g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (cert));
- issuer != NULL;
- issuer = g_tls_certificate_get_issuer (issuer))
- {
- X509 *issuer_x;
-
- /* Be careful here and duplicate the certificate since the context
- * will take the ownership
- */
- issuer_x = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (issuer)));
- if (!SSL_CTX_add_extra_chain_cert (priv->ssl_ctx, issuer_x))
- g_warning ("There was a problem adding the extra chain certificate: %s",
- ERR_error_string (ERR_get_error (), NULL));
- }
- }
-
SSL_CTX_add_session (priv->ssl_ctx, priv->session);
#ifdef SSL_CTX_set1_sigalgs_list
@@ -401,12 +427,18 @@ g_tls_server_connection_openssl_initable_init (GInitable *initable,
return FALSE;
}
+ cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (initable));
+ if (cert != NULL && !ssl_set_certificate (priv->ssl, cert, error))
+ return FALSE;
+
SSL_set_accept_state (priv->ssl);
if (!g_tls_server_connection_openssl_parent_initable_iface->
init (initable, cancellable, error))
return FALSE;
+ g_signal_connect (server, "notify::certificate", G_CALLBACK (on_certificate_changed), NULL);
+
return TRUE;
}
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index c64dd35..d82d1ba 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -286,22 +286,19 @@ on_incoming_connection (GSocketService *service,
GTlsCertificate *cert;
GError *error = NULL;
- if (test->server_certificate)
- {
- cert = g_object_ref (test->server_certificate);
- }
- else
+ g_assert_null (test->server_connection);
+ test->server_connection = g_tls_server_connection_new (G_IO_STREAM (connection),
+ test->server_certificate, &error);
+ g_assert_no_error (error);
+
+ if (!test->server_certificate)
{
cert = g_tls_certificate_new_from_file (tls_test_file_path ("server-and-key.pem"), &error);
g_assert_no_error (error);
+ g_tls_connection_set_certificate ((GTlsConnection *)test->server_connection, cert);
+ g_object_unref (cert);
}
- g_assert_null (test->server_connection);
- test->server_connection = g_tls_server_connection_new (G_IO_STREAM (connection),
- cert, &error);
- g_assert_no_error (error);
- g_object_unref (cert);
-
g_object_set (test->server_connection, "authentication-mode", test->auth_mode, NULL);
g_signal_connect (test->server_connection, "accept-certificate",
G_CALLBACK (on_accept_certificate), test);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]