+2005-03-09 Dan Winship <danw@novell.com>
+
+ * libsoup/soup-gnutls.c (soup_gnutls_read): return G_IO_STATUS_EOF
+ if gnutls returns 0. [#73352]
+ (verify_certificate): put an #ifdef around
+ GNUTLS_CERT_NOT_TRUSTED so it works with gnutls 1.2.x. [#57811]
+
2005-01-08 Not Zed <NotZed@Ximian.com>
** See ximian bug #70323.
* libsoup/soup-connection-ntlm.c: replace all unsigned long/long
types with guint32, as the code needs 32 bit longs.
+2004-10-20 Dan Winship <danw@novell.com>
+
+ * libsoup/soup-gnutls.c: Commit the alleged changes from the 10-06
+ commit, which somehow did not actually get committed then.
+
+ * libsoup/soup-connection.c (SoupConnectionPrivate): add a flag
+ indicating whether or not the connection is connected.
+ (tunnel_connect_finished): If successful, set connected. If the
+ server returns a 3xx response, translate it to 407 (under the
+ assumption that it's trying to redirect us to an HTML login page,
+ as in bug 68531). Use soup_socket_start_proxy_ssl() rather than
+ soup_socket_start_ssl().
+ (socket_connect_result, soup_connection_connect_sync): If
+ successful, set connected
+ (soup_connection_disconnect): Don't emit "disconnected" if we
+ aren't yet connected, or the message that was waiting for this
+ connection may get stranded in the queue. (also part of 68531)
+
+ * libsoup/soup-socket.c (soup_socket_start_proxy_ssl): New, starts
+ SSL and lets the caller pass the expected hostname. Fixes a
+ problem where SSL certification validation would always fail if
+ you used a proxy, because it was comparing the cert against the
+ proxy's hostname. (68583)
+
2004-10-06 Dan Winship <danw@novell.com>
* libsoup/soup-ssl.h (SoupSocketError): add
SoupMessage *cur_req;
time_t last_used;
- gboolean in_use;
+ gboolean connected, in_use;
};
#define PARENT_TYPE G_TYPE_OBJECT
clear_current_request (conn);
if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
- if (!soup_socket_start_ssl (conn->priv->socket))
+ if (soup_socket_start_proxy_ssl (conn->priv->socket,
+ conn->priv->origin_uri->host))
+ conn->priv->connected = TRUE;
+ else
status = SOUP_STATUS_SSL_FAILED;
+ } else if (SOUP_STATUS_IS_REDIRECTION (status)) {
+ /* Oops, the proxy thinks we're a web browser. */
+ status = SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED;
}
g_signal_emit (conn, signals[CONNECT_RESULT], 0,
return;
}
+ conn->priv->connected = TRUE;
+
done:
g_signal_emit (conn, signals[CONNECT_RESULT], 0,
proxified_status (conn, status));
g_object_unref (connect_msg);
}
- if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+ if (SOUP_STATUS_IS_SUCCESSFUL (status))
+ conn->priv->connected = TRUE;
+ else {
fail:
if (conn->priv->socket) {
g_object_unref (conn->priv->socket);
soup_socket_disconnect (conn->priv->socket);
g_object_unref (conn->priv->socket);
conn->priv->socket = NULL;
+
+ /* Don't emit "disconnected" if we aren't yet connected */
+ if (!conn->priv->connected)
+ return;
+
+ conn->priv->connected = FALSE;
g_signal_emit (conn, signals[DISCONNECTED], 0);
if (!conn->priv->cur_req ||
} SoupGNUTLSChannel;
static gboolean
-verify_certificate (gnutls_session session, const char *hostname)
+verify_certificate (gnutls_session session, const char *hostname, GError **err)
{
int status;
status = gnutls_certificate_verify_peers (session);
if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) {
- g_warning ("No certificate was sent.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "No SSL certificate was sent.");
return FALSE;
}
if (status & GNUTLS_CERT_INVALID ||
+#ifdef GNUTLS_CERT_NOT_TRUSTED
status & GNUTLS_CERT_NOT_TRUSTED ||
+#endif
status & GNUTLS_CERT_REVOKED)
{
- g_warning ("The certificate is not trusted.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "The SSL certificate is not trusted.");
return FALSE;
}
if (gnutls_certificate_expiration_time_peers (session) < time (0)) {
- g_warning ("The certificate has expired.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "The SSL certificate has expired.");
return FALSE;
}
if (gnutls_certificate_activation_time_peers (session) > time (0)) {
- g_warning ("The certificate is not yet activated.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "The SSL certificate is not yet activated.");
return FALSE;
}
gnutls_x509_crt cert;
if (gnutls_x509_crt_init (&cert) < 0) {
- g_warning ("Error initializing certificate.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "Error initializing SSL certificate.");
return FALSE;
}
session, &cert_list_size);
if (cert_list == NULL) {
- g_warning ("No certificate was found.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "No SSL certificate was found.");
return FALSE;
}
if (gnutls_x509_crt_import (cert, &cert_list[0],
GNUTLS_X509_FMT_DER) < 0) {
- g_warning ("The certificate could not be parsed.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "The SSL certificate could not be parsed.");
return FALSE;
}
if (!gnutls_x509_crt_check_hostname (cert, hostname)) {
- g_warning ("The certificate does not match hostname.");
+ g_set_error (err, SOUP_SSL_ERROR,
+ SOUP_SSL_ERROR_CERTIFICATE,
+ "The SSL certificate does not match the hostname.");
return FALSE;
}
}
-
+
return TRUE;
}
return G_IO_STATUS_ERROR;
}
- if (chan->type == SOUP_SSL_TYPE_CLIENT &&
- chan->cred->have_ca_file) {
- if (!verify_certificate (chan->session, chan->hostname)) {
- g_set_error (err, G_IO_CHANNEL_ERROR,
- G_IO_CHANNEL_ERROR_FAILED,
- "Unable to verify certificate");
- return G_IO_STATUS_ERROR;
- }
- }
+ if (chan->type == SOUP_SSL_TYPE_CLIENT && chan->cred->have_ca_file &&
+ !verify_certificate (chan->session, chan->hostname, err))
+ return G_IO_STATUS_ERROR;
return G_IO_STATUS_NORMAL;
}
} else {
*bytes_read = result;
- return G_IO_STATUS_NORMAL;
+ return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
}
}
gboolean
soup_socket_start_ssl (SoupSocket *sock)
{
+ return soup_socket_start_proxy_ssl (sock, soup_address_get_name (sock->priv->remote_addr));
+}
+
+/**
+ * soup_socket_start_proxy_ssl:
+ * @sock: the socket
+ * @ssl_host: hostname of the SSL server
+ *
+ * Starts using SSL on @socket, expecting to find a host named
+ * @ssl_host.
+ *
+ * Return value: success or failure
+ **/
+gboolean
+soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host)
+{
GIOChannel *ssl_chan;
get_iochannel (sock);
ssl_chan = soup_ssl_wrap_iochannel (
sock->priv->iochannel, sock->priv->is_server ?
SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
- soup_address_get_name (sock->priv->remote_addr),
- sock->priv->ssl_creds);
+ ssl_host, sock->priv->ssl_creds);
if (!ssl_chan)
return FALSE;
gboolean soup_socket_listen (SoupSocket *sock,
SoupAddress *local_addr);
gboolean soup_socket_start_ssl (SoupSocket *sock);
+gboolean soup_socket_start_proxy_ssl (SoupSocket *sock,
+ const char *ssl_host);
void soup_socket_disconnect (SoupSocket *sock);
gboolean soup_socket_is_connected (SoupSocket *sock);