DPP2: Support new legacy+DPP config object credentials
This allows devices supporting DPP protocol version 2 or newer to provision networks that enable both the legacy (PSK/SAE) and DPP credentials. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
dd6c598007
commit
18015fc8a4
3 changed files with 113 additions and 41 deletions
133
src/common/dpp.c
133
src/common/dpp.c
|
@ -4074,8 +4074,15 @@ struct dpp_configuration * dpp_configuration_alloc(const char *type)
|
||||||
conf->akm = DPP_AKM_PSK;
|
conf->akm = DPP_AKM_PSK;
|
||||||
else if (bin_str_eq(type, len, "sae"))
|
else if (bin_str_eq(type, len, "sae"))
|
||||||
conf->akm = DPP_AKM_SAE;
|
conf->akm = DPP_AKM_SAE;
|
||||||
else if (bin_str_eq(type, len, "psk-sae"))
|
else if (bin_str_eq(type, len, "psk-sae") ||
|
||||||
|
bin_str_eq(type, len, "psk+sae"))
|
||||||
conf->akm = DPP_AKM_PSK_SAE;
|
conf->akm = DPP_AKM_PSK_SAE;
|
||||||
|
else if (bin_str_eq(type, len, "sae-dpp") ||
|
||||||
|
bin_str_eq(type, len, "dpp+sae"))
|
||||||
|
conf->akm = DPP_AKM_SAE_DPP;
|
||||||
|
else if (bin_str_eq(type, len, "psk-sae-dpp") ||
|
||||||
|
bin_str_eq(type, len, "dpp+psk+sae"))
|
||||||
|
conf->akm = DPP_AKM_PSK_SAE_DPP;
|
||||||
else if (bin_str_eq(type, len, "dpp"))
|
else if (bin_str_eq(type, len, "dpp"))
|
||||||
conf->akm = DPP_AKM_DPP;
|
conf->akm = DPP_AKM_DPP;
|
||||||
else
|
else
|
||||||
|
@ -4088,15 +4095,37 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int dpp_akm_psk(enum dpp_akm akm)
|
int dpp_akm_psk(enum dpp_akm akm)
|
||||||
{
|
{
|
||||||
return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE;
|
return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
|
||||||
|
akm == DPP_AKM_PSK_SAE_DPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int dpp_akm_sae(enum dpp_akm akm)
|
int dpp_akm_sae(enum dpp_akm akm)
|
||||||
{
|
{
|
||||||
return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE;
|
return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
|
||||||
|
akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int dpp_akm_legacy(enum dpp_akm akm)
|
||||||
|
{
|
||||||
|
return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
|
||||||
|
akm == DPP_AKM_SAE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int dpp_akm_dpp(enum dpp_akm akm)
|
||||||
|
{
|
||||||
|
return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
|
||||||
|
akm == DPP_AKM_PSK_SAE_DPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int dpp_akm_ver2(enum dpp_akm akm)
|
||||||
|
{
|
||||||
|
return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4328,6 +4357,31 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dpp_build_legacy_cred_params(struct wpabuf *buf,
|
||||||
|
struct dpp_configuration *conf)
|
||||||
|
{
|
||||||
|
if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
|
||||||
|
char pass[63 * 6 + 1];
|
||||||
|
|
||||||
|
json_escape_string(pass, sizeof(pass), conf->passphrase,
|
||||||
|
os_strlen(conf->passphrase));
|
||||||
|
wpabuf_put_str(buf, "\"pass\":\"");
|
||||||
|
wpabuf_put_str(buf, pass);
|
||||||
|
wpabuf_put_str(buf, "\"");
|
||||||
|
os_memset(pass, 0, sizeof(pass));
|
||||||
|
} else if (conf->psk_set) {
|
||||||
|
char psk[2 * sizeof(conf->psk) + 1];
|
||||||
|
|
||||||
|
wpa_snprintf_hex(psk, sizeof(psk),
|
||||||
|
conf->psk, sizeof(conf->psk));
|
||||||
|
wpabuf_put_str(buf, "\"psk_hex\":\"");
|
||||||
|
wpabuf_put_str(buf, psk);
|
||||||
|
wpabuf_put_str(buf, "\"");
|
||||||
|
os_memset(psk, 0, sizeof(psk));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wpabuf *
|
static struct wpabuf *
|
||||||
dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
|
dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
|
||||||
struct dpp_configuration *conf)
|
struct dpp_configuration *conf)
|
||||||
|
@ -4348,6 +4402,8 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
|
||||||
const EVP_MD *sign_md;
|
const EVP_MD *sign_md;
|
||||||
const BIGNUM *r, *s;
|
const BIGNUM *r, *s;
|
||||||
size_t extra_len = 1000;
|
size_t extra_len = 1000;
|
||||||
|
int incl_legacy;
|
||||||
|
enum dpp_akm akm;
|
||||||
|
|
||||||
if (!auth->conf) {
|
if (!auth->conf) {
|
||||||
wpa_printf(MSG_INFO,
|
wpa_printf(MSG_INFO,
|
||||||
|
@ -4366,6 +4422,13 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
akm = conf->akm;
|
||||||
|
if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
|
||||||
|
akm = DPP_AKM_DPP;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TESTING_OPTIONS
|
#ifdef CONFIG_TESTING_OPTIONS
|
||||||
if (auth->groups_override)
|
if (auth->groups_override)
|
||||||
extra_len += os_strlen(auth->groups_override);
|
extra_len += os_strlen(auth->groups_override);
|
||||||
|
@ -4483,14 +4546,22 @@ skip_groups:
|
||||||
if (!signed3)
|
if (!signed3)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
|
||||||
tailroom = 1000;
|
tailroom = 1000;
|
||||||
tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
|
tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
|
||||||
tailroom += signed1_len + signed2_len + signed3_len;
|
tailroom += signed1_len + signed2_len + signed3_len;
|
||||||
|
if (incl_legacy)
|
||||||
|
tailroom += 1000;
|
||||||
buf = dpp_build_conf_start(auth, conf, tailroom);
|
buf = dpp_build_conf_start(auth, conf, tailroom);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
|
wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
|
||||||
|
if (incl_legacy) {
|
||||||
|
dpp_build_legacy_cred_params(buf, conf);
|
||||||
|
wpabuf_put_str(buf, ",");
|
||||||
|
}
|
||||||
|
wpabuf_put_str(buf, "\"signedConnector\":\"");
|
||||||
wpabuf_put_str(buf, signed1);
|
wpabuf_put_str(buf, signed1);
|
||||||
wpabuf_put_u8(buf, '.');
|
wpabuf_put_u8(buf, '.');
|
||||||
wpabuf_put_str(buf, signed2);
|
wpabuf_put_str(buf, signed2);
|
||||||
|
@ -4536,28 +4607,7 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
|
wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
|
||||||
if (conf->passphrase) {
|
dpp_build_legacy_cred_params(buf, conf);
|
||||||
char pass[63 * 6 + 1];
|
|
||||||
|
|
||||||
if (os_strlen(conf->passphrase) > 63) {
|
|
||||||
wpabuf_free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
json_escape_string(pass, sizeof(pass), conf->passphrase,
|
|
||||||
os_strlen(conf->passphrase));
|
|
||||||
wpabuf_put_str(buf, "\"pass\":\"");
|
|
||||||
wpabuf_put_str(buf, pass);
|
|
||||||
wpabuf_put_str(buf, "\"");
|
|
||||||
} else {
|
|
||||||
char psk[2 * sizeof(conf->psk) + 1];
|
|
||||||
|
|
||||||
wpa_snprintf_hex(psk, sizeof(psk),
|
|
||||||
conf->psk, sizeof(conf->psk));
|
|
||||||
wpabuf_put_str(buf, "\"psk_hex\":\"");
|
|
||||||
wpabuf_put_str(buf, psk);
|
|
||||||
wpabuf_put_str(buf, "\"");
|
|
||||||
}
|
|
||||||
wpabuf_put_str(buf, "}}");
|
wpabuf_put_str(buf, "}}");
|
||||||
|
|
||||||
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
|
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
|
||||||
|
@ -4588,7 +4638,7 @@ dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf->akm == DPP_AKM_DPP)
|
if (dpp_akm_dpp(conf->akm))
|
||||||
return dpp_build_conf_obj_dpp(auth, ap, conf);
|
return dpp_build_conf_obj_dpp(auth, ap, conf);
|
||||||
return dpp_build_conf_obj_legacy(auth, ap, conf);
|
return dpp_build_conf_obj_legacy(auth, ap, conf);
|
||||||
}
|
}
|
||||||
|
@ -4950,7 +5000,7 @@ static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
|
||||||
os_strlcpy(auth->passphrase, pass->string,
|
os_strlcpy(auth->passphrase, pass->string,
|
||||||
sizeof(auth->passphrase));
|
sizeof(auth->passphrase));
|
||||||
} else if (psk_hex && psk_hex->type == JSON_STRING) {
|
} else if (psk_hex && psk_hex->type == JSON_STRING) {
|
||||||
if (auth->akm == DPP_AKM_SAE) {
|
if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"DPP: Unexpected psk_hex with akm=sae");
|
"DPP: Unexpected psk_hex with akm=sae");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -4968,8 +5018,7 @@ static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((auth->akm == DPP_AKM_SAE || auth->akm == DPP_AKM_PSK_SAE) &&
|
if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
|
||||||
!auth->passphrase[0]) {
|
|
||||||
wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
|
wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -5482,6 +5531,13 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
|
||||||
|
|
||||||
os_memset(&info, 0, sizeof(info));
|
os_memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
|
if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"DPP: Legacy credential included in Connector credential");
|
||||||
|
if (dpp_parse_cred_legacy(auth, cred) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "DPP: Connector credential");
|
wpa_printf(MSG_DEBUG, "DPP: Connector credential");
|
||||||
|
|
||||||
csign = json_get_member(cred, "csign");
|
csign = json_get_member(cred, "csign");
|
||||||
|
@ -5547,6 +5603,10 @@ const char * dpp_akm_str(enum dpp_akm akm)
|
||||||
return "sae";
|
return "sae";
|
||||||
case DPP_AKM_PSK_SAE:
|
case DPP_AKM_PSK_SAE:
|
||||||
return "psk+sae";
|
return "psk+sae";
|
||||||
|
case DPP_AKM_SAE_DPP:
|
||||||
|
return "dpp+sae";
|
||||||
|
case DPP_AKM_PSK_SAE_DPP:
|
||||||
|
return "dpp+psk+sae";
|
||||||
default:
|
default:
|
||||||
return "??";
|
return "??";
|
||||||
}
|
}
|
||||||
|
@ -5563,6 +5623,10 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
|
||||||
return DPP_AKM_PSK_SAE;
|
return DPP_AKM_PSK_SAE;
|
||||||
if (os_strcmp(akm, "dpp") == 0)
|
if (os_strcmp(akm, "dpp") == 0)
|
||||||
return DPP_AKM_DPP;
|
return DPP_AKM_DPP;
|
||||||
|
if (os_strcmp(akm, "dpp+sae") == 0)
|
||||||
|
return DPP_AKM_SAE_DPP;
|
||||||
|
if (os_strcmp(akm, "dpp+psk+sae") == 0)
|
||||||
|
return DPP_AKM_PSK_SAE_DPP;
|
||||||
return DPP_AKM_UNKNOWN;
|
return DPP_AKM_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5626,11 +5690,10 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
|
||||||
}
|
}
|
||||||
auth->akm = dpp_akm_from_str(token->string);
|
auth->akm = dpp_akm_from_str(token->string);
|
||||||
|
|
||||||
if (auth->akm == DPP_AKM_PSK || auth->akm == DPP_AKM_SAE ||
|
if (dpp_akm_legacy(auth->akm)) {
|
||||||
auth->akm == DPP_AKM_PSK_SAE) {
|
|
||||||
if (dpp_parse_cred_legacy(auth, cred) < 0)
|
if (dpp_parse_cred_legacy(auth, cred) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (auth->akm == DPP_AKM_DPP) {
|
} else if (dpp_akm_dpp(auth->akm)) {
|
||||||
if (dpp_parse_cred_dpp(auth, cred) < 0)
|
if (dpp_parse_cred_dpp(auth, cred) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -146,7 +146,9 @@ enum dpp_akm {
|
||||||
DPP_AKM_DPP,
|
DPP_AKM_DPP,
|
||||||
DPP_AKM_PSK,
|
DPP_AKM_PSK,
|
||||||
DPP_AKM_SAE,
|
DPP_AKM_SAE,
|
||||||
DPP_AKM_PSK_SAE
|
DPP_AKM_PSK_SAE,
|
||||||
|
DPP_AKM_SAE_DPP,
|
||||||
|
DPP_AKM_PSK_SAE_DPP,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dpp_configuration {
|
struct dpp_configuration {
|
||||||
|
@ -394,6 +396,11 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||||
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
|
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
|
||||||
struct dpp_bootstrap_info *peer_bi);
|
struct dpp_bootstrap_info *peer_bi);
|
||||||
struct dpp_configuration * dpp_configuration_alloc(const char *type);
|
struct dpp_configuration * dpp_configuration_alloc(const char *type);
|
||||||
|
int dpp_akm_psk(enum dpp_akm akm);
|
||||||
|
int dpp_akm_sae(enum dpp_akm akm);
|
||||||
|
int dpp_akm_legacy(enum dpp_akm akm);
|
||||||
|
int dpp_akm_dpp(enum dpp_akm akm);
|
||||||
|
int dpp_akm_ver2(enum dpp_akm akm);
|
||||||
int dpp_configuration_valid(const struct dpp_configuration *conf);
|
int dpp_configuration_valid(const struct dpp_configuration *conf);
|
||||||
void dpp_configuration_free(struct dpp_configuration *conf);
|
void dpp_configuration_free(struct dpp_configuration *conf);
|
||||||
int dpp_configuration_parse(struct dpp_authentication *auth, const char *cmd);
|
int dpp_configuration_parse(struct dpp_authentication *auth, const char *cmd);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* wpa_supplicant - DPP
|
* wpa_supplicant - DPP
|
||||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||||
* Copyright (c) 2018, The Linux Foundation
|
* Copyright (c) 2018-2019, The Linux Foundation
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -1112,12 +1112,14 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
|
||||||
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
|
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!auth->connector) {
|
if (!auth->connector || dpp_akm_psk(auth->akm) ||
|
||||||
ssid->key_mgmt = 0;
|
dpp_akm_sae(auth->akm)) {
|
||||||
if (auth->akm == DPP_AKM_PSK || auth->akm == DPP_AKM_PSK_SAE)
|
if (!auth->connector)
|
||||||
|
ssid->key_mgmt = 0;
|
||||||
|
if (dpp_akm_psk(auth->akm))
|
||||||
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
|
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
|
||||||
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
|
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
|
||||||
if (auth->akm == DPP_AKM_SAE || auth->akm == DPP_AKM_PSK_SAE)
|
if (dpp_akm_sae(auth->akm))
|
||||||
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
|
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
|
||||||
WPA_KEY_MGMT_FT_SAE;
|
WPA_KEY_MGMT_FT_SAE;
|
||||||
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
|
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
|
||||||
|
|
Loading…
Add table
Reference in a new issue