summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libsoup/soup-connection.c17
-rw-r--r--libsoup/soup-connection.h1
-rw-r--r--libsoup/soup-gnutls.c6
-rw-r--r--libsoup/soup-session.c29
-rw-r--r--libsoup/soup-session.h1
-rw-r--r--libsoup/soup-socket.c44
-rw-r--r--libsoup/soup-socket.h3
-rw-r--r--tests/test-utils.c5
8 files changed, 97 insertions, 9 deletions
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 8cb110c4..b730b62c 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -34,6 +34,7 @@ typedef struct {
SoupAddress *remote_addr, *tunnel_addr;
SoupURI *proxy_uri;
gpointer ssl_creds;
+ gboolean ssl_strict;
GMainContext *async_context;
@@ -61,6 +62,7 @@ enum {
PROP_TUNNEL_ADDRESS,
PROP_PROXY_URI,
PROP_SSL_CREDS,
+ PROP_SSL_STRICT,
PROP_ASYNC_CONTEXT,
PROP_TIMEOUT,
PROP_IDLE_TIMEOUT,
@@ -175,6 +177,13 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
"Opaque SSL credentials for this connection",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (
+ object_class, PROP_SSL_STRICT,
+ g_param_spec_boolean (SOUP_CONNECTION_SSL_STRICT,
+ "Strictly validate SSL certificates",
+ "Whether certificate errors should be considered a connection error",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (
object_class, PROP_ASYNC_CONTEXT,
g_param_spec_pointer (SOUP_CONNECTION_ASYNC_CONTEXT,
"Async GMainContext",
@@ -246,6 +255,9 @@ set_property (GObject *object, guint prop_id,
case PROP_SSL_CREDS:
priv->ssl_creds = g_value_get_pointer (value);
break;
+ case PROP_SSL_STRICT:
+ priv->ssl_strict = g_value_get_boolean (value);
+ break;
case PROP_ASYNC_CONTEXT:
priv->async_context = g_value_get_pointer (value);
if (priv->async_context)
@@ -285,6 +297,9 @@ get_property (GObject *object, guint prop_id,
case PROP_SSL_CREDS:
g_value_set_pointer (value, priv->ssl_creds);
break;
+ case PROP_SSL_STRICT:
+ g_value_set_boolean (value, priv->ssl_strict);
+ break;
case PROP_ASYNC_CONTEXT:
g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
break;
@@ -466,6 +481,7 @@ soup_connection_connect_async (SoupConnection *conn,
priv->socket =
soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
+ SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
SOUP_SOCKET_TIMEOUT, priv->io_timeout,
NULL);
@@ -496,6 +512,7 @@ soup_connection_connect_sync (SoupConnection *conn)
priv->socket =
soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
+ SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
SOUP_SOCKET_TIMEOUT, priv->io_timeout,
NULL);
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index ae8973e9..f2ec40c2 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -44,6 +44,7 @@ typedef void (*SoupConnectionCallback) (SoupConnection *conn,
#define SOUP_CONNECTION_TUNNEL_ADDRESS "tunnel-address"
#define SOUP_CONNECTION_PROXY_URI "proxy-uri"
#define SOUP_CONNECTION_SSL_CREDENTIALS "ssl-creds"
+#define SOUP_CONNECTION_SSL_STRICT "ssl-strict"
#define SOUP_CONNECTION_ASYNC_CONTEXT "async-context"
#define SOUP_CONNECTION_TIMEOUT "timeout"
#define SOUP_CONNECTION_IDLE_TIMEOUT "idle-timeout"
diff --git a/libsoup/soup-gnutls.c b/libsoup/soup-gnutls.c
index c77f2b2d..1b6e613e 100644
--- a/libsoup/soup-gnutls.c
+++ b/libsoup/soup-gnutls.c
@@ -164,6 +164,8 @@ again:
return G_IO_STATUS_ERROR;
}
+ chan->established = TRUE;
+
if (chan->type == SOUP_SSL_TYPE_CLIENT && chan->creds->have_ca_file &&
!verify_certificate (chan->session, chan->hostname, err))
return G_IO_STATUS_ERROR;
@@ -190,8 +192,6 @@ again:
if (result == G_IO_STATUS_AGAIN ||
result == G_IO_STATUS_ERROR)
return result;
-
- chan->established = TRUE;
}
result = gnutls_record_recv (chan->session, buf, count);
@@ -252,8 +252,6 @@ again:
if (result == G_IO_STATUS_AGAIN ||
result == G_IO_STATUS_ERROR)
return result;
-
- chan->established = TRUE;
}
result = gnutls_record_send (chan->session, buf, count);
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 2b132286..009d702f 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -71,6 +71,7 @@ typedef struct {
typedef struct {
char *ssl_ca_file;
SoupSSLCredentials *ssl_creds;
+ gboolean ssl_strict;
SoupMessageQueue *queue;
@@ -140,6 +141,7 @@ enum {
PROP_MAX_CONNS_PER_HOST,
PROP_USE_NTLM,
PROP_SSL_CA_FILE,
+ PROP_SSL_STRICT,
PROP_ASYNC_CONTEXT,
PROP_TIMEOUT,
PROP_USER_AGENT,
@@ -191,6 +193,8 @@ soup_session_init (SoupSession *session)
* so hold a ref on the default GResolver.
*/
priv->resolver = g_resolver_get_default ();
+
+ priv->ssl_strict = TRUE;
}
static void
@@ -508,6 +512,24 @@ soup_session_class_init (SoupSessionClass *session_class)
NULL,
G_PARAM_READWRITE));
/**
+ * SOUP_SESSION_SSL_STRICT:
+ *
+ * Alias for the #SoupSession:ignore-ssl-cert-errors
+ * property. By default, when validating certificates against
+ * a CA file, Soup will consider invalid certificates as a
+ * connection error. Setting this property to %TRUE makes soup
+ * ignore the errors, and make the connection.
+ *
+ * Since: 2.30
+ **/
+ g_object_class_install_property (
+ object_class, PROP_SSL_STRICT,
+ g_param_spec_boolean (SOUP_SESSION_SSL_STRICT,
+ "Strictly validate SSL certificates",
+ "Whether certificate errors should be considered a connection error",
+ TRUE,
+ G_PARAM_READWRITE));
+ /**
* SOUP_SESSION_ASYNC_CONTEXT:
*
* Alias for the #SoupSession:async-context property. (The
@@ -843,6 +865,9 @@ set_property (GObject *object, guint prop_id,
}
break;
+ case PROP_SSL_STRICT:
+ priv->ssl_strict = g_value_get_boolean (value);
+ break;
case PROP_ASYNC_CONTEXT:
priv->async_context = g_value_get_pointer (value);
if (priv->async_context)
@@ -936,6 +961,9 @@ get_property (GObject *object, guint prop_id,
case PROP_SSL_CA_FILE:
g_value_set_string (value, priv->ssl_ca_file);
break;
+ case PROP_SSL_STRICT:
+ g_value_set_boolean (value, priv->ssl_strict);
+ break;
case PROP_ASYNC_CONTEXT:
g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
break;
@@ -1408,6 +1436,7 @@ soup_session_get_connection (SoupSession *session,
SOUP_CONNECTION_TUNNEL_ADDRESS, tunnel_addr,
SOUP_CONNECTION_PROXY_URI, item->proxy_uri,
SOUP_CONNECTION_SSL_CREDENTIALS, ssl_creds,
+ SOUP_CONNECTION_SSL_STRICT, priv->ssl_strict,
SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
SOUP_CONNECTION_TIMEOUT, priv->io_timeout,
SOUP_CONNECTION_IDLE_TIMEOUT, priv->idle_timeout,
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index 056799d8..fe078926 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -63,6 +63,7 @@ GType soup_session_get_type (void);
#define SOUP_SESSION_MAX_CONNS_PER_HOST "max-conns-per-host"
#define SOUP_SESSION_USE_NTLM "use-ntlm"
#define SOUP_SESSION_SSL_CA_FILE "ssl-ca-file"
+#define SOUP_SESSION_SSL_STRICT "ssl-strict"
#define SOUP_SESSION_ASYNC_CONTEXT "async-context"
#define SOUP_SESSION_TIMEOUT "timeout"
#define SOUP_SESSION_USER_AGENT "user-agent"
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 00fd8816..2bbf22d1 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -66,6 +66,7 @@ enum {
PROP_NON_BLOCKING,
PROP_IS_SERVER,
PROP_SSL_CREDENTIALS,
+ PROP_SSL_STRICT,
PROP_ASYNC_CONTEXT,
PROP_TIMEOUT,
@@ -81,6 +82,7 @@ typedef struct {
guint is_server:1;
guint timed_out:1;
gpointer ssl_creds;
+ gboolean ssl_strict;
GMainContext *async_context;
GSource *watch_src;
@@ -354,6 +356,18 @@ soup_socket_class_init (SoupSocketClass *socket_class)
"SSL credential information, passed from the session to the SSL implementation",
G_PARAM_READWRITE));
/**
+ * SOUP_SOCKET_SSL_STRICT:
+ *
+ * Alias for the #SoupSocket:ignore-ssl-cert-errors property.
+ **/
+ g_object_class_install_property (
+ object_class, PROP_SSL_STRICT,
+ g_param_spec_boolean (SOUP_SOCKET_SSL_STRICT,
+ "Strictly validate SSL certificates",
+ "Whether certificate errors should be considered a connection error",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ /**
* SOUP_SOCKET_ASYNC_CONTEXT:
*
* Alias for the #SoupSocket:async-context property. (The
@@ -492,6 +506,9 @@ set_property (GObject *object, guint prop_id,
case PROP_SSL_CREDENTIALS:
priv->ssl_creds = g_value_get_pointer (value);
break;
+ case PROP_SSL_STRICT:
+ priv->ssl_strict = g_value_get_boolean (value);
+ break;
case PROP_ASYNC_CONTEXT:
priv->async_context = g_value_get_pointer (value);
if (priv->async_context)
@@ -528,6 +545,9 @@ get_property (GObject *object, guint prop_id,
case PROP_SSL_CREDENTIALS:
g_value_set_pointer (value, priv->ssl_creds);
break;
+ case PROP_SSL_STRICT:
+ g_value_set_boolean (value, priv->ssl_strict);
+ break;
case PROP_ASYNC_CONTEXT:
g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
break;
@@ -1218,11 +1238,19 @@ read_from_network (SoupSocket *sock, gpointer buffer, gsize len,
return SOUP_SOCKET_ERROR;
}
+again:
status = g_io_channel_read_chars (priv->iochannel,
buffer, len, nread, &my_err);
if (my_err) {
- if (my_err->domain == SOUP_SSL_ERROR &&
- my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
+ if (g_error_matches (my_err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE) &&
+ !priv->ssl_strict) {
+ g_clear_error (&my_err);
+ goto again;
+ }
+
+ if (g_error_matches (my_err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE))
cond = G_IO_OUT;
g_propagate_error (error, my_err);
}
@@ -1517,11 +1545,19 @@ soup_socket_write (SoupSocket *sock, gconstpointer buffer,
return SOUP_SOCKET_WOULD_BLOCK;
}
+again:
status = g_io_channel_write_chars (priv->iochannel,
buffer, len, nwrote, &my_err);
if (my_err) {
- if (my_err->domain == SOUP_SSL_ERROR &&
- my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)
+ if (g_error_matches (my_err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE) &&
+ !priv->ssl_strict) {
+ g_clear_error (&my_err);
+ goto again;
+ }
+
+ if (g_error_matches (my_err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ))
cond = G_IO_IN;
g_propagate_error (error, my_err);
}
diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h
index 079297be..4106e86c 100644
--- a/libsoup/soup-socket.h
+++ b/libsoup/soup-socket.h
@@ -45,8 +45,9 @@ typedef struct {
#define SOUP_SOCKET_FLAG_NONBLOCKING "non-blocking"
#define SOUP_SOCKET_IS_SERVER "is-server"
#define SOUP_SOCKET_SSL_CREDENTIALS "ssl-creds"
+#define SOUP_SOCKET_SSL_STRICT "ssl-strict"
#define SOUP_SOCKET_ASYNC_CONTEXT "async-context"
-#define SOUP_SOCKET_TIMEOUT "timeout"
+#define SOUP_SOCKET_TIMEOUT "timeout"
typedef void (*SoupSocketCallback) (SoupSocket *sock,
guint status,
diff --git a/tests/test-utils.c b/tests/test-utils.c
index 0b13ca17..8d7e9f62 100644
--- a/tests/test-utils.c
+++ b/tests/test-utils.c
@@ -231,6 +231,11 @@ soup_test_session_new (GType type, ...)
session = (SoupSession *)g_object_new_valist (type, propname, args);
va_end (args);
+ g_object_set (G_OBJECT (session),
+ SOUP_SESSION_SSL_CA_FILE, SRCDIR "/test-cert.pem",
+ SOUP_SESSION_SSL_STRICT, FALSE,
+ NULL);
+
if (http_debug_level && !logger) {
SoupLoggerLogLevel level = MIN ((SoupLoggerLogLevel)http_debug_level, SOUP_LOGGER_LOG_BODY);