From e21e295bf09328d4e1f18c495d97605fbaae9d0d Mon Sep 17 00:00:00 2001
From: Ludovic Fauvet <etix@videolan.org>
Date: Tue, 19 Jun 2012 14:45:53 +0200
Subject: [PATCH 1/3] gnutls: show a dialog allowing the user to bypass
 certificate issues

---
 include/vlc_tls.h     |    2 +-
 modules/access/http.c |    4 +++-
 modules/misc/gnutls.c |   37 ++++++++++++++++++++++++++++++++++---
 src/network/tls.c     |    9 +++++----
 4 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/include/vlc_tls.h b/include/vlc_tls.h
index 66fcafd..32f3b4e 100644
--- a/include/vlc_tls.h
+++ b/include/vlc_tls.h
@@ -46,7 +46,7 @@ typedef struct vlc_tls
 } vlc_tls_t;
 
 VLC_API vlc_tls_t *vlc_tls_ClientCreate (vlc_object_t *, int fd,
-                                         const char *hostname);
+                                         const char *hostname, bool *pb_ssltrust);
 VLC_API void vlc_tls_ClientDelete (vlc_tls_t *);
 
 /* NOTE: It is assumed that a->sock.p_sys = a */
diff --git a/modules/access/http.c b/modules/access/http.c
index f7a1e85..257255b 100644
--- a/modules/access/http.c
+++ b/modules/access/http.c
@@ -188,6 +188,7 @@ struct access_sys_t
     bool b_pace_control;
     bool b_persist;
     bool b_has_size;
+    bool b_ssltrust;        /* invalid cert trusted by the user */
 
     vlc_array_t * cookies;
 };
@@ -287,6 +288,7 @@ static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
     p_sys->i_remaining = 0;
     p_sys->b_persist = false;
     p_sys->b_has_size = false;
+    p_sys->b_ssltrust = false;
     p_access->info.i_size = 0;
     p_access->info.i_pos  = 0;
     p_access->info.b_eof  = false;
@@ -1218,7 +1220,7 @@ static int Connect( access_t *p_access, uint64_t i_tell )
 
         /* TLS/SSL handshake */
         p_sys->p_tls = vlc_tls_ClientCreate( VLC_OBJECT(p_access), p_sys->fd,
-                                             p_sys->url.psz_host );
+                                             p_sys->url.psz_host, &p_sys->b_ssltrust );
         if( p_sys->p_tls == NULL )
         {
             msg_Err( p_access, "cannot establish HTTP/TLS session" );
diff --git a/modules/misc/gnutls.c b/modules/misc/gnutls.c
index c9fef1f..33c3e54 100644
--- a/modules/misc/gnutls.c
+++ b/modules/misc/gnutls.c
@@ -47,6 +47,8 @@
 #include <vlc_fs.h>
 #include <vlc_block.h>
 
+#include <vlc_dialog.h>
+
 #include <gcrypt.h>
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
@@ -59,7 +61,7 @@
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-static int  OpenClient  (vlc_tls_t *, int, const char *);
+static int  OpenClient  (vlc_tls_t *, int, const char *, bool *);
 static void CloseClient (vlc_tls_t *);
 static int  OpenServer  (vlc_object_t *);
 static void CloseServer (vlc_object_t *);
@@ -195,6 +197,7 @@ struct vlc_tls_sys
     gnutls_certificate_credentials_t x509_cred;
     char *hostname;
     bool handshaked;
+    bool *ssltrust;
 };
 
 
@@ -302,18 +305,44 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session)
         return -1;
     }
 
-    if (status)
+    if (status && !(*sys->ssltrust))
     {
+        char str_errors[512] = {0};
+        char *str_dialog;
+        int s = 0;
+
         msg_Err (session, "TLS session: access denied (status 0x%X)", status);
         for (const error_msg_t *e = cert_errors; e->flag; e++)
         {
             if (status & e->flag)
             {
                 msg_Err (session, "%s", e->msg);
+                s += sprintf(str_errors + s, "- %s\n", e->msg);
                 status &= ~e->flag;
             }
         }
 
+        if (asprintf(&str_dialog, "%s\n%s\n%s",
+                _( "The remote server cannot be trusted "
+                   "because of the following issues:" ),
+                str_errors,
+                _( "Would you like to continue despite the risk?" ) ) == -1)
+            return -1;
+
+
+        switch (dialog_Question(session, _("Peer certificate cannot be trusted"),
+                str_dialog,
+                _( "Yes" ), _( "No" ), NULL))
+        {
+            case 1:
+                free(str_dialog);
+                *sys->ssltrust = true;
+                goto ignorewarning;
+            default:
+                free(str_dialog);
+                break;
+        }
+
         if (status)
             msg_Err (session,
                      "unknown certificate error (you found a bug in VLC)");
@@ -322,6 +351,7 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session)
 
     /* certificate (host)name verification */
     const gnutls_datum_t *data;
+ignorewarning:
     data = gnutls_certificate_get_peers (sys->session, &(unsigned){0});
     if (data == NULL)
     {
@@ -499,7 +529,7 @@ gnutls_loadOSCAList (vlc_object_t *p_this,
 /**
  * Initializes a client-side TLS session.
  */
-static int OpenClient (vlc_tls_t *session, int fd, const char *hostname)
+static int OpenClient (vlc_tls_t *session, int fd, const char *hostname, bool *pb_ssltrust)
 {
     if (gnutls_Init (VLC_OBJECT(session)))
         return VLC_EGENERIC;
@@ -516,6 +546,7 @@ static int OpenClient (vlc_tls_t *session, int fd, const char *hostname)
     session->sock.pf_send = gnutls_Send;
     session->sock.pf_recv = gnutls_Recv;
     sys->handshaked = false;
+    sys->ssltrust = pb_ssltrust;
 
     int val = gnutls_certificate_allocate_credentials (&sys->x509_cred);
     if (val != 0)
diff --git a/src/network/tls.c b/src/network/tls.c
index 93892aa..a4dc583 100644
--- a/src/network/tls.c
+++ b/src/network/tls.c
@@ -139,12 +139,13 @@ int vlc_tls_ServerSessionHandshake (vlc_tls_t *ses)
 
 static int tls_client_start(void *func, va_list ap)
 {
-    int (*activate) (vlc_tls_t *, int fd, const char *hostname) = func;
+    int (*activate) (vlc_tls_t *, int fd, const char *hostname, bool *pb_ssltrust) = func;
     vlc_tls_t *session = va_arg (ap, vlc_tls_t *);
     int fd = va_arg (ap, int);
     const char *hostname = va_arg (ap, const char *);
+    bool *ssltrust = va_arg (ap, bool *);
 
-    return activate (session, fd, hostname);
+    return activate (session, fd, hostname, ssltrust);
 }
 
 static void tls_client_stop(void *func, va_list ap)
@@ -166,14 +167,14 @@ static void tls_client_stop(void *func, va_list ap)
  * @return NULL on error.
  **/
 vlc_tls_t *
-vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname)
+vlc_tls_ClientCreate (vlc_object_t *obj, int fd, const char *hostname, bool *pb_ssltrust)
 {
     vlc_tls_t *cl = vlc_custom_create (obj, sizeof (*cl), "tls client");
     if (unlikely(cl == NULL))
         return NULL;
 
     cl->u.module = vlc_module_load (cl, "tls client", NULL, false,
-                                    tls_client_start, cl, fd, hostname);
+                                    tls_client_start, cl, fd, hostname, pb_ssltrust);
     if (cl->u.module == NULL)
     {
         msg_Err (cl, "TLS client plugin not available");
-- 
1.7.10.4

