mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-01-22 04:44:02 -05:00
633 lines
14 KiB
C
633 lines
14 KiB
C
|
/*
|
||
|
* DPP functionality shared between hostapd and wpa_supplicant
|
||
|
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||
|
*
|
||
|
* This software may be distributed under the terms of the BSD license.
|
||
|
* See README for more details.
|
||
|
*/
|
||
|
|
||
|
#include "utils/includes.h"
|
||
|
#include <openssl/err.h>
|
||
|
|
||
|
#include "utils/common.h"
|
||
|
#include "utils/base64.h"
|
||
|
#include "common/ieee802_11_common.h"
|
||
|
#include "crypto/crypto.h"
|
||
|
#include "dpp.h"
|
||
|
|
||
|
|
||
|
static const struct dpp_curve_params dpp_curves[] = {
|
||
|
/* The mandatory to support and the default NIST P-256 curve needs to
|
||
|
* be the first entry on this list. */
|
||
|
{ "prime256v1", 32, 32, 16, 32, "P-256" },
|
||
|
{ "secp384r1", 48, 48, 24, 48, "P-384" },
|
||
|
{ "secp521r1", 64, 64, 32, 66, "P-521" },
|
||
|
{ "brainpoolP256r1", 32, 32, 16, 32, "BP-256R1" },
|
||
|
{ "brainpoolP384r1", 48, 48, 24, 48, "BP-384R1" },
|
||
|
{ "brainpoolP512r1", 64, 64, 32, 64, "BP-512R1" },
|
||
|
{ NULL, 0, 0, 0, 0, NULL }
|
||
|
};
|
||
|
|
||
|
|
||
|
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
|
||
|
{
|
||
|
if (!info)
|
||
|
return;
|
||
|
os_free(info->uri);
|
||
|
os_free(info->info);
|
||
|
EVP_PKEY_free(info->pubkey);
|
||
|
os_free(info);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int dpp_uri_valid_info(const char *info)
|
||
|
{
|
||
|
while (*info) {
|
||
|
unsigned char val = *info++;
|
||
|
|
||
|
if (val < 0x20 || val > 0x7e || val == 0x3b)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
|
||
|
{
|
||
|
bi->uri = os_strdup(uri);
|
||
|
return bi->uri ? 0 : -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
|
||
|
const char *chan_list)
|
||
|
{
|
||
|
const char *pos = chan_list;
|
||
|
int opclass, channel, freq;
|
||
|
|
||
|
while (pos && *pos && *pos != ';') {
|
||
|
opclass = atoi(pos);
|
||
|
if (opclass <= 0)
|
||
|
goto fail;
|
||
|
pos = os_strchr(pos, '/');
|
||
|
if (!pos)
|
||
|
goto fail;
|
||
|
pos++;
|
||
|
channel = atoi(pos);
|
||
|
if (channel <= 0)
|
||
|
goto fail;
|
||
|
while (*pos >= '0' && *pos <= '9')
|
||
|
pos++;
|
||
|
freq = ieee80211_chan_to_freq(NULL, opclass, channel);
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
|
||
|
opclass, channel, freq);
|
||
|
if (freq < 0) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
|
||
|
opclass, channel);
|
||
|
} else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Too many channels in URI channel-list - ignore list");
|
||
|
bi->num_freq = 0;
|
||
|
break;
|
||
|
} else {
|
||
|
bi->freq[bi->num_freq++] = freq;
|
||
|
}
|
||
|
|
||
|
if (*pos == ';' || *pos == '\0')
|
||
|
break;
|
||
|
if (*pos != ',')
|
||
|
goto fail;
|
||
|
pos++;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
fail:
|
||
|
wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
|
||
|
{
|
||
|
if (!mac)
|
||
|
return 0;
|
||
|
|
||
|
if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
|
||
|
wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
|
||
|
{
|
||
|
const char *end;
|
||
|
|
||
|
if (!info)
|
||
|
return 0;
|
||
|
|
||
|
end = os_strchr(info, ';');
|
||
|
if (!end)
|
||
|
end = info + os_strlen(info);
|
||
|
bi->info = os_malloc(end - info + 1);
|
||
|
if (!bi->info)
|
||
|
return -1;
|
||
|
os_memcpy(bi->info, info, end - info);
|
||
|
bi->info[end - info] = '\0';
|
||
|
wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
|
||
|
if (!dpp_uri_valid_info(bi->info)) {
|
||
|
wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static const struct dpp_curve_params *
|
||
|
dpp_get_curve_oid(const ASN1_OBJECT *poid)
|
||
|
{
|
||
|
ASN1_OBJECT *oid;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; dpp_curves[i].name; i++) {
|
||
|
oid = OBJ_txt2obj(dpp_curves[i].name, 0);
|
||
|
if (oid && OBJ_cmp(poid, oid) == 0)
|
||
|
return &dpp_curves[i];
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
|
||
|
{
|
||
|
int i, tmp;
|
||
|
|
||
|
if (!nid)
|
||
|
return NULL;
|
||
|
for (i = 0; dpp_curves[i].name; i++) {
|
||
|
tmp = OBJ_txt2nid(dpp_curves[i].name);
|
||
|
if (tmp == nid)
|
||
|
return &dpp_curves[i];
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
|
||
|
{
|
||
|
const char *end;
|
||
|
u8 *data;
|
||
|
size_t data_len;
|
||
|
EVP_PKEY *pkey;
|
||
|
const unsigned char *p;
|
||
|
int res;
|
||
|
X509_PUBKEY *pub = NULL;
|
||
|
ASN1_OBJECT *ppkalg;
|
||
|
const unsigned char *pk;
|
||
|
int ppklen;
|
||
|
X509_ALGOR *pa;
|
||
|
ASN1_OBJECT *pa_oid;
|
||
|
const void *pval;
|
||
|
int ptype;
|
||
|
const ASN1_OBJECT *poid;
|
||
|
char buf[100];
|
||
|
|
||
|
end = os_strchr(info, ';');
|
||
|
if (!end)
|
||
|
return -1;
|
||
|
|
||
|
data = base64_decode((const unsigned char *) info, end - info,
|
||
|
&data_len);
|
||
|
if (!data) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Invalid base64 encoding on URI public-key");
|
||
|
return -1;
|
||
|
}
|
||
|
wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
|
||
|
data, data_len);
|
||
|
|
||
|
if (sha256_vector(1, (const u8 **) &data, &data_len,
|
||
|
bi->pubkey_hash) < 0) {
|
||
|
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* DER encoded ASN.1 SubjectPublicKeyInfo
|
||
|
*
|
||
|
* SubjectPublicKeyInfo ::= SEQUENCE {
|
||
|
* algorithm AlgorithmIdentifier,
|
||
|
* subjectPublicKey BIT STRING }
|
||
|
*
|
||
|
* AlgorithmIdentifier ::= SEQUENCE {
|
||
|
* algorithm OBJECT IDENTIFIER,
|
||
|
* parameters ANY DEFINED BY algorithm OPTIONAL }
|
||
|
*
|
||
|
* subjectPublicKey = compressed format public key per ANSI X9.63
|
||
|
* algorithm = ecPublicKey (1.2.840.10045.2.1)
|
||
|
* parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
|
||
|
* prime256v1 (1.2.840.10045.3.1.7)
|
||
|
*/
|
||
|
|
||
|
p = data;
|
||
|
pkey = d2i_PUBKEY(NULL, &p, data_len);
|
||
|
os_free(data);
|
||
|
|
||
|
if (!pkey) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Could not parse URI public-key SubjectPublicKeyInfo");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: SubjectPublicKeyInfo does not describe an EC key");
|
||
|
EVP_PKEY_free(pkey);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
res = X509_PUBKEY_set(&pub, pkey);
|
||
|
if (res != 1) {
|
||
|
wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
|
||
|
if (res != 1) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Could not extract SubjectPublicKeyInfo parameters");
|
||
|
goto fail;
|
||
|
}
|
||
|
res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
|
||
|
if (res < 0 || (size_t) res >= sizeof(buf)) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Could not extract SubjectPublicKeyInfo algorithm");
|
||
|
goto fail;
|
||
|
}
|
||
|
wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
|
||
|
if (os_strcmp(buf, "id-ecPublicKey") != 0) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Unsupported SubjectPublicKeyInfo algorithm");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
|
||
|
if (ptype != V_ASN1_OBJECT) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: SubjectPublicKeyInfo parameters did not contain an OID");
|
||
|
goto fail;
|
||
|
}
|
||
|
poid = pval;
|
||
|
res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
|
||
|
if (res < 0 || (size_t) res >= sizeof(buf)) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Could not extract SubjectPublicKeyInfo parameters OID");
|
||
|
goto fail;
|
||
|
}
|
||
|
wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
|
||
|
bi->curve = dpp_get_curve_oid(poid);
|
||
|
if (!bi->curve) {
|
||
|
wpa_printf(MSG_DEBUG,
|
||
|
"DPP: Unsupported SubjectPublicKeyInfo curve: %s",
|
||
|
buf);
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
|
||
|
|
||
|
X509_PUBKEY_free(pub);
|
||
|
bi->pubkey = pkey;
|
||
|
return 0;
|
||
|
fail:
|
||
|
X509_PUBKEY_free(pub);
|
||
|
EVP_PKEY_free(pkey);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
|
||
|
{
|
||
|
const char *pos = uri;
|
||
|
const char *end;
|
||
|
const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
|
||
|
struct dpp_bootstrap_info *bi;
|
||
|
|
||
|
wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
|
||
|
|
||
|
if (os_strncmp(pos, "DPP:", 4) != 0) {
|
||
|
wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
|
||
|
return NULL;
|
||
|
}
|
||
|
pos += 4;
|
||
|
|
||
|
for (;;) {
|
||
|
end = os_strchr(pos, ';');
|
||
|
if (!end)
|
||
|
break;
|
||
|
|
||
|
if (end == pos) {
|
||
|
/* Handle terminating ";;" and ignore unexpected ";"
|
||
|
* for parsing robustness. */
|
||
|
pos++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
|
||
|
chan_list = pos + 2;
|
||
|
else if (pos[0] == 'M' && pos[1] == ':' && !mac)
|
||
|
mac = pos + 2;
|
||
|
else if (pos[0] == 'I' && pos[1] == ':' && !info)
|
||
|
info = pos + 2;
|
||
|
else if (pos[0] == 'K' && pos[1] == ':' && !pk)
|
||
|
pk = pos + 2;
|
||
|
else
|
||
|
wpa_hexdump_ascii(MSG_DEBUG,
|
||
|
"DPP: Ignore unrecognized URI parameter",
|
||
|
pos, end - pos);
|
||
|
pos = end + 1;
|
||
|
}
|
||
|
|
||
|
if (!pk) {
|
||
|
wpa_printf(MSG_INFO, "DPP: URI missing public-key");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
bi = os_zalloc(sizeof(*bi));
|
||
|
if (!bi)
|
||
|
return NULL;
|
||
|
|
||
|
if (dpp_clone_uri(bi, uri) < 0 ||
|
||
|
dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
|
||
|
dpp_parse_uri_mac(bi, mac) < 0 ||
|
||
|
dpp_parse_uri_info(bi, info) < 0 ||
|
||
|
dpp_parse_uri_pk(bi, pk) < 0) {
|
||
|
dpp_bootstrap_info_free(bi);
|
||
|
bi = NULL;
|
||
|
}
|
||
|
|
||
|
return bi;
|
||
|
}
|
||
|
|
||
|
|
||
|
struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
|
||
|
{
|
||
|
struct dpp_bootstrap_info *bi;
|
||
|
|
||
|
bi = dpp_parse_uri(uri);
|
||
|
if (bi)
|
||
|
bi->type = DPP_BOOTSTRAP_QR_CODE;
|
||
|
return bi;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
|
||
|
{
|
||
|
EC_KEY *eckey;
|
||
|
BIO *out;
|
||
|
size_t rlen;
|
||
|
char *txt;
|
||
|
int res;
|
||
|
unsigned char *der = NULL;
|
||
|
int der_len;
|
||
|
|
||
|
out = BIO_new(BIO_s_mem());
|
||
|
if (!out)
|
||
|
return;
|
||
|
|
||
|
EVP_PKEY_print_private(out, key, 0, NULL);
|
||
|
rlen = BIO_ctrl_pending(out);
|
||
|
txt = os_malloc(rlen + 1);
|
||
|
if (txt) {
|
||
|
res = BIO_read(out, txt, rlen);
|
||
|
if (res > 0) {
|
||
|
txt[res] = '\0';
|
||
|
wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
|
||
|
}
|
||
|
os_free(txt);
|
||
|
}
|
||
|
BIO_free(out);
|
||
|
|
||
|
eckey = EVP_PKEY_get1_EC_KEY(key);
|
||
|
if (!eckey)
|
||
|
return;
|
||
|
|
||
|
der_len = i2d_ECPrivateKey(eckey, &der);
|
||
|
if (der_len > 0)
|
||
|
wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
|
||
|
OPENSSL_free(der);
|
||
|
if (der_len <= 0) {
|
||
|
der = NULL;
|
||
|
der_len = i2d_EC_PUBKEY(eckey, &der);
|
||
|
if (der_len > 0)
|
||
|
wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
|
||
|
OPENSSL_free(der);
|
||
|
}
|
||
|
|
||
|
EC_KEY_free(eckey);
|
||
|
}
|
||
|
|
||
|
|
||
|
static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
|
||
|
{
|
||
|
#ifdef OPENSSL_IS_BORINGSSL
|
||
|
EVP_PKEY_CTX *kctx = NULL;
|
||
|
const EC_GROUP *group;
|
||
|
EC_KEY *ec_params;
|
||
|
#else
|
||
|
EVP_PKEY_CTX *pctx, *kctx = NULL;
|
||
|
#endif
|
||
|
EVP_PKEY *params = NULL, *key = NULL;
|
||
|
int nid;
|
||
|
|
||
|
wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
|
||
|
|
||
|
nid = OBJ_txt2nid(curve->name);
|
||
|
if (nid == NID_undef) {
|
||
|
wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
|
||
|
return NULL;
|
||
|
}
|
||
|
#ifdef OPENSSL_IS_BORINGSSL
|
||
|
group = EC_GROUP_new_by_curve_name(nid);
|
||
|
ec_params = EC_KEY_new();
|
||
|
if (!ec_params || EC_KEY_set_group(ec_params, group) != 1) {
|
||
|
wpa_printf(MSG_ERROR,
|
||
|
"DPP: Failed to generate EC_KEY parameters");
|
||
|
goto fail;
|
||
|
}
|
||
|
EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
|
||
|
params = EVP_PKEY_new();
|
||
|
if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
|
||
|
wpa_printf(MSG_ERROR,
|
||
|
"DPP: Failed to generate EVP_PKEY parameters");
|
||
|
goto fail;
|
||
|
}
|
||
|
#else
|
||
|
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
|
||
|
if (!pctx ||
|
||
|
EVP_PKEY_paramgen_init(pctx) != 1 ||
|
||
|
EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1 ||
|
||
|
EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE) != 1 ||
|
||
|
EVP_PKEY_paramgen(pctx, ¶ms) != 1) {
|
||
|
wpa_printf(MSG_ERROR,
|
||
|
"DPP: Failed to generate EVP_PKEY parameters");
|
||
|
EVP_PKEY_CTX_free(pctx);
|
||
|
goto fail;
|
||
|
}
|
||
|
EVP_PKEY_CTX_free(pctx);
|
||
|
#endif
|
||
|
|
||
|
kctx = EVP_PKEY_CTX_new(params, NULL);
|
||
|
if (!kctx ||
|
||
|
EVP_PKEY_keygen_init(kctx) != 1 ||
|
||
|
EVP_PKEY_keygen(kctx, &key) != 1) {
|
||
|
wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
if (wpa_debug_show_keys)
|
||
|
dpp_debug_print_key("Own generated key", key);
|
||
|
|
||
|
EVP_PKEY_free(params);
|
||
|
EVP_PKEY_CTX_free(kctx);
|
||
|
return key;
|
||
|
fail:
|
||
|
EVP_PKEY_CTX_free(kctx);
|
||
|
EVP_PKEY_free(params);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
static const struct dpp_curve_params *
|
||
|
dpp_get_curve_name(const char *name)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; dpp_curves[i].name; i++) {
|
||
|
if (os_strcmp(name, dpp_curves[i].name) == 0 ||
|
||
|
(dpp_curves[i].jwk_crv &&
|
||
|
os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
|
||
|
return &dpp_curves[i];
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
|
||
|
const u8 *privkey, size_t privkey_len)
|
||
|
{
|
||
|
EVP_PKEY *pkey;
|
||
|
EC_KEY *eckey;
|
||
|
const EC_GROUP *group;
|
||
|
int nid;
|
||
|
|
||
|
pkey = EVP_PKEY_new();
|
||
|
if (!pkey)
|
||
|
return NULL;
|
||
|
eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
|
||
|
if (!eckey) {
|
||
|
wpa_printf(MSG_INFO,
|
||
|
"DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
|
||
|
ERR_error_string(ERR_get_error(), NULL));
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
|
||
|
EC_KEY_free(eckey);
|
||
|
EVP_PKEY_free(pkey);
|
||
|
return NULL;
|
||
|
}
|
||
|
return pkey;
|
||
|
}
|
||
|
|
||
|
|
||
|
char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
|
||
|
const u8 *privkey, size_t privkey_len)
|
||
|
{
|
||
|
unsigned char *base64 = NULL;
|
||
|
char *pos, *end;
|
||
|
size_t len;
|
||
|
unsigned char *der = NULL;
|
||
|
int der_len;
|
||
|
EC_KEY *eckey;
|
||
|
|
||
|
if (!curve) {
|
||
|
bi->curve = &dpp_curves[0];
|
||
|
} else {
|
||
|
bi->curve = dpp_get_curve_name(curve);
|
||
|
if (!bi->curve) {
|
||
|
wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
|
||
|
curve);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
if (privkey)
|
||
|
bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
|
||
|
else
|
||
|
bi->pubkey = dpp_gen_keypair(bi->curve);
|
||
|
if (!bi->pubkey)
|
||
|
goto fail;
|
||
|
bi->own = 1;
|
||
|
|
||
|
/* Need to get the compressed form of the public key through EC_KEY, so
|
||
|
* cannot use the simpler i2d_PUBKEY() here. */
|
||
|
eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey);
|
||
|
if (!eckey)
|
||
|
goto fail;
|
||
|
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
|
||
|
der_len = i2d_EC_PUBKEY(eckey, &der);
|
||
|
EC_KEY_free(eckey);
|
||
|
if (der_len <= 0) {
|
||
|
wpa_printf(MSG_ERROR,
|
||
|
"DDP: Failed to build DER encoded public key");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
len = der_len;
|
||
|
if (sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash) < 0) {
|
||
|
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
base64 = base64_encode(der, der_len, &len);
|
||
|
OPENSSL_free(der);
|
||
|
if (!base64)
|
||
|
goto fail;
|
||
|
pos = (char *) base64;
|
||
|
end = pos + len;
|
||
|
for (;;) {
|
||
|
pos = os_strchr(pos, '\n');
|
||
|
if (!pos)
|
||
|
break;
|
||
|
os_memmove(pos, pos + 1, end - pos);
|
||
|
}
|
||
|
return (char *) base64;
|
||
|
fail:
|
||
|
os_free(base64);
|
||
|
OPENSSL_free(der);
|
||
|
return NULL;
|
||
|
}
|