From: David Woodhouse <dwmw2@infradead.org>
Date: Mon, 14 Aug 2017 11:25:33 +0000 (+0100)
Subject: Kill HAVE_GNUTLS_CERTIFICATE_SET_KEY
X-Git-Tag: v8.00~142
X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=e42c1166e9e451eb5f9a99dfa0808636cd3db8d8;p=users%2Fdwmw2%2Fopenconnect.git

Kill HAVE_GNUTLS_CERTIFICATE_SET_KEY

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
---

diff --git a/configure.ac b/configure.ac
index fbc1a994..3e39ec1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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,
diff --git a/gnutls.c b/gnutls.c
index 4f3c46e6..4b9bc956 100644
--- a/gnutls.c
+++ b/gnutls.c
@@ -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>
@@ -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,
@@ -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
@@ -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 */
@@ -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"),
@@ -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! */
@@ -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.
@@ -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
 	}
 }
diff --git a/gnutls.h b/gnutls.h
index 3c4e7909..5eeacb0f 100644
--- a/gnutls.h
+++ b/gnutls.h
@@ -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);
 
diff --git a/gnutls_tpm.c b/gnutls_tpm.c
index 070796f5..ed417d19 100644
--- a/gnutls_tpm.c
+++ b/gnutls_tpm.c
@@ -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)
 {
@@ -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,
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 67b73f46..9d98590d 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -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;