SoupAddress *remote_addr, *tunnel_addr;
SoupURI *proxy_uri;
gpointer ssl_creds;
+ gboolean ssl_strict;
GMainContext *async_context;
PROP_TUNNEL_ADDRESS,
PROP_PROXY_URI,
PROP_SSL_CREDS,
+ PROP_SSL_STRICT,
PROP_ASYNC_CONTEXT,
PROP_TIMEOUT,
PROP_IDLE_TIMEOUT,
"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",
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)
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;
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);
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);
#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"
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;
if (result == G_IO_STATUS_AGAIN ||
result == G_IO_STATUS_ERROR)
return result;
-
- chan->established = TRUE;
}
result = gnutls_record_recv (chan->session, buf, count);
if (result == G_IO_STATUS_AGAIN ||
result == G_IO_STATUS_ERROR)
return result;
-
- chan->established = TRUE;
}
result = gnutls_record_send (chan->session, buf, count);
typedef struct {
char *ssl_ca_file;
SoupSSLCredentials *ssl_creds;
+ gboolean ssl_strict;
SoupMessageQueue *queue;
PROP_MAX_CONNS_PER_HOST,
PROP_USE_NTLM,
PROP_SSL_CA_FILE,
+ PROP_SSL_STRICT,
PROP_ASYNC_CONTEXT,
PROP_TIMEOUT,
PROP_USER_AGENT,
* so hold a ref on the default GResolver.
*/
priv->resolver = g_resolver_get_default ();
+
+ priv->ssl_strict = TRUE;
}
static void
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
}
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)
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;
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,
#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"
PROP_NON_BLOCKING,
PROP_IS_SERVER,
PROP_SSL_CREDENTIALS,
+ PROP_SSL_STRICT,
PROP_ASYNC_CONTEXT,
PROP_TIMEOUT,
guint is_server:1;
guint timed_out:1;
gpointer ssl_creds;
+ gboolean ssl_strict;
GMainContext *async_context;
GSource *watch_src;
"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
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)
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;
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);
}
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);
}
#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,
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);