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

gnutls: support SSH-style first use certificate authentication

If a certificate does not validate, the user will be given the option
to accept it manually. GnuTLS will then store the certificate in its
known hosts database.
parent c8d471d5
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
# include "config.h" # include "config.h"
#endif #endif
#include <time.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
...@@ -41,7 +42,12 @@ ...@@ -41,7 +42,12 @@
# define gnutls_certificate_set_x509_system_trust(c) \ # define gnutls_certificate_set_x509_system_trust(c) \
(c, GNUTLS_E_UNIMPLEMENTED_FEATURE) (c, GNUTLS_E_UNIMPLEMENTED_FEATURE)
#endif #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" #include "dhparams.h"
/***************************************************************************** /*****************************************************************************
...@@ -247,9 +253,29 @@ static int gnutls_ContinueHandshake (vlc_tls_t *session, const char *host, ...@@ -247,9 +253,29 @@ static int gnutls_ContinueHandshake (vlc_tls_t *session, const char *host,
* @return 0 on success, -1 on failure. * @return 0 on success, -1 on failure.
*/ */
static int gnutls_CertSearch (vlc_tls_t *obj, const char *host, static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
const char *service,
const gnutls_datum_t *restrict datum) const gnutls_datum_t *restrict datum)
{ {
assert (host != NULL); assert (host != NULL);
/* Look up mismatching certificate in store */
int val = gnutls_verify_stored_pubkey (NULL, NULL, host, service,
GNUTLS_CRT_X509, datum, 0);
switch (val)
{
case 0:
msg_Dbg (obj, "certificate key match for %s", host);
return 0;
case GNUTLS_E_NO_CERTIFICATE_FOUND:
msg_Dbg (obj, "no known certificates for %s", host);
break;
case GNUTLS_E_CERTIFICATE_KEY_MISMATCH:
msg_Dbg (obj, "certificate keys mismatch for %s", host);
break;
default:
msg_Err (obj, "certificate key match error for %s: %s", host,
gnutls_strerror (val));
return -1;
}
if (dialog_Question (obj, N_("Insecure site"), if (dialog_Question (obj, N_("Insecure site"),
N_("You attempted to reach %s, but security certificate presented by " N_("You attempted to reach %s, but security certificate presented by "
...@@ -273,14 +299,25 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host, ...@@ -273,14 +299,25 @@ static int gnutls_CertSearch (vlc_tls_t *obj, const char *host,
} }
gnutls_x509_crt_deinit (cert); gnutls_x509_crt_deinit (cert);
int val = dialog_Question (obj, N_("Insecure site"), val = dialog_Question (obj, N_("Insecure site"),
N_("This is the certificate presented by %s:\n%s\n\n" N_("This is the certificate presented by %s:\n%s\n\n"
"If in doubt, abort now.\n"), "If in doubt, abort now.\n"),
N_("Abort"), N_("Proceed anyway"), NULL, N_("Abort"), N_("Accept 24 hours"),
host, desc.data); N_("Accept permanently"), host, desc.data);
gnutls_free (desc.data); gnutls_free (desc.data);
return (val == 2) ? 0 : -1; time_t expiry = 0;
switch (val)
{
case 2:
time (&expiry);
expiry += 24 * 60 * 60;
case 3:
gnutls_store_pubkey (NULL, NULL, host, service, GNUTLS_CRT_X509,
datum, expiry, 0);
return 0;
}
return -1;
} }
...@@ -361,7 +398,7 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host, ...@@ -361,7 +398,7 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host,
if (val || host == NULL) if (val || host == NULL)
return val; return val;
if (status && gnutls_CertSearch (session, host, data)) if (status && gnutls_CertSearch (session, host, service, data))
return -1; return -1;
gnutls_x509_crt_t cert; gnutls_x509_crt_t cert;
...@@ -384,7 +421,7 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host, ...@@ -384,7 +421,7 @@ static int gnutls_HandshakeAndValidate (vlc_tls_t *session, const char *host,
if (val) if (val)
{ {
msg_Err (session, "Certificate does not match \"%s\"", host); msg_Err (session, "Certificate does not match \"%s\"", host);
val = gnutls_CertSearch (session, host, data); val = gnutls_CertSearch (session, host, service, data);
} }
error: error:
gnutls_x509_crt_init (&cert); gnutls_x509_crt_init (&cert);
......
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