Interworking: Add support for certificate credentials (EAP-TLS)
This allows Interworking network selection to be used with EAP-TLS (client certificate/private key based credential). Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
10531d2166
commit
11e4f46a10
3 changed files with 104 additions and 3 deletions
|
@ -1782,6 +1782,9 @@ void wpa_config_free_cred(struct wpa_cred *cred)
|
|||
os_free(cred->username);
|
||||
os_free(cred->password);
|
||||
os_free(cred->ca_cert);
|
||||
os_free(cred->client_cert);
|
||||
os_free(cred->private_key);
|
||||
os_free(cred->private_key_passwd);
|
||||
os_free(cred->imsi);
|
||||
os_free(cred->milenage);
|
||||
os_free(cred->domain);
|
||||
|
@ -2257,6 +2260,24 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (os_strcmp(var, "client_cert") == 0) {
|
||||
os_free(cred->client_cert);
|
||||
cred->client_cert = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (os_strcmp(var, "private_key") == 0) {
|
||||
os_free(cred->private_key);
|
||||
cred->private_key = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (os_strcmp(var, "private_key_passwd") == 0) {
|
||||
os_free(cred->private_key_passwd);
|
||||
cred->private_key_passwd = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (os_strcmp(var, "imsi") == 0) {
|
||||
os_free(cred->imsi);
|
||||
cred->imsi = val;
|
||||
|
|
|
@ -80,6 +80,51 @@ struct wpa_cred {
|
|||
*/
|
||||
char *ca_cert;
|
||||
|
||||
/**
|
||||
* client_cert - File path to client certificate file (PEM/DER)
|
||||
*
|
||||
* This field is used with Interworking networking selection for a case
|
||||
* where client certificate/private key is used for authentication
|
||||
* (EAP-TLS). Full path to the file should be used since working
|
||||
* directory may change when wpa_supplicant is run in the background.
|
||||
*
|
||||
* Alternatively, a named configuration blob can be used by setting
|
||||
* this to blob://blob_name.
|
||||
*/
|
||||
char *client_cert;
|
||||
|
||||
/**
|
||||
* private_key - File path to client private key file (PEM/DER/PFX)
|
||||
*
|
||||
* When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
|
||||
* commented out. Both the private key and certificate will be read
|
||||
* from the PKCS#12 file in this case. Full path to the file should be
|
||||
* used since working directory may change when wpa_supplicant is run
|
||||
* in the background.
|
||||
*
|
||||
* Windows certificate store can be used by leaving client_cert out and
|
||||
* configuring private_key in one of the following formats:
|
||||
*
|
||||
* cert://substring_to_match
|
||||
*
|
||||
* hash://certificate_thumbprint_in_hex
|
||||
*
|
||||
* For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
|
||||
*
|
||||
* Note that when running wpa_supplicant as an application, the user
|
||||
* certificate store (My user account) is used, whereas computer store
|
||||
* (Computer account) is used when running wpasvc as a service.
|
||||
*
|
||||
* Alternatively, a named configuration blob can be used by setting
|
||||
* this to blob://blob_name.
|
||||
*/
|
||||
char *private_key;
|
||||
|
||||
/**
|
||||
* private_key_passwd - Password for private key file
|
||||
*/
|
||||
char *private_key_passwd;
|
||||
|
||||
/**
|
||||
* imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
|
||||
*/
|
||||
|
|
|
@ -417,6 +417,20 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap)
|
|||
}
|
||||
|
||||
|
||||
static int nai_realm_cred_cert(struct nai_realm_eap *eap)
|
||||
{
|
||||
if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
|
||||
return 0; /* method not supported */
|
||||
|
||||
if (eap->method != EAP_TYPE_TLS) {
|
||||
/* Only EAP-TLS supported for credential authentication */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
|
||||
struct nai_realm *realm)
|
||||
{
|
||||
|
@ -425,13 +439,19 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
|
|||
if (cred == NULL ||
|
||||
cred->username == NULL ||
|
||||
cred->username[0] == '\0' ||
|
||||
cred->password == NULL ||
|
||||
cred->password[0] == '\0')
|
||||
((cred->password == NULL ||
|
||||
cred->password[0] == '\0') &&
|
||||
(cred->private_key == NULL ||
|
||||
cred->private_key[0] == '\0')))
|
||||
return NULL;
|
||||
|
||||
for (e = 0; e < realm->eap_count; e++) {
|
||||
struct nai_realm_eap *eap = &realm->eap[e];
|
||||
if (nai_realm_cred_username(eap))
|
||||
if (cred->password && cred->password[0] &&
|
||||
nai_realm_cred_username(eap))
|
||||
return eap;
|
||||
if (cred->private_key && cred->private_key[0] &&
|
||||
nai_realm_cred_cert(eap))
|
||||
return eap;
|
||||
}
|
||||
|
||||
|
@ -757,6 +777,19 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
|
|||
wpa_config_set_quoted(ssid, "password", cred->password) < 0)
|
||||
goto fail;
|
||||
|
||||
if (cred->client_cert && cred->client_cert[0] &&
|
||||
wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
|
||||
goto fail;
|
||||
|
||||
if (cred->private_key && cred->private_key[0] &&
|
||||
wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
|
||||
goto fail;
|
||||
|
||||
if (cred->private_key_passwd && cred->private_key_passwd[0] &&
|
||||
wpa_config_set_quoted(ssid, "private_key_passwd",
|
||||
cred->private_key_passwd) < 0)
|
||||
goto fail;
|
||||
|
||||
switch (eap->method) {
|
||||
case EAP_TYPE_TTLS:
|
||||
if (eap->inner_method) {
|
||||
|
@ -796,6 +829,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
|
|||
if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
|
||||
goto fail;
|
||||
break;
|
||||
case EAP_TYPE_TLS:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cred->ca_cert && cred->ca_cert[0] &&
|
||||
|
|
Loading…
Reference in a new issue