}
}
- if (soup_socket_is_ssl (io->sock)) {
- gboolean trusted_certificate;
-
- g_object_get (io->sock,
- SOUP_SOCKET_TRUSTED_CERTIFICATE, &trusted_certificate,
- NULL);
-
- if (trusted_certificate)
- soup_message_set_flags (msg, priv->msg_flags | SOUP_MESSAGE_CERTIFICATE_TRUSTED);
- }
-
return TRUE;
}
if (!read_metadata (msg, TRUE))
return;
+ if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
+ soup_socket_is_ssl (io->sock)) {
+ GTlsCertificate *certificate;
+ GTlsCertificateFlags errors;
+
+ g_object_get (io->sock,
+ SOUP_SOCKET_TLS_CERTIFICATE, &certificate,
+ SOUP_SOCKET_TLS_ERRORS, &errors,
+ NULL);
+ if (certificate) {
+ g_object_set (msg,
+ SOUP_MESSAGE_TLS_CERTIFICATE, certificate,
+ SOUP_MESSAGE_TLS_ERRORS, errors,
+ NULL);
+ g_object_unref (certificate);
+ }
+ }
+
/* We need to "rewind" io->read_meta_buf back one line.
* That SHOULD be two characters (CR LF), but if the
* web server was stupid, it might only be one.
GSList *decoders;
SoupURI *first_party;
+
+ GTlsCertificate *tls_certificate;
+ GTlsCertificateFlags tls_errors;
} SoupMessagePrivate;
#define SOUP_MESSAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_MESSAGE, SoupMessagePrivate))
PROP_REQUEST_HEADERS,
PROP_RESPONSE_BODY,
PROP_RESPONSE_HEADERS,
+ PROP_TLS_CERTIFICATE,
+ PROP_TLS_ERRORS,
LAST_PROP
};
"The HTTP response headers",
SOUP_TYPE_MESSAGE_HEADERS,
G_PARAM_READABLE));
+ /**
+ * SOUP_MESSAGE_TLS_CERTIFICATE:
+ *
+ * Alias for the #SoupMessage:tls-certificate property. (The
+ * TLS certificate associated with the message, if any.)
+ **/
+ g_object_class_install_property (
+ object_class, PROP_TLS_CERTIFICATE,
+ g_param_spec_object (SOUP_MESSAGE_TLS_CERTIFICATE,
+ "TLS Certificate",
+ "The TLS certificate associated with the message",
+ G_TYPE_TLS_CERTIFICATE,
+ G_PARAM_READWRITE));
+ /**
+ * SOUP_MESSAGE_TLS_ERRORS:
+ *
+ * Alias for the #SoupMessage:tls-errors property. (The
+ * verification errors on #SoupMessage:tls-certificate.)
+ **/
+ g_object_class_install_property (
+ object_class, PROP_TLS_ERRORS,
+ g_param_spec_flags (SOUP_MESSAGE_TLS_ERRORS,
+ "TLS Errors",
+ "The verification errors on the message's TLS certificate",
+ G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
+ G_PARAM_READWRITE));
}
static void
case PROP_FIRST_PARTY:
soup_message_set_first_party (msg, g_value_get_boxed (value));
break;
+ case PROP_TLS_CERTIFICATE:
+ if (priv->tls_certificate)
+ g_object_unref (priv->tls_certificate);
+ priv->tls_certificate = g_value_dup_object (value);
+ if (priv->tls_certificate && !priv->tls_errors)
+ priv->msg_flags |= SOUP_MESSAGE_CERTIFICATE_TRUSTED;
+ break;
+ case PROP_TLS_ERRORS:
+ priv->tls_errors = g_value_get_flags (value);
+ if (priv->tls_errors)
+ priv->msg_flags &= ~SOUP_MESSAGE_CERTIFICATE_TRUSTED;
+ else if (priv->tls_certificate)
+ priv->msg_flags |= SOUP_MESSAGE_CERTIFICATE_TRUSTED;
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_RESPONSE_HEADERS:
g_value_set_boxed (value, msg->response_headers);
break;
+ case PROP_TLS_CERTIFICATE:
+ g_value_set_object (value, priv->tls_certificate);
+ break;
+ case PROP_TLS_ERRORS:
+ g_value_set_flags (value, priv->tls_errors);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
priv->http_version = priv->orig_http_version;
+ if (priv->tls_certificate) {
+ g_object_unref (priv->tls_certificate);
+ priv->tls_certificate = NULL;
+ }
+ priv->tls_errors = 0;
+
g_object_notify (G_OBJECT (req), SOUP_MESSAGE_STATUS_CODE);
g_object_notify (G_OBJECT (req), SOUP_MESSAGE_REASON_PHRASE);
g_object_notify (G_OBJECT (req), SOUP_MESSAGE_HTTP_VERSION);
g_object_notify (G_OBJECT (req), SOUP_MESSAGE_FLAGS);
+ g_object_notify (G_OBJECT (req), SOUP_MESSAGE_TLS_CERTIFICATE);
+ g_object_notify (G_OBJECT (req), SOUP_MESSAGE_TLS_ERRORS);
}
/**
priv->first_party = soup_uri_copy (first_party);
g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_FIRST_PARTY);
}
+
+/**
+ * soup_message_get_https_status:
+ * @msg: a #SoupMessage
+ * @certificate: (out) (transfer none): @msg's TLS certificate
+ * @errors: (out): the verification status of @certificate
+ *
+ * If @msg is using https, this retrieves the #GTlsCertificate
+ * associated with its connection, and the #GTlsCertificateFlags showing
+ * what problems, if any, have been found with that certificate.
+ *
+ * Return value: %TRUE if @msg uses https, %FALSE if not
+ *
+ * Since: 2.34
+ */
+gboolean
+soup_message_get_https_status (SoupMessage *msg,
+ GTlsCertificate **certificate,
+ GTlsCertificateFlags *errors)
+{
+ SoupMessagePrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
+
+ priv = SOUP_MESSAGE_GET_PRIVATE (msg);
+
+ if (certificate)
+ *certificate = priv->tls_certificate;
+ if (errors)
+ *errors = priv->tls_errors;
+ return priv->tls_certificate != NULL;
+}
#define SOUP_MESSAGE_REQUEST_HEADERS "request-headers"
#define SOUP_MESSAGE_RESPONSE_BODY "response-body"
#define SOUP_MESSAGE_RESPONSE_HEADERS "response-headers"
+#define SOUP_MESSAGE_TLS_CERTIFICATE "tls-certificate"
+#define SOUP_MESSAGE_TLS_ERRORS "tls-errors"
SoupMessage *soup_message_new (const char *method,
const char *uri_string);
SoupURI *soup_message_get_first_party (SoupMessage *msg);
void soup_message_set_first_party (SoupMessage *msg,
SoupURI *first_party);
+
typedef enum {
SOUP_MESSAGE_NO_REDIRECT = (1 << 1),
#ifndef LIBSOUP_DISABLE_DEPRECATED
SOUP_MESSAGE_CERTIFICATE_TRUSTED = (1 << 5)
} SoupMessageFlags;
-void soup_message_set_flags (SoupMessage *msg,
- SoupMessageFlags flags);
+void soup_message_set_flags (SoupMessage *msg,
+ SoupMessageFlags flags);
+
+SoupMessageFlags soup_message_get_flags (SoupMessage *msg);
+
+gboolean soup_message_get_https_status (SoupMessage *msg,
+ GTlsCertificate **certificate,
+ GTlsCertificateFlags *errors);
-SoupMessageFlags soup_message_get_flags (SoupMessage *msg);
/* Specialized signal handlers */
guint soup_message_add_header_handler (SoupMessage *msg,
PROP_TIMEOUT,
PROP_TRUSTED_CERTIFICATE,
PROP_CLEAN_DISPOSE,
+ PROP_TLS_CERTIFICATE,
+ PROP_TLS_ERRORS,
LAST_PROP
};
GSocket *gsock;
GPollableInputStream *istream;
GPollableOutputStream *ostream;
+ GTlsCertificateFlags tls_errors;
guint non_blocking:1;
guint is_server:1;
guint ssl_strict:1;
- guint trusted_certificate:1;
guint clean_dispose:1;
gpointer ssl_creds;
* SOUP_SOCKET_TRUSTED_CERTIFICATE:
*
* Alias for the #SoupSocket:trusted-certificate
- * property. Notice that this property's value is only useful
- * if the socket is for an SSL connection, and only reliable
- * after some data has been transferred to or from it.
+ * property.
**/
g_object_class_install_property (
object_class, PROP_TRUSTED_CERTIFICATE,
"Trusted Certificate",
"Whether the server certificate is trusted, if this is an SSL socket",
FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_READABLE));
/**
* SOUP_SOCKET_ASYNC_CONTEXT:
*
"Warn on unclean dispose",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+ /**
+ * SOUP_SOCKET_TLS_CERTIFICATE:
+ *
+ * Alias for the #SoupSocket:tls-certificate
+ * property. Note that this property's value is only useful
+ * if the socket is for a TLS connection, and only reliable
+ * after some data has been transferred to or from it.
+ *
+ * Since: 2.34
+ **/
+ g_object_class_install_property (
+ object_class, PROP_TLS_CERTIFICATE,
+ g_param_spec_object (SOUP_SOCKET_TLS_CERTIFICATE,
+ "TLS certificate",
+ "The peer's TLS certificate",
+ G_TYPE_TLS_CERTIFICATE,
+ G_PARAM_READABLE));
+ /**
+ * SOUP_SOCKET_TLS_ERRORS:
+ *
+ * Alias for the #SoupSocket:tls-errors
+ * property. Note that this property's value is only useful
+ * if the socket is for a TLS connection, and only reliable
+ * after some data has been transferred to or from it.
+ *
+ * Since: 2.34
+ **/
+ g_object_class_install_property (
+ object_class, PROP_TLS_ERRORS,
+ g_param_spec_flags (SOUP_SOCKET_TLS_ERRORS,
+ "TLS errors",
+ "Errors with the peer's TLS certificate",
+ G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
+ G_PARAM_READABLE));
}
case PROP_SSL_STRICT:
priv->ssl_strict = g_value_get_boolean (value);
break;
- case PROP_TRUSTED_CERTIFICATE:
- priv->trusted_certificate = g_value_get_boolean (value);
- break;
case PROP_ASYNC_CONTEXT:
priv->async_context = g_value_get_pointer (value);
if (priv->async_context)
g_value_set_boolean (value, priv->ssl_strict);
break;
case PROP_TRUSTED_CERTIFICATE:
- g_value_set_boolean (value, priv->trusted_certificate);
+ g_value_set_boolean (value, priv->tls_errors == 0);
break;
case PROP_ASYNC_CONTEXT:
g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
case PROP_TIMEOUT:
g_value_set_uint (value, priv->timeout);
break;
+ case PROP_TLS_CERTIFICATE:
+ if (G_IS_TLS_CONNECTION (priv->conn))
+ g_value_set_object (value, g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (priv->conn)));
+ else
+ g_value_set_object (value, NULL);
+ break;
+ case PROP_TLS_ERRORS:
+ g_value_set_flags (value, priv->tls_errors);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
{
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+ priv->tls_errors = errors;
if (soup_ssl_credentials_verify_certificate (priv->ssl_creds,
- cert, errors))
- return TRUE;
-
- if (!priv->ssl_strict) {
- priv->trusted_certificate = FALSE;
+ cert, errors)) {
+ priv->tls_errors &= ~G_TLS_CERTIFICATE_UNKNOWN_CA;
return TRUE;
}
- return FALSE;
+
+ return !priv->ssl_strict;
}
/**
g_object_unref (priv->conn);
priv->conn = G_IO_STREAM (conn);
- priv->trusted_certificate = TRUE;
+ priv->tls_errors = 0;
g_signal_connect (conn, "accept-certificate",
G_CALLBACK (soup_socket_accept_certificate),
sock);
#define SOUP_SOCKET_TRUSTED_CERTIFICATE "trusted-certificate"
#define SOUP_SOCKET_ASYNC_CONTEXT "async-context"
#define SOUP_SOCKET_TIMEOUT "timeout"
+#define SOUP_SOCKET_TLS_CERTIFICATE "tls-certificate"
+#define SOUP_SOCKET_TLS_ERRORS "tls-errors"
typedef void (*SoupSocketCallback) (SoupSocket *sock,
guint status,