]> git.sesse.net Git - vlc/blobdiff - modules/misc/gnutls.c
Use _WIN32 rather than WIN32 (same for WIN64)
[vlc] / modules / misc / gnutls.c
index 56c51f3ec83f8f3e822c3ed95d1497a39502ee9d..4a6056abe1d237c350c9b3202bdd97fb61ac5d45 100644 (file)
 
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
-#if (GNUTLS_VERSION_NUMBER < 0x030014)
-# define gnutls_certificate_set_x509_system_trust(c) \
-    (c, GNUTLS_E_UNIMPLEMENTED_FEATURE)
-#endif
-#if (GNUTLS_VERSION_NUMBER < 0x03000D)
-# define gnutls_verify_stored_pubkey(db,tdb,host,serv,ctype,cert,fl) \
-    (db, host, serv, ctype, cert, fl, GNUTLS_E_NO_CERTIFICATE_FOUND)
-# define gnutls_store_pubkey(db,tdb,host,serv,ctype,cert,e,fl) \
-    (db, host, serv, ctype, cert, fl, GNUTLS_E_UNIMPLEMENTED_FEATURE)
-#endif
 #include "dhparams.h"
 
 /*****************************************************************************
@@ -83,13 +73,13 @@ vlc_module_begin ()
     set_capability( "tls client", 1 )
     set_callbacks( OpenClient, CloseClient )
     set_category( CAT_ADVANCED )
-    set_subcategory( SUBCAT_ADVANCED_MISC )
+    set_subcategory( SUBCAT_ADVANCED_NETWORK )
 
     add_submodule ()
         set_description( N_("GNU TLS server") )
         set_capability( "tls server", 1 )
         set_category( CAT_ADVANCED )
-        set_subcategory( SUBCAT_ADVANCED_MISC )
+        set_subcategory( SUBCAT_ADVANCED_NETWORK )
         set_callbacks( OpenServer, CloseServer )
 
         add_string ("gnutls-priorities", "NORMAL", PRIORITIES_TEXT,
@@ -114,7 +104,7 @@ static int gnutls_Init (vlc_object_t *p_this)
         goto error;
     }
 
-    const char *psz_version = gnutls_check_version ("2.6.6");
+    const char *psz_version = gnutls_check_version ("3.0.20");
     if (psz_version == NULL)
     {
         msg_Err (p_this, "unsupported GnuTLS version");
@@ -149,7 +139,7 @@ static int gnutls_Error (vlc_object_t *obj, int val)
     switch (val)
     {
         case GNUTLS_E_AGAIN:
-#ifdef WIN32
+#ifdef _WIN32
             WSASetLastError (WSAEWOULDBLOCK);
 #else
             errno = EAGAIN;
@@ -157,7 +147,7 @@ static int gnutls_Error (vlc_object_t *obj, int val)
             break;
 
         case GNUTLS_E_INTERRUPTED:
-#ifdef WIN32
+#ifdef _WIN32
             WSASetLastError (WSAEINTR);
 #else
             errno = EINTR;
@@ -170,7 +160,7 @@ static int gnutls_Error (vlc_object_t *obj, int val)
             if (!gnutls_error_is_fatal (val))
                 msg_Err (obj, "Error above should be handled");
 #endif
-#ifdef WIN32
+#ifdef _WIN32
             WSASetLastError (WSAECONNRESET);
 #else
             errno = ECONNRESET;
@@ -226,16 +216,23 @@ static int gnutls_ContinueHandshake (vlc_tls_t *session, const char *host,
     vlc_tls_sys_t *sys = session->sys;
     int val;
 
-#ifdef WIN32
+#ifdef _WIN32
     WSASetLastError (0);
 #endif
-    val = gnutls_handshake (sys->session);
-    if ((val == GNUTLS_E_AGAIN) || (val == GNUTLS_E_INTERRUPTED))
-        return 1 + gnutls_record_get_direction (sys->session);
+    do
+    {
+        val = gnutls_handshake (sys->session);
+        msg_Dbg (session, "TLS handshake: %s", gnutls_strerror (val));
+
+        if ((val == GNUTLS_E_AGAIN) || (val == GNUTLS_E_INTERRUPTED))
+            /* I/O event: return to caller's poll() loop */
+            return 1 + gnutls_record_get_direction (sys->session);
+    }
+    while (val < 0 && !gnutls_error_is_fatal (val));
 
     if (val < 0)
     {
-#ifdef WIN32
+#ifdef _WIN32
         msg_Dbg (session, "Winsock error %d", WSAGetLastError ());
 #endif
         msg_Err (session, "TLS handshake error: %s", gnutls_strerror (val));
@@ -257,9 +254,11 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
                               const gnutls_datum_t *restrict datum)
 {
     assert (host != NULL);
+
     /* Look up mismatching certificate in store */
     int val = gnutls_verify_stored_pubkey (NULL, NULL, host, service,
                                            GNUTLS_CRT_X509, datum, 0);
+    const char *msg;
     switch (val)
     {
         case 0:
@@ -267,9 +266,24 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
             return 0;
         case GNUTLS_E_NO_CERTIFICATE_FOUND:
             msg_Dbg (obj, "no known certificates for %s", host);
+            msg = N_("You attempted to reach %s. "
+                "However the security certificate presented by the server "
+                "is unknown and could not be authenticated by any trusted "
+                "Certification Authority. "
+                "This problem may be caused by a configuration error "
+                "or an attempt to breach your security or your privacy.\n\n"
+                "If in doubt, abort now.\n");
             break;
         case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
             msg_Dbg (obj, "certificate keys mismatch for %s", host);
+            msg = N_("You attempted to reach %s. "
+                "However the security certificate presented by the server "
+                "changed since the previous visit "
+                "and was not authenticated by any trusted "
+                "Certification Authority. "
+                "This problem may be caused by a configuration error "
+                "or an attempt to breach your security or your privacy.\n\n"
+                "If in doubt, abort now.\n");
             break;
         default:
             msg_Err (obj, "certificate key match error for %s: %s", host,
@@ -277,14 +291,9 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
             return -1;
     }
 
-    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;
+    if (dialog_Question (obj, _("Insecure site"), vlc_gettext (msg),
+                         _("Abort"), _("View certificate"), NULL, host) != 2)
+        return -1;
 
     gnutls_x509_crt_t cert;
     gnutls_datum_t desc;
@@ -299,11 +308,11 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
     }
     gnutls_x509_crt_deinit (cert);
 
-    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_("Accept 24 hours"),
-                           N_("Accept permanently"), host, desc.data);
+    val = dialog_Question (obj, _("Insecure site"),
+         _("This is the certificate presented by %s:\n%s\n\n"
+           "If in doubt, abort now.\n"),
+                           _("Abort"), _("Accept 24 hours"),
+                           _("Accept permanently"), host, desc.data);
     gnutls_free (desc.data);
 
     time_t expiry = 0;
@@ -313,8 +322,11 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
             time (&expiry);
             expiry += 24 * 60 * 60;
         case 3:
-            gnutls_store_pubkey (NULL, NULL, host, service, GNUTLS_CRT_X509,
-                                 datum, expiry, 0);
+            val = gnutls_store_pubkey (NULL, NULL, host, service,
+                                       GNUTLS_CRT_X509, datum, expiry, 0);
+            if (val)
+                msg_Err (obj, "cannot store X.509 certificate: %s",
+                         gnutls_strerror (val));
             return 0;
     }
     return -1;
@@ -323,25 +335,17 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
 
 static struct
 {
-    int flag;
-    const char msg[43];
-    bool strict;
+    unsigned flag;
+    const char msg[29];
 } cert_errs[] =
 {
-    { GNUTLS_CERT_INVALID,
-        "Certificate could not be verified", false },
-    { GNUTLS_CERT_REVOKED,
-        "Certificate was revoked", true },
-    { GNUTLS_CERT_SIGNER_NOT_FOUND,
-        "Certificate's signer was not found", false },
-    { GNUTLS_CERT_SIGNER_NOT_CA,
-        "Certificate's signer is not a CA", true },
-    { GNUTLS_CERT_INSECURE_ALGORITHM,
-      "Insecure certificate signature algorithm", true },
-    { GNUTLS_CERT_NOT_ACTIVATED,
-        "Certificate is not yet activated", true },
-    { GNUTLS_CERT_EXPIRED,
-        "Certificate has expired", true },
+    { GNUTLS_CERT_INVALID,            "Certificate not verified"     },
+    { GNUTLS_CERT_REVOKED,            "Certificate revoked"          },
+    { GNUTLS_CERT_SIGNER_NOT_FOUND,   "Signer not found"             },
+    { GNUTLS_CERT_SIGNER_NOT_CA,      "Signer not a CA"              },
+    { GNUTLS_CERT_INSECURE_ALGORITHM, "Signature algorithm insecure" },
+    { GNUTLS_CERT_NOT_ACTIVATED,      "Certificate not activated"    },
+    { GNUTLS_CERT_EXPIRED,            "Certificate expired"          },
 };
 
 
@@ -364,25 +368,14 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host,
                  gnutls_strerror (val));
         return -1;
     }
-
     if (status)
     {
-        msg_Err (session, "Certificate verification failure:");
+        msg_Err (session, "Certificate verification failure (0x%04X)", status);
         for (size_t i = 0; i < sizeof (cert_errs) / sizeof (cert_errs[0]); i++)
             if (status & cert_errs[i].flag)
-            {
                 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);
-            val = -1;
-        }
-        status = -1;
+        if (status & ~(GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND))
+            return -1;
     }
 
     /* certificate (host)name verification */
@@ -424,8 +417,8 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host,
         val = gnutls_CertSearch (session, host, service, data);
     }
 error:
-    gnutls_x509_crt_init (&cert);
-    return val ? -1 : 0;
+    gnutls_x509_crt_deinit (cert);
+    return val;
 }
 
 static int