From 7475c3447d99ac271966f6bc80ad36bfcb234474 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sat, 12 Dec 2009 00:02:04 +0000 Subject: [PATCH] Simplify creation of secret from DH negotiation. PKCS#11 says to use the low order bytes, and that's what we do here. This bears more research to make sure we're doing this in a standard way. --- egg/egg-dh.c | 150 +++++++++++++++++++---------------------------- egg/egg-dh.h | 19 +++--- egg/tests/unit-test-dh.c | 54 ++++------------- 3 files changed, 84 insertions(+), 139 deletions(-) diff --git a/egg/egg-dh.c b/egg/egg-dh.c index d90abc0..f162f4d 100644 --- a/egg/egg-dh.c +++ b/egg/egg-dh.c @@ -21,9 +21,10 @@ #include "config.h" -#include "egg-asn1.h" #include "egg-dh.h" -#include "egg-openssl.h" +#include "egg-secure-memory.h" + +#define DEBUG_DH_SECRET 0 typedef struct _DHGroup { const gchar *name; @@ -238,16 +239,18 @@ egg_dh_default_params (const gchar *name, gcry_mpi_t *prime, gcry_mpi_t *base) gcry_error_t gcry; g_return_val_if_fail (name, FALSE); - g_return_val_if_fail (prime, FALSE); - g_return_val_if_fail (base, FALSE); for (group = dh_groups; group->name; ++group) { if (g_str_equal (group->name, name)) { - gcry = gcry_mpi_scan (prime, GCRYMPI_FMT_USG, group->prime, group->n_prime, NULL); - g_return_val_if_fail (gcry == 0, FALSE); - g_return_val_if_fail (gcry_mpi_get_nbits (*prime) == group->bits, FALSE); - gcry = gcry_mpi_scan (base, GCRYMPI_FMT_USG, group->base, group->n_base, NULL); - g_return_val_if_fail (gcry == 0, FALSE); + if (prime) { + gcry = gcry_mpi_scan (prime, GCRYMPI_FMT_USG, group->prime, group->n_prime, NULL); + g_return_val_if_fail (gcry == 0, FALSE); + g_return_val_if_fail (gcry_mpi_get_nbits (*prime) == group->bits, FALSE); + } + if (base) { + gcry = gcry_mpi_scan (base, GCRYMPI_FMT_USG, group->base, group->n_base, NULL); + g_return_val_if_fail (gcry == 0, FALSE); + } return TRUE; } } @@ -300,91 +303,56 @@ egg_dh_gen_pair (gcry_mpi_t p, gcry_mpi_t g, guint bits, return TRUE; } -gboolean -egg_dh_gen_secret (gcry_mpi_t Y, gcry_mpi_t x, - gcry_mpi_t p, gcry_mpi_t *k) -{ - gint bits; - - g_return_val_if_fail (Y, FALSE); - g_return_val_if_fail (x, FALSE); - g_return_val_if_fail (p, FALSE); - g_return_val_if_fail (k, FALSE); - - bits = gcry_mpi_get_nbits (p); - g_return_val_if_fail (bits >= 0, FALSE); - - *k = gcry_mpi_snew (bits); - g_return_val_if_fail (*k, FALSE); - gcry_mpi_powm (*k, Y, x, p); - - return TRUE; -} - -typedef struct _Parameters { - gcry_mpi_t p; - gcry_mpi_t g; -} Parameters; - -#ifndef EGG_DH_NO_ASN1 - -static gboolean -parse_der_pkcs3 (const guchar *data, gsize n_data, Parameters *params) +gpointer +egg_dh_gen_secret (gcry_mpi_t peer, gcry_mpi_t priv, + gcry_mpi_t prime, gsize bytes) { - ASN1_TYPE asn; - guchar *buf_p, *buf_g; - gsize n_buf_p, n_buf_g; gcry_error_t gcry; + guchar *value; + gsize n_value; + gsize offset = 0; + gcry_mpi_t k; + gint bits; - asn = egg_asn1_decode ("PK.DHParameter", data, n_data); - if (!asn) - return FALSE; - - buf_p = egg_asn1_read_value (asn, "prime", &n_buf_p, (EggAllocator)g_realloc); - buf_g = egg_asn1_read_value (asn, "base", &n_buf_g, (EggAllocator)g_realloc); - g_return_val_if_fail (buf_p && buf_g, FALSE); - gcry = gcry_mpi_scan (¶ms->p, GCRYMPI_FMT_STD, buf_p, n_buf_p, &n_buf_p); - g_return_val_if_fail (gcry == 0, FALSE); - gcry = gcry_mpi_scan (¶ms->g, GCRYMPI_FMT_STD, buf_g, n_buf_g, &n_buf_g); - g_return_val_if_fail (gcry == 0, FALSE); - - g_free (buf_p); - g_free (buf_g); - return TRUE; -} - -static void -parse_openssl_pkcs3 (GQuark type, const guchar *data, gsize n_data, - GHashTable *headers, gpointer user_data) -{ - Parameters *params = user_data; - - /* Only parse the first one */ - if (params->p != NULL) - return; - - if (g_quark_try_string ("DH PARAMETERS") == type) - parse_der_pkcs3 (data, n_data, params); -} - -gboolean -egg_dh_parse_pkcs3 (const guchar *data, gsize n_data, gcry_mpi_t *p, gcry_mpi_t *g) -{ - Parameters params; - - g_return_val_if_fail (data, FALSE); - g_return_val_if_fail (p, FALSE); - g_return_val_if_fail (g, FALSE); + g_return_val_if_fail (peer, NULL); + g_return_val_if_fail (priv, NULL); + g_return_val_if_fail (prime, NULL); + + bits = gcry_mpi_get_nbits (prime); + g_return_val_if_fail (bits >= 0, NULL); + + k = gcry_mpi_snew (bits); + g_return_val_if_fail (k, NULL); + gcry_mpi_powm (k, peer, priv, prime); + + /* Write out the secret */ + gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_value, k); + g_return_val_if_fail (gcry == 0, NULL); + if (n_value < bytes) + offset = bytes - n_value; + value = egg_secure_alloc (n_value + offset); + memset (value, 0, n_value + offset); + gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value + offset, n_value, &n_value, k); + g_return_val_if_fail (gcry == 0, NULL); + +#if DEBUG_DH_SECRET + g_printerr ("DH SECRET: "); + gcry_mpi_dump (k); + gcry_mpi_release (k); +#endif + + if (bytes != 0 && bytes < n_value) { + offset = n_value - bytes; + memmove (value, value + offset, bytes); + egg_secure_clear (value + bytes, offset); + } - memset (¶ms, 0, sizeof (params)); - if (!parse_der_pkcs3 (data, n_data, ¶ms)) - egg_openssl_pem_parse (data, n_data, parse_openssl_pkcs3, ¶ms); +#if DEBUG_DH_SECRET + gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, bytes, NULL); + g_printerr ("RAW SECRET: "); + gcry_mpi_dump (k); + gcry_mpi_release (k); +#endif - if (!params.p || !params.g) - return FALSE; - *p = params.p; - *g = params.g; - return TRUE; + return value; } - -#endif /* EGG_DH_NO_ASN1 */ diff --git a/egg/egg-dh.h b/egg/egg-dh.h index 55d4077..cfdb3d0 100644 --- a/egg/egg-dh.h +++ b/egg/egg-dh.h @@ -26,7 +26,9 @@ #include -gboolean egg_dh_default_params (const gchar *name, gcry_mpi_t *prime, gcry_mpi_t *base); +gboolean egg_dh_default_params (const gchar *name, + gcry_mpi_t *prime, + gcry_mpi_t *base); gboolean egg_dh_default_params_raw (const gchar *name, gconstpointer *prime, @@ -34,12 +36,15 @@ gboolean egg_dh_default_params_raw (const gchar *name gconstpointer *base, gsize *n_base); -gboolean egg_dh_gen_pair (gcry_mpi_t p, gcry_mpi_t g, guint bits, gcry_mpi_t *X, gcry_mpi_t *x); +gboolean egg_dh_gen_pair (gcry_mpi_t prime, + gcry_mpi_t base, + guint bits, + gcry_mpi_t *pub, + gcry_mpi_t *priv); -gboolean egg_dh_gen_secret (gcry_mpi_t Y, gcry_mpi_t x, gcry_mpi_t p, gcry_mpi_t *k); - -#ifndef EGG_DH_NO_ASN1 -gboolean egg_dh_parse_pkcs3 (const guchar *data, gsize n_data, gcry_mpi_t *p, gcry_mpi_t *g); -#endif +gpointer egg_dh_gen_secret (gcry_mpi_t peer, + gcry_mpi_t priv, + gcry_mpi_t prime, + gsize bytes); #endif /* EGG_DH_H_ */ diff --git a/egg/tests/unit-test-dh.c b/egg/tests/unit-test-dh.c index b5d6da1..1111fd4 100644 --- a/egg/tests/unit-test-dh.c +++ b/egg/tests/unit-test-dh.c @@ -1,5 +1,5 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* unit-test-dh.c: Test egg-dh.c +/* test-dh.c: Test egg-dh.c Copyright (C) 2009 Stefan Walter @@ -28,49 +28,21 @@ #include "run-auto-test.h" #include "egg-dh.h" +#include "egg-secure-memory.h" #include -DEFINE_TEST(dh_parse_pkcs3) -{ - gcry_mpi_t p, g; - guchar *data; - gsize n_data; - gboolean ret; - - data = test_data_read ("dh-params.pem", &n_data); - ret = egg_dh_parse_pkcs3 (data, n_data, &p, &g); - g_assert (ret == TRUE); - g_assert (gcry_mpi_get_nbits (p) == 1024); - -#if 0 - guchar *output; - gsize n_written; - gcry_mpi_aprint (GCRYMPI_FMT_HEX, &output, &n_written, p); - g_printerr ("\nprime: %s\n", output); - gcry_mpi_aprint (GCRYMPI_FMT_HEX, &output, &n_written, g); - g_printerr ("\nbase: %s\n", output); -#endif - - gcry_mpi_release (p); - gcry_mpi_release (g); - g_free (data); -} - DEFINE_TEST(dh_perform) { - guchar *data; - gsize n_data; gcry_mpi_t p, g; - gcry_mpi_t x1, X1, k1; - gcry_mpi_t x2, X2, k2; + gcry_mpi_t x1, X1; + gcry_mpi_t x2, X2; + gpointer k1, k2; gboolean ret; /* Load up the parameters */ - data = test_data_read ("dh-params.pem", &n_data); - if (!egg_dh_parse_pkcs3 (data, n_data, &p, &g)) + if (!egg_dh_default_params ("ietf-ike-grp-modp-768", &p, &g)) g_assert_not_reached (); - g_free (data); /* Generate secrets */ ret = egg_dh_gen_pair (p, g, 0, &X1, &x1); @@ -79,22 +51,22 @@ DEFINE_TEST(dh_perform) g_assert (ret); /* Calculate keys */ - ret = egg_dh_gen_secret (X2, x1, p, &k1); - g_assert (ret); - ret = egg_dh_gen_secret (X1, x2, p, &k2); - g_assert (ret); + k1 = egg_dh_gen_secret (X2, x1, p, 96); + g_assert (k1); + k2 = egg_dh_gen_secret (X1, x2, p, 96); + g_assert (k2); /* Keys must be the same */ - g_assert (gcry_mpi_cmp (k1, k2) == 0); + g_assert (memcmp (k1, k2, 96) == 0); gcry_mpi_release (p); gcry_mpi_release (g); gcry_mpi_release (x1); gcry_mpi_release (X1); - gcry_mpi_release (k1); + egg_secure_free (k1); gcry_mpi_release (x2); gcry_mpi_release (X2); - gcry_mpi_release (k2); + egg_secure_free (k2); } DEFINE_TEST(dh_short_pair) -- 2.7.4