Browse Source

Allow the internal DH implementation to be overridden

Crypto library wrappers can now override the internal DH (group 5)
implementation. As a starting point, this is done with OpenSSL. The
new mechanism is currently available only for WPS (i.e., IKEv2 still
depends on the internal DH implementation).
Jouni Malinen 15 years ago
parent
commit
f042122a57

+ 11 - 0
hostapd/Makefile

@@ -449,6 +449,7 @@ OBJS_p += ../src/crypto/fips_prf_gnutls.o
 endif
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 ifeq ($(CONFIG_TLS), internal)
 ifeq ($(CONFIG_CRYPTO), libtomcrypt)
@@ -456,6 +457,7 @@ OBJS += ../src/crypto/crypto_libtomcrypt.o
 OBJS_p += ../src/crypto/crypto_libtomcrypt.o
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 ifeq ($(CONFIG_CRYPTO), internal)
 OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
@@ -477,6 +479,7 @@ CONFIG_INTERNAL_MD4=y
 CONFIG_INTERNAL_MD5=y
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 endif
 else
@@ -516,12 +519,20 @@ OBJS += ../src/crypto/sha256-internal.o
 endif
 endif
 
+ifdef CONFIG_INTERNAL_DH_GROUP5
 ifdef NEED_DH_GROUPS
 OBJS += ../src/crypto/dh_groups.o
+OBJS += ../src/crypto/dh_group5.o
 ifdef NEED_DH_GROUPS_ALL
 CFLAGS += -DALL_DH_GROUPS
 endif
 endif
+else
+ifdef NEED_DH_GROUPS_ALL
+OBJS += ../src/crypto/dh_groups.o
+CFLAGS += -DALL_DH_GROUPS
+endif
+endif
 
 ifdef NEED_T_PRF
 SHA1OBJS += ../src/crypto/sha1-tprf.o

+ 97 - 0
src/crypto/crypto_openssl.c

@@ -19,8 +19,10 @@
 #include <openssl/aes.h>
 #include <openssl/bn.h>
 #include <openssl/evp.h>
+#include <openssl/dh.h>
 
 #include "common.h"
+#include "wpabuf.h"
 #include "crypto.h"
 
 #if OPENSSL_VERSION_NUMBER < 0x00907000
@@ -363,3 +365,98 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx)
 	EVP_CIPHER_CTX_cleanup(&ctx->dec);
 	os_free(ctx);
 }
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	DH *dh;
+	struct wpabuf *pubkey = NULL, *privkey = NULL;
+	size_t publen, privlen;
+
+	*priv = NULL;
+	*publ = NULL;
+
+	dh = DH_new();
+	if (dh == NULL)
+		return NULL;
+
+	dh->g = BN_new();
+	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+		goto err;
+
+	dh->p = get_rfc3526_prime_1536(NULL);
+	if (dh->p == NULL)
+		goto err;
+
+	if (DH_generate_key(dh) != 1)
+		goto err;
+
+	publen = BN_num_bytes(dh->p);
+	pubkey = wpabuf_alloc(publen);
+	if (pubkey == NULL)
+		goto err;
+	privlen = BN_num_bytes(dh->priv_key);
+	privkey = wpabuf_alloc(privlen);
+	if (privkey == NULL)
+		goto err;
+
+	BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
+	BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
+
+	*priv = privkey;
+	*publ = pubkey;
+	return dh;
+
+err:
+	wpabuf_free(pubkey);
+	wpabuf_free(privkey);
+	DH_free(dh);
+	return NULL;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	BIGNUM *pub_key;
+	struct wpabuf *res = NULL;
+	size_t rlen;
+	DH *dh = ctx;
+	int keylen;
+
+	if (ctx == NULL)
+		return NULL;
+
+	pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
+			    NULL);
+	if (pub_key == NULL)
+		return NULL;
+
+	rlen = DH_size(dh);
+	res = wpabuf_alloc(rlen);
+	if (res == NULL)
+		goto err;
+
+	keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
+	if (keylen < 0)
+		goto err;
+	wpabuf_put(res, keylen);
+	BN_free(pub_key);
+
+	return res;
+
+err:
+	BN_free(pub_key);
+	wpabuf_free(res);
+	return NULL;
+}
+
+
+void dh5_free(void *ctx)
+{
+	DH *dh;
+	if (ctx == NULL)
+		return;
+	dh = ctx;
+	DH_free(dh);
+}

+ 40 - 0
src/crypto/dh_group5.c

@@ -0,0 +1,40 @@
+/*
+ * Diffie-Hellman group 5 operations
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "dh_groups.h"
+#include "dh_group5.h"
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	*publ = dh_init(dh_groups_get(5), priv);
+	if (*publ == 0)
+		return NULL;
+	return (void *) 1;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	return dh_derive_shared(peer_public, own_private, dh_groups_get(5));
+}
+
+
+void dh5_free(void *ctx)
+{
+}

+ 23 - 0
src/crypto/dh_group5.h

@@ -0,0 +1,23 @@
+/*
+ * Diffie-Hellman group 5 operations
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DH_GROUP5_H
+#define DH_GROUP5_H
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private);
+void dh5_free(void *ctx);
+
+#endif /* DH_GROUP5_H */

+ 2 - 0
src/wps/wps.c

@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "dh_group5.h"
 #include "wps_i.h"
 #include "wps_dev_attr.h"
 #include "ieee802_11_defs.h"
@@ -130,6 +131,7 @@ void wps_deinit(struct wps_data *data)
 	os_free(data->new_psk);
 	wps_device_data_free(&data->peer_dev);
 	os_free(data->new_ap_settings);
+	dh5_free(data->dh_ctx);
 	os_free(data);
 }
 

+ 5 - 0
src/wps/wps.h

@@ -438,6 +438,11 @@ struct wps_context {
 	 */
 	u16 oob_dev_pw_id;
 
+	/**
+	 * dh_ctx - Context data for Diffie-Hellman operation
+	 */
+	void *dh_ctx;
+
 	/**
 	 * dh_privkey - Diffie-Hellman private key
 	 */

+ 6 - 4
src/wps/wps_attr_build.c

@@ -15,7 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
-#include "dh_groups.h"
+#include "dh_group5.h"
 #include "crypto.h"
 #include "sha256.h"
 #include "aes_wrap.h"
@@ -31,15 +31,17 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
 	if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
 		wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
 		wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
+		wps->dh_ctx = wps->wps->dh_ctx;
+		wps->wps->dh_ctx = NULL;
 		pubkey = wpabuf_dup(wps->wps->dh_pubkey);
 	} else {
 		wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
 		wps->dh_privkey = NULL;
-		pubkey = dh_init(dh_groups_get(WPS_DH_GROUP),
-				 &wps->dh_privkey);
+		dh5_free(wps->dh_ctx);
+		wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
 		pubkey = wpabuf_zeropad(pubkey, 192);
 	}
-	if (wps->dh_privkey == NULL || pubkey == NULL) {
+	if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
 			   "Diffie-Hellman handshake");
 		wpabuf_free(pubkey);

+ 4 - 3
src/wps/wps_common.c

@@ -15,7 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
-#include "dh_groups.h"
+#include "dh_group5.h"
 #include "sha256.h"
 #include "aes_wrap.h"
 #include "crypto.h"
@@ -80,8 +80,9 @@ int wps_derive_keys(struct wps_data *wps)
 		return -1;
 	}
 
-	dh_shared = dh_derive_shared(pubkey, wps->dh_privkey,
-				     dh_groups_get(WPS_DH_GROUP));
+	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
+	dh5_free(wps->dh_ctx);
+	wps->dh_ctx = NULL;
 	dh_shared = wpabuf_zeropad(dh_shared, 192);
 	if (dh_shared == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");

+ 2 - 0
src/wps/wps_i.h

@@ -105,6 +105,8 @@ struct wps_data {
 	int ext_reg;
 
 	struct wps_credential *new_ap_settings;
+
+	void *dh_ctx;
 };
 
 

+ 14 - 0
wpa_supplicant/Makefile

@@ -56,6 +56,7 @@ OBJS += ../src/utils/wpabuf.o
 OBJS_p = wpa_passphrase.o
 OBJS_p += ../src/utils/common.o
 OBJS_p += ../src/utils/wpa_debug.o
+OBJS_p += ../src/utils/wpabuf.o
 OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
 
 -include .config
@@ -756,12 +757,14 @@ OBJS += ../src/crypto/fips_prf_gnutls.o
 endif
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 ifeq ($(CONFIG_TLS), schannel)
 OBJS += ../src/crypto/crypto_cryptoapi.o
 OBJS_p += ../src/crypto/crypto_cryptoapi.o
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 ifeq ($(CONFIG_TLS), nss)
 OBJS += ../src/crypto/crypto_nss.o
@@ -770,6 +773,7 @@ CONFIG_INTERNAL_MD4=y
 ifdef NEED_FIPS186_2_PRF
 OBJS += ../src/crypto/fips_prf_nss.o
 endif
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 ifeq ($(CONFIG_TLS), internal)
 ifeq ($(CONFIG_CRYPTO), libtomcrypt)
@@ -777,6 +781,7 @@ OBJS += ../src/crypto/crypto_libtomcrypt.o
 OBJS_p += ../src/crypto/crypto_libtomcrypt.o
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 ifeq ($(CONFIG_CRYPTO), internal)
 OBJS += ../src/crypto/crypto_internal.o ../src/tls/bignum.o
@@ -798,6 +803,7 @@ CONFIG_INTERNAL_MD4=y
 CONFIG_INTERNAL_MD5=y
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
 endif
 ifeq ($(CONFIG_CRYPTO), cryptoapi)
 OBJS += ../src/crypto/crypto_cryptoapi.o
@@ -997,12 +1003,20 @@ ifdef NEED_AES
 OBJS += $(AESOBJS)
 endif
 
+ifdef CONFIG_INTERNAL_DH_GROUP5
 ifdef NEED_DH_GROUPS
 OBJS += ../src/crypto/dh_groups.o
+OBJS += ../src/crypto/dh_group5.o
 ifdef NEED_DH_GROUPS_ALL
 CFLAGS += -DALL_DH_GROUPS
 endif
 endif
+else
+ifdef NEED_DH_GROUPS_ALL
+OBJS += ../src/crypto/dh_groups.o
+CFLAGS += -DALL_DH_GROUPS
+endif
+endif
 
 ifdef NEED_T_PRF
 SHA1OBJS += ../src/crypto/sha1-tprf.o

+ 5 - 4
wpa_supplicant/wps_supplicant.c

@@ -30,7 +30,7 @@
 #include "blacklist.h"
 #include "wpa.h"
 #include "wps_supplicant.h"
-#include "dh_groups.h"
+#include "dh_group5.h"
 
 #define WPS_PIN_SCAN_IGNORE_SEL_REG 3
 
@@ -619,10 +619,11 @@ int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
 		wpabuf_free(wps->dh_pubkey);
 		wpabuf_free(wps->dh_privkey);
 		wps->dh_privkey = NULL;
-		wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP),
-					 &wps->dh_privkey);
+		wps->dh_pubkey = NULL;
+		dh5_free(wps->dh_ctx);
+		wps->dh_ctx = dh5_init(&wps->dh_privkey, &wps->dh_pubkey);
 		wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
-		if (wps->dh_pubkey == NULL) {
+		if (wps->dh_ctx == NULL || wps->dh_pubkey == NULL) {
 			wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
 				   "Diffie-Hellman handshake");
 			return -1;