New SoupMessageFlag to report whether it has dealt with a trusted certificate
authorGustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
Thu, 18 Feb 2010 16:05:15 +0000 (14:05 -0200)
committerDan Winship <danw@gnome.org>
Sun, 21 Feb 2010 15:06:11 +0000 (10:06 -0500)
https://bugzilla.gnome.org/show_bug.cgi?id=610374

libsoup/soup-message-io.c
libsoup/soup-message.c
libsoup/soup-message.h
libsoup/soup-socket.c
libsoup/soup-socket.h

index 73c8ae6..fc0e14d 100644 (file)
@@ -342,6 +342,17 @@ read_metadata (SoupMessage *msg, gboolean to_blank)
                }
        }
 
+       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;
 }
 
index ded0198..7c0b802 100644 (file)
@@ -1258,6 +1258,7 @@ soup_message_cleanup_response (SoupMessage *req)
                priv->decoders = g_slist_delete_link (priv->decoders, priv->decoders);
        }
        priv->msg_flags &= ~SOUP_MESSAGE_CONTENT_DECODED;
+       priv->msg_flags &= ~SOUP_MESSAGE_CERTIFICATE_TRUSTED;
 
        req->status_code = SOUP_STATUS_NONE;
        if (req->reason_phrase) {
@@ -1283,6 +1284,9 @@ soup_message_cleanup_response (SoupMessage *req)
  * indicate that it has removed the Content-Encoding on a message (and
  * so headers such as Content-Length may no longer accurately describe
  * the body).
+ * @SOUP_MESSAGE_CERTIFICATE_TRUSTED: if %TRUE after an https response
+ * has been received, indicates that the server's SSL certificate is
+ * trusted according to the session's CA.
  *
  * Various flags that can be set on a #SoupMessage to alter its
  * behavior.
index 2638620..3f3ee14 100644 (file)
@@ -105,11 +105,12 @@ 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),
+       SOUP_MESSAGE_NO_REDIRECT          = (1 << 1),
 #ifndef LIBSOUP_DISABLE_DEPRECATED
-       SOUP_MESSAGE_OVERWRITE_CHUNKS = (1 << 3),
+       SOUP_MESSAGE_OVERWRITE_CHUNKS     = (1 << 3),
 #endif
-       SOUP_MESSAGE_CONTENT_DECODED  = (1 << 4)
+       SOUP_MESSAGE_CONTENT_DECODED      = (1 << 4),
+       SOUP_MESSAGE_CERTIFICATE_TRUSTED  = (1 << 5)
 } SoupMessageFlags;
 
 void           soup_message_set_flags           (SoupMessage        *msg,
index 2bbf22d..4f570a7 100644 (file)
@@ -69,6 +69,7 @@ enum {
        PROP_SSL_STRICT,
        PROP_ASYNC_CONTEXT,
        PROP_TIMEOUT,
+       PROP_TRUSTED_CERTIFICATE,
 
        LAST_PROP
 };
@@ -83,6 +84,7 @@ typedef struct {
        guint timed_out:1;
        gpointer ssl_creds;
        gboolean ssl_strict;
+       gboolean trusted_certificate;
 
        GMainContext   *async_context;
        GSource        *watch_src;
@@ -368,6 +370,21 @@ soup_socket_class_init (SoupSocketClass *socket_class)
                                      TRUE,
                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
        /**
+        * 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.
+        **/
+       g_object_class_install_property (
+               object_class, PROP_TRUSTED_CERTIFICATE,
+               g_param_spec_boolean (SOUP_SOCKET_TRUSTED_CERTIFICATE,
+                                    "Trusted Certificate",
+                                    "Whether the server certificate is trusted, if this is an SSL socket",
+                                    FALSE,
+                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       /**
         * SOUP_SOCKET_ASYNC_CONTEXT:
         *
         * Alias for the #SoupSocket:async-context property. (The
@@ -509,6 +526,9 @@ set_property (GObject *object, guint prop_id,
        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)
@@ -548,6 +568,9 @@ get_property (GObject *object, guint prop_id,
        case PROP_SSL_STRICT:
                g_value_set_boolean (value, priv->ssl_strict);
                break;
+       case PROP_TRUSTED_CERTIFICATE:
+               g_value_set_boolean (value, priv->trusted_certificate);
+               break;
        case PROP_ASYNC_CONTEXT:
                g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
                break;
@@ -1011,6 +1034,12 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
        if (!ssl_chan)
                return FALSE;
 
+       /* This is optimistic, we will set this to false if we get a
+        * cert error from one of the I/O calls
+        */
+       if (priv->ssl_creds)
+               priv->trusted_certificate = TRUE;
+
        priv->iochannel = ssl_chan;
        g_io_channel_unref (real_chan);
 
@@ -1245,6 +1274,7 @@ again:
                if (g_error_matches (my_err, SOUP_SSL_ERROR,
                                     SOUP_SSL_ERROR_CERTIFICATE) &&
                    !priv->ssl_strict) {
+                       priv->trusted_certificate = FALSE;
                        g_clear_error (&my_err);
                        goto again;
                }
@@ -1552,6 +1582,7 @@ again:
                if (g_error_matches (my_err, SOUP_SSL_ERROR,
                                     SOUP_SSL_ERROR_CERTIFICATE) &&
                    !priv->ssl_strict) {
+                       priv->trusted_certificate = FALSE;
                        g_clear_error (&my_err);
                        goto again;
                }
index 4106e86..2e039d9 100644 (file)
@@ -40,14 +40,15 @@ typedef struct {
        void (*_libsoup_reserved4) (void);
 } SoupSocketClass;
 
-#define SOUP_SOCKET_LOCAL_ADDRESS    "local-address"
-#define SOUP_SOCKET_REMOTE_ADDRESS   "remote-address"
-#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_LOCAL_ADDRESS       "local-address"
+#define SOUP_SOCKET_REMOTE_ADDRESS      "remote-address"
+#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_TRUSTED_CERTIFICATE "trusted-certificate"
+#define SOUP_SOCKET_ASYNC_CONTEXT       "async-context"
+#define SOUP_SOCKET_TIMEOUT             "timeout"
 
 typedef void (*SoupSocketCallback)            (SoupSocket         *sock,
                                               guint               status,