Allow the internal DH implementation to be overridden
authorJouni Malinen <j@w1.fi>
Sun, 11 Oct 2009 16:17:22 +0000 (19:17 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 11 Oct 2009 16:17:22 +0000 (19:17 +0300)
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).

hostapd/Makefile
src/crypto/crypto_openssl.c
src/crypto/dh_group5.c [new file with mode: 0644]
src/crypto/dh_group5.h [new file with mode: 0644]
src/wps/wps.c
src/wps/wps.h
src/wps/wps_attr_build.c
src/wps/wps_common.c
src/wps/wps_i.h
wpa_supplicant/Makefile
wpa_supplicant/wps_supplicant.c

index ab637c1..2e049de 100644 (file)
@@ -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
index 9e290fb..9d8cb31 100644 (file)
 #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);
+}
diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c
new file mode 100644 (file)
index 0000000..8c475bf
--- /dev/null
@@ -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)
+{
+}
diff --git a/src/crypto/dh_group5.h b/src/crypto/dh_group5.h
new file mode 100644 (file)
index 0000000..595f111
--- /dev/null
@@ -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 */
index 870a493..6b0c6c7 100644 (file)
@@ -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);
 }
 
index 22fa5ea..d02256f 100644 (file)
@@ -439,6 +439,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
         */
        struct wpabuf *dh_privkey;
index f35881a..265eb18 100644 (file)
@@ -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);
index 7cc63e1..8340b27 100644 (file)
@@ -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");
index 3ee2051..067758c 100644 (file)
@@ -105,6 +105,8 @@ struct wps_data {
        int ext_reg;
 
        struct wps_credential *new_ap_settings;
+
+       void *dh_ctx;
 };
 
 
index 128a9d2..2a218a6 100644 (file)
@@ -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
index ffc139d..b5be98d 100644 (file)
@@ -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;