GNUTLS: Tidy up the cert authentication callback

This commit is contained in:
Aaron Jones 2016-09-16 12:09:56 +00:00
parent 75d7d47a7e
commit fde101b9b2
No known key found for this signature in database
GPG key ID: EC6F86EE9CD840B5

View file

@ -39,14 +39,6 @@
# include <gnutls/crypto.h> # include <gnutls/crypto.h>
#endif #endif
#if GNUTLS_VERSION_MAJOR < 3
static int cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs,
const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr_st *st);
#else
static int cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs,
const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr2_st *st);
#endif
#define SSL_P(x) *((gnutls_session_t *)F->ssl) #define SSL_P(x) *((gnutls_session_t *)F->ssl)
@ -66,6 +58,42 @@ static gnutls_priority_t default_priority;
/*
* We only have one certificate to authenticate with, as both a client and server.
*
* Unfortunately, GNUTLS tries to be clever, and as client, will attempt to use a certificate that the server will
* trust. We usually use self-signed certs, though, so the result of this search is always nothing. Therefore, it
* uses no certificate to authenticate as a client. This is undesirable, as it breaks fingerprint authentication;
* e.g. the connect::fingerprint on the remote ircd will not match.
*
* Thus, we use this callback to force GNUTLS to authenticate with our (server) certificate as a client.
*/
static int
rb_ssl_cert_auth_cb(gnutls_session_t session,
const gnutls_datum_t *const req_ca_rdn, const int req_ca_rdn_len,
const gnutls_pk_algorithm_t *const sign_algos, const int sign_algos_len,
#if (GNUTLS_VERSION_MAJOR < 3)
gnutls_retr_st *const st)
#else
gnutls_retr2_st *const st)
#endif
{
#if (GNUTLS_VERSION_MAJOR < 3)
st->type = GNUTLS_CRT_X509;
#else
st->cert_type = GNUTLS_CRT_X509;
st->key_type = GNUTLS_PRIVKEY_X509;
#endif
st->ncerts = client_cert_count;
st->cert.x509 = client_cert;
st->key.x509 = client_key;
st->deinit_all = 0;
return 0;
}
void void
rb_ssl_shutdown(rb_fde_t *const F) rb_ssl_shutdown(rb_fde_t *const F)
{ {
@ -291,9 +319,9 @@ rb_init_ssl(void)
} }
#if GNUTLS_VERSION_MAJOR < 3 #if GNUTLS_VERSION_MAJOR < 3
gnutls_certificate_client_set_retrieve_function(server_cert_key, cert_callback); gnutls_certificate_client_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb);
#else #else
gnutls_certificate_set_retrieve_function(server_cert_key, cert_callback); gnutls_certificate_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb);
#endif #endif
#if (GNUTLS_VERSION_MAJOR < 3) #if (GNUTLS_VERSION_MAJOR < 3)
@ -303,38 +331,6 @@ rb_init_ssl(void)
return 1; return 1;
} }
/* We only have one certificate to authenticate with, as both client and server. Unfortunately,
* GnuTLS tries to be clever, and as client, will attempt to use a certificate that the server
* will trust. We usually use self-signed certs, though, so the result of this search is always
* nothing. Therefore, it uses no certificate to authenticate as a client. This is undesirable
* as it breaks fingerprint auth. Thus, we use this callback to force GnuTLS to always
* authenticate with our certificate at all times.
*/
#if GNUTLS_VERSION_MAJOR < 3
static int
cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs,
const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr_st *st)
#else
static int
cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs,
const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr2_st *st)
#endif
{
/* XXX - ugly hack. Tell GnuTLS to use the first (only) certificate we have for auth. */
#if (GNUTLS_VERSION_MAJOR < 3)
st->type = GNUTLS_CRT_X509;
#else
st->cert_type = GNUTLS_CRT_X509;
st->key_type = GNUTLS_PRIVKEY_X509;
#endif
st->ncerts = client_cert_count;
st->cert.x509 = client_cert;
st->key.x509 = client_key;
st->deinit_all = 0;
return 0;
}
static void static void
rb_free_datum_t(gnutls_datum_t * d) rb_free_datum_t(gnutls_datum_t * d)
{ {
@ -391,7 +387,7 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, c
} }
/* In addition to creating the certificate set, we also need to store our cert elsewhere /* In addition to creating the certificate set, we also need to store our cert elsewhere
* so we can force GnuTLS to identify with it when acting as a client. * so we can force GNUTLS to identify with it when acting as a client.
*/ */
gnutls_x509_privkey_init(&client_key); gnutls_x509_privkey_init(&client_key);
if ((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) if ((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS)