Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Kill HAVE_GNUTLS_CERTIFICATE_SET_KEY
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
dwmw2 committed Aug 14, 2017
1 parent 95970ab commit e42c116
Show file tree
Hide file tree
Showing 5 changed files with 9 additions and 229 deletions.
2 changes: 0 additions & 2 deletions configure.ac
Expand Up @@ -452,8 +452,6 @@ case "$ssl_library" in
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
esp=yes
dtls=yes
AC_CHECK_FUNC(gnutls_certificate_set_key,
[AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_SET_KEY, 1, [From GnuTLS 3.0.4])], [])
AC_CHECK_FUNC(gnutls_pk_to_sign,
[AC_DEFINE(HAVE_GNUTLS_PK_TO_SIGN, 1, [From GnuTLS 3.1.0])], [])
AC_CHECK_FUNC(gnutls_pubkey_export2,
Expand Down
132 changes: 8 additions & 124 deletions gnutls.c
Expand Up @@ -27,12 +27,6 @@
#include <stdarg.h>
#include <stdlib.h>

#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
/* Shut up about gnutls_sign_callback_set() being deprecated. We only use it
in the GnuTLS 2.12 case, and there just isn't another way of doing it. */
#define GNUTLS_INTERNAL_BUILD 1
#endif

#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/crypto.h>
Expand Down Expand Up @@ -593,86 +587,9 @@ static int get_cert_name(gnutls_x509_crt_t cert, char *name, size_t namelen)
}

#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined (HAVE_GNUTLS_SYSTEM_KEYS)
#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
/* For GnuTLS 2.12 even if we *have* a privkey (as we do for PKCS#11), we
can't register it. So we have to use the cert_callback function. This
just hands out the certificate chain we prepared in load_certificate().
If we have a pkey then return that too; otherwise leave the key NULL —
we'll also have registered a sign_callback for the session, which will
handle that. */
static int gtls_cert_cb(gnutls_session_t sess, const gnutls_datum_t *req_ca_dn,
int nreqs, const gnutls_pk_algorithm_t *pk_algos,
int pk_algos_length, gnutls_retr2_st *st) {

struct openconnect_info *vpninfo = gnutls_session_get_ptr(sess);
int algo = GNUTLS_PK_RSA; /* TPM */
int i;

#ifdef HAVE_P11KIT
if (vpninfo->my_p11key) {
st->key_type = GNUTLS_PRIVKEY_PKCS11;
st->key.pkcs11 = vpninfo->my_p11key;
algo = gnutls_pkcs11_privkey_get_pk_algorithm(vpninfo->my_p11key, NULL);
};
#endif
for (i = 0; i < pk_algos_length; i++) {
if (algo == pk_algos[i])
break;
}
if (i == pk_algos_length)
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;

st->cert_type = GNUTLS_CRT_X509;
st->cert.x509 = vpninfo->my_certs;
st->ncerts = vpninfo->nr_my_certs;
st->deinit_all = 0;

return 0;
}

/* For GnuTLS 2.12, this has to set the cert_callback to the function
above, which will return the pkey and certs on demand. Or in the
case of TPM we can't make a suitable pkey, so we have to set a
sign_callback too (which is done in openconnect_open_https() since
it has to be done on the *session*). */
static int assign_privkey(struct openconnect_info *vpninfo,
gnutls_privkey_t pkey,
gnutls_x509_crt_t *certs,
unsigned int nr_certs,
uint8_t *free_certs)
{
vpninfo->my_certs = gnutls_calloc(nr_certs, sizeof(*certs));
if (!vpninfo->my_certs)
return GNUTLS_E_MEMORY_ERROR;

vpninfo->free_my_certs = gnutls_malloc(nr_certs);
if (!vpninfo->free_my_certs) {
gnutls_free(vpninfo->my_certs);
vpninfo->my_certs = NULL;
return GNUTLS_E_MEMORY_ERROR;
}

memcpy(vpninfo->free_my_certs, free_certs, nr_certs);
memcpy(vpninfo->my_certs, certs, nr_certs * sizeof(*certs));
vpninfo->nr_my_certs = nr_certs;

/* We are *keeping* the certs, unlike in GnuTLS 3 where our caller
can free them after gnutls_certificate_set_key() has been called.
So wipe the 'free_certs' array. */
memset(free_certs, 0, nr_certs);

gnutls_certificate_set_retrieve_function(vpninfo->https_cred,
gtls_cert_cb);
vpninfo->my_pkey = pkey;

return 0;
}
#else /* !SET_KEY */

/* For GnuTLS 3+ this is saner than the GnuTLS 2.12 version. But still we
have to convert the array of X509 certificates to gnutls_pcert_st for
ourselves. There's no function that takes a gnutls_privkey_t as the key
and gnutls_x509_crt_t certificates. */
/* We have to convert the array of X509 certificates to gnutls_pcert_st
for ourselves. There's no function that takes a gnutls_privkey_t as
the key and gnutls_x509_crt_t certificates. */
static int assign_privkey(struct openconnect_info *vpninfo,
gnutls_privkey_t pkey,
gnutls_x509_crt_t *certs,
Expand Down Expand Up @@ -708,17 +625,15 @@ static int assign_privkey(struct openconnect_info *vpninfo,
}
return err;
}
#endif /* !SET_KEY */

static int verify_signed_data(gnutls_pubkey_t pubkey, gnutls_privkey_t privkey,
const gnutls_datum_t *data, const gnutls_datum_t *sig)
{
#ifdef HAVE_GNUTLS_PK_TO_SIGN
gnutls_sign_algorithm_t algo = GNUTLS_SIGN_RSA_SHA1; /* TPM keys */
gnutls_sign_algorithm_t algo;

if (privkey != OPENCONNECT_TPM_PKEY)
algo = gnutls_pk_to_sign(gnutls_privkey_get_pk_algorithm(privkey, NULL),
GNUTLS_DIG_SHA1);
algo = gnutls_pk_to_sign(gnutls_privkey_get_pk_algorithm(privkey, NULL),
GNUTLS_DIG_SHA1);

return gnutls_pubkey_verify_data2(pubkey, algo, 0, data, sig);
#else
Expand Down Expand Up @@ -1415,16 +1330,6 @@ static int load_certificate(struct openconnect_info *vpninfo)
ret = -EIO;
goto out;
}
#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
/* This can be set now and doesn't need to be separately freed.
It goes with the pkey. This is a PITA; it would be better
if there was a way to get the p11key *back* from a privkey
that we *know* is based on one. In fact, since this is only
for GnuTLS 2.12 and we *know* the gnutls_privkey_st won't
ever change there, so we *could* do something evil... but
we won't :) */
vpninfo->my_p11key = p11key;
#endif /* !SET_KEY */
goto match_cert;
}
#endif /* HAVE_P11KIT */
Expand Down Expand Up @@ -1618,7 +1523,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
fdata.size = 20;
}

err = sign_dummy_data(vpninfo, pkey, &fdata, &pkey_sig);
err = gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA1, 0, &fdata, &pkey_sig);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Error signing test data with private key: %s\n"),
Expand Down Expand Up @@ -1882,7 +1787,7 @@ static int load_certificate(struct openconnect_info *vpninfo)
gnutls_free(extra_certs);

#if defined(HAVE_P11KIT) || defined(HAVE_TROUSERS) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
if (pkey && pkey != OPENCONNECT_TPM_PKEY)
if (pkey)
gnutls_privkey_deinit(pkey);
/* If we support arbitrary privkeys, we might have abused fdata.data
just to point to something to hash. Don't free it in that case! */
Expand Down Expand Up @@ -2315,10 +2220,6 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
}
gnutls_init(&vpninfo->https_sess, GNUTLS_CLIENT);
gnutls_session_set_ptr(vpninfo->https_sess, (void *) vpninfo);
#if defined(HAVE_TROUSERS) && !defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
if (vpninfo->my_pkey == OPENCONNECT_TPM_PKEY)
gnutls_sign_callback_set(vpninfo->https_sess, gtls2_tpm_sign_cb, vpninfo);
#endif
/*
* For versions of GnuTLS older than 3.2.9, we try to avoid long
* packets by silently disabling extensions such as SNI.
Expand Down Expand Up @@ -2512,23 +2413,6 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
Tspi_Context_Close(vpninfo->tpm_context);
vpninfo->tpm_context = 0;
}
#endif
#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
if (vpninfo->my_pkey && vpninfo->my_pkey != OPENCONNECT_TPM_PKEY) {
gnutls_privkey_deinit(vpninfo->my_pkey);
vpninfo->my_pkey = NULL;
/* my_p11key went with it */
}
if (vpninfo->my_certs) {
int i;
for (i = 0; i < vpninfo->nr_my_certs; i++)
if (vpninfo->free_my_certs[i])
gnutls_x509_crt_deinit(vpninfo->my_certs[i]);
gnutls_free(vpninfo->my_certs);
gnutls_free(vpninfo->free_my_certs);
vpninfo->my_certs = NULL;
vpninfo->free_my_certs = NULL;
}
#endif
}
}
Expand Down
27 changes: 0 additions & 27 deletions gnutls.h
Expand Up @@ -24,33 +24,6 @@

#include "openconnect-internal.h"

#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
int gtls2_tpm_sign_cb(gnutls_session_t sess, void *_vpninfo,
gnutls_certificate_type_t cert_type,
const gnutls_datum_t *cert, const gnutls_datum_t *data,
gnutls_datum_t *sig);
int gtls2_tpm_sign_dummy_data(struct openconnect_info *vpninfo,
const gnutls_datum_t *data,
gnutls_datum_t *sig);
#endif /* !HAVE_GNUTLS_CERTIFICATE_SET_KEY */

/* In GnuTLS 2.12 this can't be a real private key; we have to use the sign_callback
instead. But we want to set the 'pkey' variable to *something* non-NULL in order
to indicate that we aren't just using an x509 key. */
#define OPENCONNECT_TPM_PKEY ((void *)1UL)

static inline int sign_dummy_data(struct openconnect_info *vpninfo,
gnutls_privkey_t pkey,
const gnutls_datum_t *data,
gnutls_datum_t *sig)
{
#if defined(HAVE_TROUSERS) && !defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
if (pkey == OPENCONNECT_TPM_PKEY)
return gtls2_tpm_sign_dummy_data(vpninfo, data, sig);
#endif
return gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA1, 0, data, sig);
}

int load_tpm_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig);

Expand Down
68 changes: 1 addition & 67 deletions gnutls_tpm.c
Expand Up @@ -33,68 +33,6 @@
#ifdef HAVE_TROUSERS

/* Signing function for TPM privkeys, set with gnutls_privkey_import_ext() */
static int tpm_sign_fn(gnutls_privkey_t key, void *_vpninfo,
const gnutls_datum_t *data, gnutls_datum_t *sig);


#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
/* We *want* to use gnutls_privkey_import_ext() to create a privkey with our
own signing function tpm_sign_fn(). But GnuTLS 2.12 doesn't support that,
so instead we have to register this sign_callback function with the
*session* */
int gtls2_tpm_sign_cb(gnutls_session_t sess, void *_vpninfo,
gnutls_certificate_type_t cert_type,
const gnutls_datum_t *cert, const gnutls_datum_t *data,
gnutls_datum_t *sig)
{
struct openconnect_info *vpninfo = _vpninfo;

if (cert_type != GNUTLS_CRT_X509)
return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;

return tpm_sign_fn(NULL, vpninfo, data, sig);
}

/* In GnuTLS 2.12 since we don't have a normal privkey and hence can't just
use gnutls_privkey_sign_data() with it, we have to jump through hoops to
prepare the hash in exactly the right way and call our internal TPM
signing function. */
int gtls2_tpm_sign_dummy_data(struct openconnect_info *vpninfo,
const gnutls_datum_t *data,
gnutls_datum_t *sig)
{
static const unsigned char ber_encode[15] = {
0x30, 0x21, /* SEQUENCE, length 31 */
0x30, 0x09, /* SEQUENCE, length 9 */
0x06, 0x05, /* OBJECT_ID, length 5 */
0x2b, 0x0e, 0x03, 0x02, 0x1a, /* SHA1 OID: 1.3.14.3.2.26 */
0x05, 0x00, /* NULL (parameters) */
0x04, 0x14, /* OCTET_STRING, length 20 */
/* followed by the 20-byte sha1 */
};
gnutls_datum_t hash;
unsigned char digest[sizeof(ber_encode) + SHA1_SIZE];
size_t shalen = SHA1_SIZE;
int err;

err = gnutls_fingerprint(GNUTLS_DIG_SHA1, data,
&digest[sizeof(ber_encode)], &shalen);
if (err) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to SHA1 input data for signing: %s\n"),
gnutls_strerror(err));
return err;
}

memcpy(digest, ber_encode, sizeof(ber_encode));

hash.data = digest;
hash.size = sizeof(digest);

return tpm_sign_fn(NULL, vpninfo, &hash, sig);
}
#endif /* !HAVE_GNUTLS_CERTIFICATE_SET_KEY */

static int tpm_sign_fn(gnutls_privkey_t key, void *_vpninfo,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
Expand Down Expand Up @@ -258,18 +196,14 @@ int load_tpm_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
goto out_srkpol;
}

#ifdef HAVE_GNUTLS_CERTIFICATE_SET_KEY
gnutls_privkey_init(pkey);
/* This would be nicer if there was a destructor callback. I could
allocate a data structure with the TPM handles and the vpninfo
pointer, and destroy that properly when the key is destroyed. */
gnutls_privkey_import_ext(*pkey, GNUTLS_PK_RSA, vpninfo, tpm_sign_fn, NULL, 0);
#else
*pkey = OPENCONNECT_TPM_PKEY;
#endif

retry_sign:
err = sign_dummy_data(vpninfo, *pkey, fdata, pkey_sig);
err = gnutls_privkey_sign_data(*pkey, GNUTLS_DIG_SHA1, 0, fdata, pkey_sig);
if (err == GNUTLS_E_INSUFFICIENT_CREDENTIALS) {
if (!vpninfo->tpm_key_policy) {
err = Tspi_Context_CreateObject(vpninfo->tpm_context,
Expand Down
9 changes: 0 additions & 9 deletions openconnect-internal.h
Expand Up @@ -503,15 +503,6 @@ struct openconnect_info {
TSS_HKEY tpm_key;
TSS_HPOLICY tpm_key_policy;
#endif
#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
#ifdef HAVE_P11KIT
gnutls_pkcs11_privkey_t my_p11key;
#endif
gnutls_privkey_t my_pkey;
gnutls_x509_crt_t *my_certs;
uint8_t *free_my_certs;
unsigned int nr_my_certs;
#endif
#endif /* OPENCONNECT_GNUTLS */
struct pin_cache *pin_cache;
struct keepalive_info ssl_times;
Expand Down

0 comments on commit e42c116

Please sign in to comment.