EAP peer: Add a concept of a separate machine credential

This is an initial step in adding support for configuring separate user
and machine credentials. The new wpa_supplicant network profile
parameters machine_identity and machine_password are similar to the
existing identity and password, but explicitly assigned for the purpose
of machine authentication.

This commit alone does not change actual EAP peer method behavior as
separate commits are needed to determine when there is an explicit
request for machine authentication. Furthermore, this is only addressing
the username/password credential type, i.e., additional changes
following this design approach will be needed for certificate
credentials.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2019-08-20 13:10:34 +03:00
parent 0b39274ca3
commit c724a0a16c
5 changed files with 242 additions and 19 deletions

View file

@ -266,6 +266,7 @@ SM_STATE(EAP, INITIALIZE)
sm->expected_failure = 0;
sm->reauthInit = FALSE;
sm->erp_seq = (u32) -1;
sm->use_machine_cred = 0;
}
@ -1675,6 +1676,11 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
identity_len = config->anonymous_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
identity, identity_len);
} else if (sm->use_machine_cred) {
identity = config->machine_identity;
identity_len = config->machine_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
@ -2741,8 +2747,15 @@ struct eap_peer_config * eap_get_config(struct eap_sm *sm)
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
if (config == NULL)
if (!config)
return NULL;
if (sm->use_machine_cred) {
*len = config->machine_identity_len;
return config->machine_identity;
}
*len = config->identity_len;
return config->identity;
}
@ -2752,14 +2765,24 @@ static int eap_get_ext_password(struct eap_sm *sm,
struct eap_peer_config *config)
{
char *name;
const u8 *password;
size_t password_len;
if (config->password == NULL)
if (sm->use_machine_cred) {
password = config->machine_password;
password_len = config->machine_password_len;
} else {
password = config->password;
password_len = config->password_len;
}
if (!password)
return -1;
name = os_zalloc(config->password_len + 1);
if (name == NULL)
name = os_zalloc(password_len + 1);
if (!name)
return -1;
os_memcpy(name, config->password, config->password_len);
os_memcpy(name, password, password_len);
ext_password_free(sm->ext_pw_buf);
sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
@ -2778,16 +2801,25 @@ static int eap_get_ext_password(struct eap_sm *sm,
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
if (config == NULL)
if (!config)
return NULL;
if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
if ((sm->use_machine_cred &&
(config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
(!sm->use_machine_cred &&
(config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
*len = wpabuf_len(sm->ext_pw_buf);
return wpabuf_head(sm->ext_pw_buf);
}
if (sm->use_machine_cred) {
*len = config->machine_password_len;
return config->machine_password;
}
*len = config->password_len;
return config->password;
}
@ -2805,10 +2837,14 @@ const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
{
struct eap_peer_config *config = eap_get_config(sm);
if (config == NULL)
if (!config)
return NULL;
if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
if ((sm->use_machine_cred &&
(config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
(!sm->use_machine_cred &&
(config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
if (hash)
@ -2817,6 +2853,14 @@ const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
return wpabuf_head(sm->ext_pw_buf);
}
if (sm->use_machine_cred) {
*len = config->machine_password_len;
if (hash)
*hash = !!(config->flags &
EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH);
return config->machine_password;
}
*len = config->password_len;
if (hash)
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);

View file

@ -49,6 +49,20 @@ struct eap_peer_config {
u8 *imsi_identity;
size_t imsi_identity_len;
/**
* machine_identity - EAP Identity for machine credential
*
* This field is used to set the machine identity or NAI for cases where
* and explicit machine credential (instead of or in addition to a user
* credential (from %identity) is needed.
*/
u8 *machine_identity;
/**
* machine_identity_len - EAP Identity length for machine credential
*/
size_t machine_identity_len;
/**
* password - Password string for EAP
*
@ -72,6 +86,20 @@ struct eap_peer_config {
*/
size_t password_len;
/**
* machine_password - Password string for EAP machine credential
*
* This field is used when machine credential based on username/password
* is needed instead of a user credential (from %password). See
* %password for more details on the format.
*/
u8 *machine_password;
/**
* machine_password_len - Length of machine credential password field
*/
size_t machine_password_len;
/**
* ca_cert - File path to CA certificate file (PEM/DER)
*
@ -751,6 +779,8 @@ struct eap_peer_config {
#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
#define EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH BIT(2)
#define EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD BIT(3)
/**
* flags - Network configuration flags (bitfield)
*
@ -760,6 +790,10 @@ struct eap_peer_config {
* instead of plaintext password
* bit 1 = password is stored in external storage; the value in the
* password field is the name of that external entry
* bit 2 = machine password is represented as a 16-byte NtPasswordHash
* value instead of plaintext password
* bit 3 = machine password is stored in external storage; the value in
* the password field is the name of that external entry
*/
u32 flags;

View file

@ -382,6 +382,7 @@ struct eap_sm {
unsigned int expected_failure:1;
unsigned int ext_cert_check:1;
unsigned int waiting_ext_cert_check:1;
unsigned int use_machine_cred:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};

View file

@ -1614,7 +1614,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
#ifdef CONFIG_EXT_PASSWORD
if (os_strncmp(value, "ext:", 4) == 0) {
char *name = os_strdup(value + 4);
if (name == NULL)
if (!name)
return -1;
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = (u8 *) name;
@ -1630,9 +1630,9 @@ static int wpa_config_parse_password(const struct parse_data *data,
size_t res_len;
tmp = wpa_config_parse_string(value, &res_len);
if (tmp == NULL) {
wpa_printf(MSG_ERROR, "Line %d: failed to parse "
"password.", line);
if (!tmp) {
wpa_printf(MSG_ERROR,
"Line %d: failed to parse password.", line);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
@ -1650,13 +1650,14 @@ static int wpa_config_parse_password(const struct parse_data *data,
/* NtPasswordHash: hash:<32 hex digits> */
if (os_strlen(value + 5) != 2 * 16) {
wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
"(expected 32 hex digits)", line);
wpa_printf(MSG_ERROR,
"Line %d: Invalid password hash length (expected 32 hex digits)",
line);
return -1;
}
hash = os_malloc(16);
if (hash == NULL)
if (!hash)
return -1;
if (hexstr2bin(value + 5, hash, 16)) {
@ -1683,19 +1684,118 @@ static int wpa_config_parse_password(const struct parse_data *data,
}
static int wpa_config_parse_machine_password(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
u8 *hash;
if (os_strcmp(value, "NULL") == 0) {
if (!ssid->eap.machine_password)
return 1; /* Already unset */
wpa_printf(MSG_DEBUG,
"Unset configuration string 'machine_password'");
bin_clear_free(ssid->eap.machine_password,
ssid->eap.machine_password_len);
ssid->eap.machine_password = NULL;
ssid->eap.machine_password_len = 0;
return 0;
}
#ifdef CONFIG_EXT_PASSWORD
if (os_strncmp(value, "ext:", 4) == 0) {
char *name = os_strdup(value + 4);
if (!name)
return -1;
bin_clear_free(ssid->eap.machine_password,
ssid->eap.machine_password_len);
ssid->eap.machine_password = (u8 *) name;
ssid->eap.machine_password_len = os_strlen(name);
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
return 0;
}
#endif /* CONFIG_EXT_PASSWORD */
if (os_strncmp(value, "hash:", 5) != 0) {
char *tmp;
size_t res_len;
tmp = wpa_config_parse_string(value, &res_len);
if (!tmp) {
wpa_printf(MSG_ERROR,
"Line %d: failed to parse machine_password.",
line);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
(u8 *) tmp, res_len);
bin_clear_free(ssid->eap.machine_password,
ssid->eap.machine_password_len);
ssid->eap.machine_password = (u8 *) tmp;
ssid->eap.machine_password_len = res_len;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
return 0;
}
/* NtPasswordHash: hash:<32 hex digits> */
if (os_strlen(value + 5) != 2 * 16) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid machine_password hash length (expected 32 hex digits)",
line);
return -1;
}
hash = os_malloc(16);
if (!hash)
return -1;
if (hexstr2bin(value + 5, hash, 16)) {
os_free(hash);
wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
line);
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
if (ssid->eap.machine_password &&
ssid->eap.machine_password_len == 16 &&
os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
bin_clear_free(hash, 16);
return 1;
}
bin_clear_free(ssid->eap.machine_password,
ssid->eap.machine_password_len);
ssid->eap.machine_password = hash;
ssid->eap.machine_password_len = 16;
ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
return 0;
}
#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_password(const struct parse_data *data,
struct wpa_ssid *ssid)
{
char *buf;
if (ssid->eap.password == NULL)
if (!ssid->eap.password)
return NULL;
#ifdef CONFIG_EXT_PASSWORD
if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
buf = os_zalloc(4 + ssid->eap.password_len + 1);
if (buf == NULL)
if (!buf)
return NULL;
os_memcpy(buf, "ext:", 4);
os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
@ -1709,7 +1809,7 @@ static char * wpa_config_write_password(const struct parse_data *data,
}
buf = os_malloc(5 + 32 + 1);
if (buf == NULL)
if (!buf)
return NULL;
os_memcpy(buf, "hash:", 5);
@ -1717,6 +1817,44 @@ static char * wpa_config_write_password(const struct parse_data *data,
return buf;
}
static char * wpa_config_write_machine_password(const struct parse_data *data,
struct wpa_ssid *ssid)
{
char *buf;
if (!ssid->eap.machine_password)
return NULL;
#ifdef CONFIG_EXT_PASSWORD
if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
if (!buf)
return NULL;
os_memcpy(buf, "ext:", 4);
os_memcpy(buf + 4, ssid->eap.machine_password,
ssid->eap.machine_password_len);
return buf;
}
#endif /* CONFIG_EXT_PASSWORD */
if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
return wpa_config_write_string(
ssid->eap.machine_password,
ssid->eap.machine_password_len);
}
buf = os_malloc(5 + 32 + 1);
if (!buf)
return NULL;
os_memcpy(buf, "hash:", 5);
wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
return buf;
}
#endif /* NO_CONFIG_WRITE */
#endif /* IEEE8021X_EAPOL */
@ -2249,7 +2387,9 @@ static const struct parse_data ssid_fields[] = {
{ STR_LENe(identity) },
{ STR_LENe(anonymous_identity) },
{ STR_LENe(imsi_identity) },
{ STR_LENe(machine_identity) },
{ FUNC_KEY(password) },
{ FUNC_KEY(machine_password) },
{ STRe(ca_cert) },
{ STRe(ca_path) },
{ STRe(client_cert) },
@ -2520,7 +2660,9 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
bin_clear_free(eap->machine_password, eap->machine_password_len);
os_free(eap->ca_cert);
os_free(eap->ca_path);
os_free(eap->client_cert);

View file

@ -774,7 +774,9 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(identity);
STR(anonymous_identity);
STR(imsi_identity);
STR(machine_identity);
STR(password);
STR(machine_password);
STR(ca_cert);
STR(ca_path);
STR(client_cert);