[vlc-commits] gnutls: ask user if certificate is invalid

Rémi Denis-Courmont git at videolan.org
Sun Sep 30 15:45:15 CEST 2012


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Sep 30 16:30:41 2012 +0300| [ac8f45552c4b30747092f8eada9e4d7d4493bbbc] | committer: Rémi Denis-Courmont

gnutls: ask user if certificate is invalid

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=ac8f45552c4b30747092f8eada9e4d7d4493bbbc
---

 modules/misc/gnutls.c |   91 ++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 72 insertions(+), 19 deletions(-)

diff --git a/modules/misc/gnutls.c b/modules/misc/gnutls.c
index 1248276..3946c7a 100644
--- a/modules/misc/gnutls.c
+++ b/modules/misc/gnutls.c
@@ -33,6 +33,7 @@
 #include <vlc_plugin.h>
 #include <vlc_tls.h>
 #include <vlc_block.h>
+#include <vlc_dialog.h>
 
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
@@ -240,26 +241,69 @@ static int gnutls_ContinueHandshake (vlc_tls_t *session, const char *host)
 }
 
 
+/**
+ * Looks up certificate in known hosts data base.
+ * @return 0 on success, -1 on failure.
+ */
+static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
+                              const gnutls_datum_t *restrict datum)
+{
+    assert (host != NULL);
+
+    if (dialog_Question (obj, N_("Insecure site"),
+         N_("You attempted to reach %s, but security certificate presented by "
+            "the server could not be verified."
+            "This problem may be caused by a configuration error "
+            "on the server or by a serious breach of network security.\n\n"
+            "If in doubt, abort now.\n"),
+                         N_("Abort"), N_("View certificate"), NULL, host) != 2)
+         return -1;
+
+    gnutls_x509_crt_t cert;
+    gnutls_datum_t desc;
+
+    if (gnutls_x509_crt_init (&cert))
+        return -1;
+    if (gnutls_x509_crt_import (cert, datum, GNUTLS_X509_FMT_DER)
+     || gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &desc))
+    {
+        gnutls_x509_crt_deinit (cert);
+        return -1;
+    }
+    gnutls_x509_crt_deinit (cert);
+
+    int val = dialog_Question (obj, N_("Insecure site"),
+         N_("This is the certificate presented by %s:\n%s\n\n"
+            "If in doubt, abort now.\n"),
+                           N_("Abort"), N_("Proceed anyway"), NULL,
+                           host, desc.data);
+    gnutls_free (desc.data);
+
+    return (val == 2) ? 0 : -1;
+}
+
+
 static struct
 {
     int flag;
-    const char msg[44];
+    const char msg[43];
+    bool strict;
 } cert_errs[] =
 {
     { GNUTLS_CERT_INVALID,
-        "Certificate could not be verified" },
+        "Certificate could not be verified", false },
     { GNUTLS_CERT_REVOKED,
-        "Certificate was revoked" },
+        "Certificate was revoked", true },
     { GNUTLS_CERT_SIGNER_NOT_FOUND,
-        "Certificate's signer was not found" },
+        "Certificate's signer was not found", false },
     { GNUTLS_CERT_SIGNER_NOT_CA,
-        "Certificate's signer is not a CA" },
+        "Certificate's signer is not a CA", true },
     { GNUTLS_CERT_INSECURE_ALGORITHM,
-        "Insecure certificate signature algorithm" },
+      "Insecure certificate signature algorithm", true },
     { GNUTLS_CERT_NOT_ACTIVATED,
-        "Certificate is not yet activated" },
+        "Certificate is not yet activated", true },
     { GNUTLS_CERT_EXPIRED,
-        "Certificate has expired" },
+        "Certificate has expired", true },
 };
 
 
@@ -290,21 +334,33 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host)
             {
                 msg_Err (session, " * %s", cert_errs[i].msg);
                 status &= ~cert_errs[i].flag;
+                if (cert_errs[i].strict)
+                    val = -1;
             }
 
         if (status)
+        {
             msg_Err (session, " * Unknown verification error 0x%04X", status);
-        return -1;
+            val = -1;
+        }
+        status = -1;
     }
 
     /* certificate (host)name verification */
     const gnutls_datum_t *data;
-    data = gnutls_certificate_get_peers (sys->session, &(unsigned){0});
-    if (data == NULL)
+    unsigned count;
+    data = gnutls_certificate_get_peers (sys->session, &count);
+    if (data == NULL || count == 0)
     {
         msg_Err (session, "Peer certificate not available");
         return -1;
     }
+    msg_Dbg (session, "%u certificate(s) in the list", count);
+
+    if (val || host == NULL)
+        return val;
+    if (status && gnutls_CertSearch (session, host, data))
+        return -1;
 
     gnutls_x509_crt_t cert;
     val = gnutls_x509_crt_init (&cert);
@@ -322,18 +378,15 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host)
         goto error;
     }
 
-    if (host != NULL && !gnutls_x509_crt_check_hostname (cert, host))
+    val = !gnutls_x509_crt_check_hostname (cert, host);
+    if (val)
     {
         msg_Err (session, "Certificate does not match \"%s\"", host);
-        goto error;
+        val = gnutls_CertSearch (session, host, data);
     }
-
-    gnutls_x509_crt_deinit (cert);
-    return 0;
-
 error:
-    gnutls_x509_crt_deinit (cert);
-    return -1;
+    gnutls_x509_crt_init (&cert);
+    return val ? -1 : 0;
 }
 
 static int



More information about the vlc-commits mailing list