wsc: Memzero secrets after use
Also printing keys with l_debug conditional on an environment variable as someone wanting debug logs, or leaving debug on accidentally, does not necessarily want the keys in the logs and in memory.
This commit is contained in:
parent
2042fe7a73
commit
13f09be1a0
133
src/eap-wsc.c
133
src/eap-wsc.c
|
@ -236,6 +236,7 @@ static uint8_t *encrypted_settings_decrypt(struct eap_wsc_state *wsc,
|
||||||
return decrypted;
|
return decrypted;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
explicit_bzero(decrypted, encrypted_len);
|
||||||
l_free(decrypted);
|
l_free(decrypted);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -263,8 +264,10 @@ static bool encrypted_settings_encrypt(struct eap_wsc_state *wsc,
|
||||||
for (i = 0; i < pad; i++)
|
for (i = 0; i < pad; i++)
|
||||||
out[len++] = pad;
|
out[len++] = pad;
|
||||||
|
|
||||||
if (!l_cipher_encrypt(wsc->aes_cbc_128, out + 16, out + 16, len - 16))
|
if (!l_cipher_encrypt(wsc->aes_cbc_128, out + 16, out + 16, len - 16)) {
|
||||||
|
explicit_bzero(out + 16, len - 16);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
*out_len = len;
|
*out_len = len;
|
||||||
return true;
|
return true;
|
||||||
|
@ -276,7 +279,12 @@ static void eap_wsc_free(struct eap_state *eap)
|
||||||
|
|
||||||
eap_set_data(eap, NULL);
|
eap_set_data(eap, NULL);
|
||||||
|
|
||||||
l_free(wsc->device_password);
|
if (wsc->device_password) {
|
||||||
|
explicit_bzero(wsc->device_password,
|
||||||
|
strlen(wsc->device_password));
|
||||||
|
l_free(wsc->device_password);
|
||||||
|
}
|
||||||
|
|
||||||
l_key_free(wsc->private);
|
l_key_free(wsc->private);
|
||||||
|
|
||||||
l_free(wsc->sent_pdu);
|
l_free(wsc->sent_pdu);
|
||||||
|
@ -296,6 +304,11 @@ static void eap_wsc_free(struct eap_state *eap)
|
||||||
l_free(wsc->m1);
|
l_free(wsc->m1);
|
||||||
l_free(wsc->m2);
|
l_free(wsc->m2);
|
||||||
|
|
||||||
|
explicit_bzero(wsc->e_snonce1, 16);
|
||||||
|
explicit_bzero(wsc->e_snonce2, 16);
|
||||||
|
explicit_bzero(wsc->psk1, 16);
|
||||||
|
explicit_bzero(wsc->psk2, 16);
|
||||||
|
|
||||||
l_free(wsc);
|
l_free(wsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,6 +471,7 @@ static void eap_wsc_handle_m8(struct eap_state *eap,
|
||||||
struct iovec creds[3];
|
struct iovec creds[3];
|
||||||
size_t n_creds;
|
size_t n_creds;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
bool nack = true;
|
||||||
|
|
||||||
/* Spec unclear what to do here, see comments in eap_wsc_send_nack */
|
/* Spec unclear what to do here, see comments in eap_wsc_send_nack */
|
||||||
if (wsc_parse_m8(pdu, len, &m8, &encrypted) != 0) {
|
if (wsc_parse_m8(pdu, len, &m8, &encrypted) != 0) {
|
||||||
|
@ -478,29 +492,34 @@ static void eap_wsc_handle_m8(struct eap_state *eap,
|
||||||
|
|
||||||
if (wsc_parse_m8_encrypted_settings(decrypted, decrypted_len,
|
if (wsc_parse_m8_encrypted_settings(decrypted, decrypted_len,
|
||||||
&m8es, creds, &n_creds))
|
&m8es, creds, &n_creds))
|
||||||
goto invalid_settings;
|
goto cleanup;
|
||||||
|
|
||||||
if (!keywrap_authenticator_check(wsc, decrypted, decrypted_len))
|
if (!keywrap_authenticator_check(wsc, decrypted, decrypted_len))
|
||||||
goto invalid_settings;
|
goto cleanup;
|
||||||
|
|
||||||
for (i = 0; i < n_creds; i++) {
|
for (i = 0; i < n_creds; i++) {
|
||||||
struct wsc_credential cred;
|
struct wsc_credential cred;
|
||||||
|
|
||||||
if (wsc_parse_credential(creds[i].iov_base, creds[i].iov_len,
|
if (wsc_parse_credential(creds[i].iov_base, creds[i].iov_len,
|
||||||
&cred) != 0)
|
&cred) == 0)
|
||||||
continue;
|
eap_method_event(eap, EAP_WSC_EVENT_CREDENTIAL_OBTAINED,
|
||||||
|
&cred);
|
||||||
|
|
||||||
eap_method_event(eap, EAP_WSC_EVENT_CREDENTIAL_OBTAINED, &cred);
|
explicit_bzero(&cred, sizeof(cred));
|
||||||
}
|
}
|
||||||
|
|
||||||
l_free(decrypted);
|
|
||||||
|
|
||||||
eap_wsc_send_done(eap);
|
eap_wsc_send_done(eap);
|
||||||
wsc->state = STATE_FINISHED;
|
wsc->state = STATE_FINISHED;
|
||||||
return;
|
nack = false;
|
||||||
|
|
||||||
invalid_settings:
|
cleanup:
|
||||||
|
explicit_bzero(&m8es, sizeof(m8es));
|
||||||
|
explicit_bzero(decrypted, decrypted_len);
|
||||||
l_free(decrypted);
|
l_free(decrypted);
|
||||||
|
|
||||||
|
if (!nack)
|
||||||
|
return;
|
||||||
|
|
||||||
send_nack:
|
send_nack:
|
||||||
eap_wsc_send_nack(eap, WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE);
|
eap_wsc_send_nack(eap, WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -520,12 +539,14 @@ static void eap_wsc_send_m7(struct eap_state *eap,
|
||||||
|
|
||||||
memcpy(m7es.e_snonce2, wsc->e_snonce2, sizeof(wsc->e_snonce2));
|
memcpy(m7es.e_snonce2, wsc->e_snonce2, sizeof(wsc->e_snonce2));
|
||||||
pdu = wsc_build_m7_encrypted_settings(&m7es, &pdu_len);
|
pdu = wsc_build_m7_encrypted_settings(&m7es, &pdu_len);
|
||||||
|
explicit_bzero(m7es.e_snonce2, sizeof(wsc->e_snonce2));
|
||||||
if (!pdu)
|
if (!pdu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
keywrap_authenticator_put(wsc, pdu, pdu_len);
|
keywrap_authenticator_put(wsc, pdu, pdu_len);
|
||||||
r = encrypted_settings_encrypt(wsc, wsc->iv2, pdu, pdu_len,
|
r = encrypted_settings_encrypt(wsc, wsc->iv2, pdu, pdu_len,
|
||||||
encrypted, &encrypted_len);
|
encrypted, &encrypted_len);
|
||||||
|
explicit_bzero(pdu, pdu_len);
|
||||||
l_free(pdu);
|
l_free(pdu);
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
|
@ -553,12 +574,11 @@ static void eap_wsc_handle_m6(struct eap_state *eap,
|
||||||
uint8_t *decrypted;
|
uint8_t *decrypted;
|
||||||
size_t decrypted_len;
|
size_t decrypted_len;
|
||||||
struct wsc_m6_encrypted_settings m6es;
|
struct wsc_m6_encrypted_settings m6es;
|
||||||
|
enum wsc_configuration_error error = WSC_CONFIGURATION_ERROR_NO_ERROR;
|
||||||
|
|
||||||
/* Spec unclear what to do here, see comments in eap_wsc_send_nack */
|
/* Spec unclear what to do here, see comments in eap_wsc_send_nack */
|
||||||
if (wsc_parse_m6(pdu, len, &m6, &encrypted) != 0) {
|
if (wsc_parse_m6(pdu, len, &m6, &encrypted) != 0)
|
||||||
eap_wsc_send_nack(eap, WSC_CONFIGURATION_ERROR_NO_ERROR);
|
goto send_nack;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!authenticator_check(wsc, pdu, len))
|
if (!authenticator_check(wsc, pdu, len))
|
||||||
return;
|
return;
|
||||||
|
@ -566,31 +586,39 @@ static void eap_wsc_handle_m6(struct eap_state *eap,
|
||||||
decrypted = encrypted_settings_decrypt(wsc, encrypted.iov_base,
|
decrypted = encrypted_settings_decrypt(wsc, encrypted.iov_base,
|
||||||
encrypted.iov_len,
|
encrypted.iov_len,
|
||||||
&decrypted_len);
|
&decrypted_len);
|
||||||
if (!decrypted)
|
if (!decrypted) {
|
||||||
|
error = WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE;
|
||||||
goto send_nack;
|
goto send_nack;
|
||||||
|
}
|
||||||
|
|
||||||
if (wsc_parse_m6_encrypted_settings(decrypted, decrypted_len, &m6es))
|
if (wsc_parse_m6_encrypted_settings(decrypted, decrypted_len, &m6es)) {
|
||||||
goto invalid_settings;
|
error = WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (!keywrap_authenticator_check(wsc, decrypted, decrypted_len))
|
if (!keywrap_authenticator_check(wsc, decrypted, decrypted_len)) {
|
||||||
goto invalid_settings;
|
error = WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE;
|
||||||
|
goto cleanup;
|
||||||
l_free(decrypted);
|
}
|
||||||
|
|
||||||
/* We now have R-SNonce2, verify R-Hash2 stored in eap_wsc_handle_m4 */
|
/* We now have R-SNonce2, verify R-Hash2 stored in eap_wsc_handle_m4 */
|
||||||
if (!r_hash_check(wsc, m6es.r_snonce2, wsc->psk2, wsc->r_hash2)) {
|
if (!r_hash_check(wsc, m6es.r_snonce2, wsc->psk2, wsc->r_hash2)) {
|
||||||
eap_wsc_send_nack(eap,
|
error = WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE;
|
||||||
WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE);
|
goto cleanup;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eap_wsc_send_m7(eap, pdu, len);
|
eap_wsc_send_m7(eap, pdu, len);
|
||||||
return;
|
|
||||||
|
|
||||||
invalid_settings:
|
cleanup:
|
||||||
|
explicit_bzero(&m6es, sizeof(m6es));
|
||||||
|
explicit_bzero(decrypted, decrypted_len);
|
||||||
l_free(decrypted);
|
l_free(decrypted);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
return;
|
||||||
|
|
||||||
send_nack:
|
send_nack:
|
||||||
eap_wsc_send_nack(eap, WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE);
|
eap_wsc_send_nack(eap, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eap_wsc_send_m5(struct eap_state *eap,
|
static void eap_wsc_send_m5(struct eap_state *eap,
|
||||||
|
@ -608,12 +636,14 @@ static void eap_wsc_send_m5(struct eap_state *eap,
|
||||||
|
|
||||||
memcpy(m5es.e_snonce1, wsc->e_snonce1, sizeof(wsc->e_snonce1));
|
memcpy(m5es.e_snonce1, wsc->e_snonce1, sizeof(wsc->e_snonce1));
|
||||||
pdu = wsc_build_m5_encrypted_settings(&m5es, &pdu_len);
|
pdu = wsc_build_m5_encrypted_settings(&m5es, &pdu_len);
|
||||||
|
explicit_bzero(m5es.e_snonce1, sizeof(wsc->e_snonce1));
|
||||||
if (!pdu)
|
if (!pdu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
keywrap_authenticator_put(wsc, pdu, pdu_len);
|
keywrap_authenticator_put(wsc, pdu, pdu_len);
|
||||||
r = encrypted_settings_encrypt(wsc, wsc->iv1, pdu, pdu_len,
|
r = encrypted_settings_encrypt(wsc, wsc->iv1, pdu, pdu_len,
|
||||||
encrypted, &encrypted_len);
|
encrypted, &encrypted_len);
|
||||||
|
explicit_bzero(pdu, pdu_len);
|
||||||
l_free(pdu);
|
l_free(pdu);
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
|
@ -641,12 +671,11 @@ static void eap_wsc_handle_m4(struct eap_state *eap,
|
||||||
uint8_t *decrypted;
|
uint8_t *decrypted;
|
||||||
size_t decrypted_len;
|
size_t decrypted_len;
|
||||||
struct wsc_m4_encrypted_settings m4es;
|
struct wsc_m4_encrypted_settings m4es;
|
||||||
|
enum wsc_configuration_error error = WSC_CONFIGURATION_ERROR_NO_ERROR;
|
||||||
|
|
||||||
/* Spec unclear what to do here, see comments in eap_wsc_send_nack */
|
/* Spec unclear what to do here, see comments in eap_wsc_send_nack */
|
||||||
if (wsc_parse_m4(pdu, len, &m4, &encrypted) != 0) {
|
if (wsc_parse_m4(pdu, len, &m4, &encrypted) != 0)
|
||||||
eap_wsc_send_nack(eap, WSC_CONFIGURATION_ERROR_NO_ERROR);
|
goto send_nack;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!authenticator_check(wsc, pdu, len))
|
if (!authenticator_check(wsc, pdu, len))
|
||||||
return;
|
return;
|
||||||
|
@ -654,33 +683,41 @@ static void eap_wsc_handle_m4(struct eap_state *eap,
|
||||||
decrypted = encrypted_settings_decrypt(wsc, encrypted.iov_base,
|
decrypted = encrypted_settings_decrypt(wsc, encrypted.iov_base,
|
||||||
encrypted.iov_len,
|
encrypted.iov_len,
|
||||||
&decrypted_len);
|
&decrypted_len);
|
||||||
if (!decrypted)
|
if (!decrypted) {
|
||||||
|
error = WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE;
|
||||||
goto send_nack;
|
goto send_nack;
|
||||||
|
}
|
||||||
|
|
||||||
if (wsc_parse_m4_encrypted_settings(decrypted, decrypted_len, &m4es))
|
if (wsc_parse_m4_encrypted_settings(decrypted, decrypted_len, &m4es)) {
|
||||||
goto invalid_settings;
|
error = WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (!keywrap_authenticator_check(wsc, decrypted, decrypted_len))
|
if (!keywrap_authenticator_check(wsc, decrypted, decrypted_len)) {
|
||||||
goto invalid_settings;
|
error = WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE;
|
||||||
|
goto cleanup;
|
||||||
l_free(decrypted);
|
}
|
||||||
|
|
||||||
/* Since we have obtained R-SNonce1, we can now verify R-Hash1. */
|
/* Since we have obtained R-SNonce1, we can now verify R-Hash1. */
|
||||||
if (!r_hash_check(wsc, m4es.r_snonce1, wsc->psk1, m4.r_hash1)) {
|
if (!r_hash_check(wsc, m4es.r_snonce1, wsc->psk1, m4.r_hash1)) {
|
||||||
eap_wsc_send_nack(eap,
|
error = WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE;
|
||||||
WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE);
|
goto cleanup;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now store R_Hash2 so we can verify it when we receive M6 */
|
/* Now store R_Hash2 so we can verify it when we receive M6 */
|
||||||
memcpy(wsc->r_hash2, m4.r_hash2, sizeof(m4.r_hash2));
|
memcpy(wsc->r_hash2, m4.r_hash2, sizeof(m4.r_hash2));
|
||||||
eap_wsc_send_m5(eap, pdu, len);
|
eap_wsc_send_m5(eap, pdu, len);
|
||||||
return;
|
|
||||||
|
|
||||||
invalid_settings:
|
cleanup:
|
||||||
|
explicit_bzero(&m4es, sizeof(m4es));
|
||||||
|
explicit_bzero(decrypted, decrypted_len);
|
||||||
l_free(decrypted);
|
l_free(decrypted);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
return;
|
||||||
|
|
||||||
send_nack:
|
send_nack:
|
||||||
eap_wsc_send_nack(eap, WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE);
|
eap_wsc_send_nack(eap, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eap_wsc_send_m3(struct eap_state *eap,
|
static void eap_wsc_send_m3(struct eap_state *eap,
|
||||||
|
@ -1323,7 +1360,11 @@ static bool eap_wsc_load_settings(struct eap_state *eap,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
l_free(wsc->device_password);
|
if (wsc->device_password) {
|
||||||
|
explicit_bzero(wsc->device_password,
|
||||||
|
strlen(wsc->device_password));
|
||||||
|
l_free(wsc->device_password);
|
||||||
|
}
|
||||||
|
|
||||||
if (wsc->private)
|
if (wsc->private)
|
||||||
l_key_free(wsc->private);
|
l_key_free(wsc->private);
|
||||||
|
|
|
@ -169,6 +169,7 @@ static void wsc_store_credentials(struct wsc *wsc)
|
||||||
|
|
||||||
l_settings_set_value(settings, "Security",
|
l_settings_set_value(settings, "Security",
|
||||||
"PreSharedKey", hex);
|
"PreSharedKey", hex);
|
||||||
|
explicit_bzero(hex, strlen(hex));
|
||||||
l_free(hex);
|
l_free(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +253,8 @@ static void wsc_credential_obtained(struct wsc *wsc,
|
||||||
l_debug("auth_type: %02x, encryption_type: %02x",
|
l_debug("auth_type: %02x, encryption_type: %02x",
|
||||||
cred->auth_type, cred->encryption_type);
|
cred->auth_type, cred->encryption_type);
|
||||||
|
|
||||||
l_debug("Key (%u): %.*s", cred->network_key_len,
|
if (getenv("IWD_WSC_DEBUG_KEYS"))
|
||||||
|
l_debug("Key (%u): %.*s", cred->network_key_len,
|
||||||
cred->network_key_len, cred->network_key);
|
cred->network_key_len, cred->network_key);
|
||||||
|
|
||||||
if (wsc->n_creds == L_ARRAY_SIZE(wsc->creds)) {
|
if (wsc->n_creds == L_ARRAY_SIZE(wsc->creds)) {
|
||||||
|
@ -309,6 +311,7 @@ static void wsc_credential_obtained(struct wsc *wsc,
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(wsc->creds[wsc->n_creds].psk, decoded, 32);
|
memcpy(wsc->creds[wsc->n_creds].psk, decoded, 32);
|
||||||
|
explicit_bzero(decoded, 32);
|
||||||
l_free(decoded);
|
l_free(decoded);
|
||||||
} else {
|
} else {
|
||||||
const char *passphrase =
|
const char *passphrase =
|
||||||
|
@ -336,6 +339,8 @@ static void wsc_credential_obtained(struct wsc *wsc,
|
||||||
|
|
||||||
l_warn("Found duplicate credentials for SSID: %s",
|
l_warn("Found duplicate credentials for SSID: %s",
|
||||||
wsc->creds[i].ssid);
|
wsc->creds[i].ssid);
|
||||||
|
explicit_bzero(&wsc->creds[wsc->n_creds],
|
||||||
|
sizeof(wsc->creds[wsc->n_creds]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue