DPP: Send Authentication Confirm failure reports

If Authentication Response processing fails due to R-capab
incompatibility or R-auth mismatch, send Authentication Confirm with
error status.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2017-10-28 12:06:22 +03:00 committed by Jouni Malinen
parent 978bc3f2af
commit 7d917ab048

View file

@ -2566,22 +2566,27 @@ int dpp_notify_new_qr_code(struct dpp_authentication *auth,
} }
static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth) static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
enum dpp_status_error status)
{ {
struct wpabuf *msg; struct wpabuf *msg;
u8 i_auth[4 + DPP_MAX_HASH_LEN]; u8 i_auth[4 + DPP_MAX_HASH_LEN];
size_t i_auth_len; size_t i_auth_len;
u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
size_t r_nonce_len;
const u8 *addr[2]; const u8 *addr[2];
size_t len[2], attr_len; size_t len[2], attr_len;
u8 *wrapped_i_auth; u8 *wrapped_i_auth;
u8 *wrapped_r_nonce;
u8 *attr_start, *attr_end; u8 *attr_start, *attr_end;
wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation"); wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
i_auth_len = 4 + auth->curve->hash_len; i_auth_len = 4 + auth->curve->hash_len;
r_nonce_len = 4 + auth->curve->nonce_len;
/* Build DPP Authentication Confirmation frame attributes */ /* Build DPP Authentication Confirmation frame attributes */
attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
4 + i_auth_len + AES_BLOCK_SIZE; 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
attr_len += 4; attr_len += 4;
@ -2600,7 +2605,7 @@ static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth)
/* DPP Status */ /* DPP Status */
wpabuf_put_le16(msg, DPP_ATTR_STATUS); wpabuf_put_le16(msg, DPP_ATTR_STATUS);
wpabuf_put_le16(msg, 1); wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, DPP_STATUS_OK); wpabuf_put_u8(msg, status);
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
skip_status: skip_status:
@ -2647,34 +2652,54 @@ skip_i_bootstrap_key:
len[1] = attr_end - attr_start; len[1] = attr_end - attr_start;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); if (status == DPP_STATUS_OK) {
wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE); /* I-auth wrapped with ke */
wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE); wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF) if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
goto skip_i_auth; goto skip_i_auth;
#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_TESTING_OPTIONS */
/* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG); * 1) */
WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len); WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
if (dpp_gen_i_auth(auth, i_auth + 4) < 0) WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
goto fail; if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
goto fail;
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) { if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch"); wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
i_auth[4 + auth->curve->hash_len / 2] ^= 0x01; i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
} }
skip_i_auth: skip_i_auth:
#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_TESTING_OPTIONS */
if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
i_auth, i_auth_len, i_auth, i_auth_len,
2, addr, len, wrapped_i_auth) < 0) 2, addr, len, wrapped_i_auth) < 0)
goto fail; goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke", wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE); wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
} else {
/* R-nonce wrapped with k2 */
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
r_nonce, r_nonce_len,
2, addr, len, wrapped_r_nonce) < 0)
goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
}
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) { if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
@ -2688,7 +2713,8 @@ skip_wrapped_data:
wpa_hexdump_buf(MSG_DEBUG, wpa_hexdump_buf(MSG_DEBUG,
"DPP: Authentication Confirmation frame attributes", "DPP: Authentication Confirmation frame attributes",
msg); msg);
dpp_auth_success(auth); if (status == DPP_STATUS_OK)
dpp_auth_success(auth);
return msg; return msg;
@ -2988,9 +3014,6 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
goto fail; goto fail;
} }
if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
goto fail;
r_capab = dpp_get_attr(unwrapped, unwrapped_len, r_capab = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_R_CAPABILITIES, DPP_ATTR_R_CAPABILITIES,
&r_capab_len); &r_capab_len);
@ -3007,7 +3030,12 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x", "Unexpected role in R-capabilities 0x%02x",
role); role);
goto fail; if (role != DPP_CAPAB_ENROLLEE &&
role != DPP_CAPAB_CONFIGURATOR)
goto fail;
bin_clear_free(unwrapped, unwrapped_len);
auth->remove_on_tx_status = 1;
return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
} }
wrapped2 = dpp_get_attr(unwrapped, unwrapped_len, wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
@ -3020,6 +3048,10 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped2, wrapped2_len); wrapped2, wrapped2_len);
if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
goto fail;
unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE; unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
unwrapped2 = os_malloc(unwrapped2_len); unwrapped2 = os_malloc(unwrapped2_len);
if (!unwrapped2) if (!unwrapped2)
@ -3055,13 +3087,16 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
r_auth2, r_auth_len); r_auth2, r_auth_len);
if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) { if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag"); dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
goto fail; bin_clear_free(unwrapped, unwrapped_len);
bin_clear_free(unwrapped2, unwrapped2_len);
auth->remove_on_tx_status = 1;
return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
} }
bin_clear_free(unwrapped, unwrapped_len); bin_clear_free(unwrapped, unwrapped_len);
bin_clear_free(unwrapped2, unwrapped2_len); bin_clear_free(unwrapped2, unwrapped2_len);
return dpp_auth_build_conf(auth); return dpp_auth_build_conf(auth, DPP_STATUS_OK);
fail: fail:
bin_clear_free(unwrapped, unwrapped_len); bin_clear_free(unwrapped, unwrapped_len);