[PATCH] DPP: Allow loading bootstrap keys using an OpenSSL engine
Andrew Beltrano
anbeltra at microsoft.com
Tue Apr 6 17:03:48 BST 2021
Add ability to load a DPP bootstrap key-pair using an arbitrary OpenSSL
engine instead of requiring the private key to be specified explicitly.
The engine name, so path, and key identifier must be specified to
enable loading a key using an OpenSSL engine. The key identifier is
an engine-specific field used to identify the key to load.
Explicit private keys, if specified, take precedence over OpenSSL
engine-based keys.
Signed-off-by: Andrew Beltrano <anbeltra at microsoft.com>
---
Note that this patch depends on the patch-set titled 'Expose OpenSSL dynamic
engine loading globally'.
hostapd/hostapd_cli.c | 2 +-
src/common/dpp.c | 19 ++++++++
src/common/dpp.h | 9 ++++
src/common/dpp_crypto.c | 101 +++++++++++++++++++++++++++++++++++++++
src/common/dpp_i.h | 7 +++
wpa_supplicant/wpa_cli.c | 2 +-
6 files changed, 138 insertions(+), 2 deletions(-)
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index eaa628ad0..62d948680 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1690,7 +1690,7 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
"report a scanned DPP URI from a QR Code" },
{ "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL,
- "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
+ "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] [key_id=..] [engine=..] [engine_path=..] = generate DPP bootstrap information" },
{ "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL,
"*|<id> = remove DPP bootstrap information" },
{ "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL,
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 3c8c7682d..a7468ca91 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -180,6 +180,13 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
os_free(info->info);
os_free(info->chan);
os_free(info->pk);
+#ifndef OPENSSL_NO_ENGINE
+ os_free(info->key_id);
+ os_free(info->engine_id);
+ os_free(info->engine_path);
+ if (info->engine)
+ ENGINE_finish(info->engine);
+#endif /* OPENSSL_NO_ENGINE */
EVP_PKEY_free(info->pubkey);
str_clear_free(info->configurator_params);
os_free(info);
@@ -3893,6 +3900,11 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
info = get_param(cmd, " info=");
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
+#ifndef OPENSSL_NO_ENGINE
+ bi->key_id = get_param(cmd, " key_id=");
+ bi->engine_id = get_param(cmd, " engine=");
+ bi->engine_path = get_param(cmd, " engine_path=");
+#endif /* OPENSSL_NO_ENGINE */
if (key) {
privkey_len = os_strlen(key) / 2;
@@ -3901,6 +3913,13 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
hexstr2bin(key, privkey, privkey_len) < 0)
goto fail;
}
+#ifndef OPENSSL_NO_ENGINE
+ else if (bi->key_id) {
+ bi->engine = dpp_load_engine(bi->engine_id, bi->engine_path);
+ if (!bi->engine)
+ goto fail;
+ }
+#endif /* OPENSSL_NO_ENGINE */
if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 65ee905a7..d5c062f82 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -12,6 +12,9 @@
#ifdef CONFIG_DPP
#include <openssl/x509.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
#include "utils/list.h"
#include "common/wpa_common.h"
@@ -166,6 +169,12 @@ struct dpp_bootstrap_info {
int nfc_negotiated; /* whether this has been used in NFC negotiated
* connection handover */
char *configurator_params;
+#ifndef OPENSSL_NO_ENGINE
+ char *key_id;
+ char *engine_id;
+ char *engine_path;
+ ENGINE *engine;
+#endif /* OPENSSL_NO_ENGINE */
};
#define PKEX_COUNTER_T_LIMIT 5
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index c75fc7871..f04ee9e0e 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -19,6 +19,9 @@
#include "utils/json.h"
#include "common/ieee802_11_defs.h"
#include "crypto/crypto.h"
+#ifndef OPENSSL_NO_ENGINE
+#include "crypto/openssl_engine.h"
+#endif
#include "crypto/random.h"
#include "crypto/sha384.h"
#include "crypto/sha512.h"
@@ -363,6 +366,100 @@ int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
#endif /* CONFIG_DPP2 */
+#ifndef OPENSSL_NO_ENGINE
+static EVP_PKEY * dpp_load_keypair(const struct dpp_curve_params **curve,
+ ENGINE *engine, const char *key_id)
+{
+ EVP_PKEY *pkey;
+ EC_KEY *eckey;
+ const EC_GROUP *group;
+ int nid;
+
+ pkey = ENGINE_load_private_key(engine, key_id, NULL, NULL);
+ if (!pkey) {
+ wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id '%s' [%s]",
+ key_id, ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
+ if (!eckey) {
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+
+ group = EC_KEY_get0_group(eckey);
+ if (!group) {
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+
+ nid = EC_GROUP_get_curve_name(group);
+ *curve = dpp_get_curve_nid(nid);
+ if (!*curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported curve (nid=%d) in pre-assigned key",
+ nid);
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+
+ EC_KEY_free(eckey);
+ return pkey;
+}
+
+
+static int dpp_openssl_engine_load_dynamic(const char *engine_id,
+ const char *engine_path)
+{
+ const char *pre_cmd[] = {
+ "SO_PATH", engine_path,
+ "ID", engine_id,
+ "LIST_ADD", "1",
+ "LOAD", NULL,
+ NULL, NULL
+ };
+ const char *post_cmd[] = {
+ NULL, NULL
+ };
+
+ if (!engine_id || !engine_path)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading %s Engine from %s",
+ engine_id, engine_path);
+
+ return openssl_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
+}
+
+
+ENGINE * dpp_load_engine(const char *engine_id, const char *engine_path)
+{
+ if (dpp_openssl_engine_load_dynamic(engine_id, engine_path) < 0)
+ return NULL;
+
+ ENGINE *engine = ENGINE_by_id(engine_id);
+ if (!engine) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
+ engine_id, ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+
+ if (ENGINE_init(engine) != 1) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
+ "(engine: %s) [%s]", engine_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ ENGINE_free(engine);
+ return NULL;
+ }
+
+ return engine;
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
{
int num_bytes, offset;
@@ -730,6 +827,10 @@ int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
if (privkey)
bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
+#ifndef OPENSSL_NO_ENGINE
+ else if (bi->engine)
+ bi->pubkey = dpp_load_keypair(&bi->curve, bi->engine, bi->key_id);
+#endif /* OPENSSL_NO_ENGINE */
else
bi->pubkey = dpp_gen_keypair(bi->curve);
if (!bi->pubkey)
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index af12467a5..3e42b1a11 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -12,6 +12,10 @@
#ifdef CONFIG_DPP
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
+
struct dpp_global {
void *msg_ctx;
struct dl_list bootstrap; /* struct dpp_bootstrap_info */
@@ -139,6 +143,9 @@ char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg,
const struct dpp_curve_params *curve);
+#ifndef OPENSSL_NO_ENGINE
+ENGINE * dpp_load_engine(const char *engine_id, const char *engine_path);
+#endif /* OPENSSL_NO_ENGINE */
struct dpp_reconfig_id {
const EC_GROUP *group;
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index fea7b85e0..11bb63dc3 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3855,7 +3855,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
"report a scanned DPP URI from a QR Code" },
{ "dpp_bootstrap_gen", wpa_cli_cmd_dpp_bootstrap_gen, NULL,
cli_cmd_flag_sensitive,
- "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
+ "type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] [key_id=..] [engine=..] [engine_path=..] = generate DPP bootstrap information" },
{ "dpp_bootstrap_remove", wpa_cli_cmd_dpp_bootstrap_remove, NULL,
cli_cmd_flag_none,
"*|<id> = remove DPP bootstrap information" },
--
2.23.3
More information about the Hostap
mailing list