Commit ac8f4555 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

gnutls: ask user if certificate is invalid

parent d40dc861
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_tls.h> #include <vlc_tls.h>
#include <vlc_block.h> #include <vlc_block.h>
#include <vlc_dialog.h>
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
#include <gnutls/x509.h> #include <gnutls/x509.h>
...@@ -240,26 +241,69 @@ static int gnutls_ContinueHandshake (vlc_tls_t *session, const char *host) ...@@ -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 static struct
{ {
int flag; int flag;
const char msg[44]; const char msg[43];
bool strict;
} cert_errs[] = } cert_errs[] =
{ {
{ GNUTLS_CERT_INVALID, { GNUTLS_CERT_INVALID,
"Certificate could not be verified" }, "Certificate could not be verified", false },
{ GNUTLS_CERT_REVOKED, { GNUTLS_CERT_REVOKED,
"Certificate was revoked" }, "Certificate was revoked", true },
{ GNUTLS_CERT_SIGNER_NOT_FOUND, { GNUTLS_CERT_SIGNER_NOT_FOUND,
"Certificate's signer was not found" }, "Certificate's signer was not found", false },
{ GNUTLS_CERT_SIGNER_NOT_CA, { GNUTLS_CERT_SIGNER_NOT_CA,
"Certificate's signer is not a CA" }, "Certificate's signer is not a CA", true },
{ GNUTLS_CERT_INSECURE_ALGORITHM, { GNUTLS_CERT_INSECURE_ALGORITHM,
"Insecure certificate signature algorithm" }, "Insecure certificate signature algorithm", true },
{ GNUTLS_CERT_NOT_ACTIVATED, { GNUTLS_CERT_NOT_ACTIVATED,
"Certificate is not yet activated" }, "Certificate is not yet activated", true },
{ GNUTLS_CERT_EXPIRED, { 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) ...@@ -290,21 +334,33 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host)
{ {
msg_Err (session, " * %s", cert_errs[i].msg); msg_Err (session, " * %s", cert_errs[i].msg);
status &= ~cert_errs[i].flag; status &= ~cert_errs[i].flag;
if (cert_errs[i].strict)
val = -1;
} }
if (status) if (status)
{
msg_Err (session, " * Unknown verification error 0x%04X", status); msg_Err (session, " * Unknown verification error 0x%04X", status);
return -1; val = -1;
}
status = -1;
} }
/* certificate (host)name verification */ /* certificate (host)name verification */
const gnutls_datum_t *data; const gnutls_datum_t *data;
data = gnutls_certificate_get_peers (sys->session, &(unsigned){0}); unsigned count;
if (data == NULL) data = gnutls_certificate_get_peers (sys->session, &count);
if (data == NULL || count == 0)
{ {
msg_Err (session, "Peer certificate not available"); msg_Err (session, "Peer certificate not available");
return -1; 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; gnutls_x509_crt_t cert;
val = gnutls_x509_crt_init (&cert); val = gnutls_x509_crt_init (&cert);
...@@ -322,18 +378,15 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host) ...@@ -322,18 +378,15 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host)
goto error; 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); 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: error:
gnutls_x509_crt_deinit (cert); gnutls_x509_crt_init (&cert);
return -1; return val ? -1 : 0;
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment