eap-tls: Add ServerDomainMask config option

Allow users to provide a glob string that the contents of the server
certificate's subject DN should be matched against as a primitive
protection against rogue APs using certificates purchased from
commercial CAs trusted by the client.  If the network uses an AP
certificate emitted by a commerical CA and the clients are configured
to trust those CAs so that the client configurations don't have to be
updated when the AP renews its certificate, this new option can be used
to check if the CN in the AP certificate's DN matches the known domain
name.  This logic assumes that the commercial CAs provide enough
assurance that only the owner of the domain can buy a certificate with
that domain in the CN field.

The format of this option is similar to apple's TLSTrustedServerNames
and wpa_supplicant's domain_match/domain_suffix_match format, the exact
syntax is documented in ell/tls.c.
This commit is contained in:
Andrew Zaborowski 2019-08-23 03:30:23 +02:00 committed by Denis Kenzior
parent 0ebe960daf
commit fc4685abec
1 changed files with 33 additions and 0 deletions

View File

@ -117,6 +117,7 @@ struct eap_tls_state {
char *client_cert;
char *client_key;
char *passphrase;
char **domain_mask;
const struct eap_tls_variant_ops *variant_ops;
void *variant_data;
@ -186,6 +187,7 @@ void eap_tls_common_state_free(struct eap_state *eap)
l_free(eap_tls->passphrase);
}
l_strv_free(eap_tls->domain_mask);
l_free(eap_tls);
}
@ -552,6 +554,9 @@ static bool eap_tls_tunnel_init(struct eap_state *eap)
return false;
}
if (eap_tls->domain_mask)
l_tls_set_domain_mask(eap_tls->tunnel, eap_tls->domain_mask);
if (!l_tls_start(eap_tls->tunnel)) {
l_error("%s: Failed to start the TLS client",
eap_get_method_name(eap));
@ -765,6 +770,7 @@ int eap_tls_common_settings_check(struct l_settings *settings,
ssize_t result;
uint8_t *encrypted, *decrypted;
struct l_key *pub_key;
const char *domain_mask_str;
L_AUTO_FREE_VAR(char *, path);
L_AUTO_FREE_VAR(char *, client_cert) = NULL;
@ -930,6 +936,22 @@ int eap_tls_common_settings_check(struct l_settings *settings,
goto done;
}
/*
* Require CACert if ServerDomainMask is present. If the server
* certificate is not being checked against any trusted certificates
* there's no point validating its contents and we wouldn't even
* receive the subject DN from ell, because it may be freely made up.
*/
snprintf(setting_key, sizeof(setting_key), "%sServerDomainMask",
prefix);
domain_mask_str = l_settings_get_value(settings, "Security",
setting_key);
if (domain_mask_str && !cacerts) {
l_error("%s was set but no CA Certificates given", setting_key);
ret = -EINVAL;
goto done;
}
ret = 0;
done:
l_queue_destroy(cacerts,
@ -950,6 +972,7 @@ bool eap_tls_common_settings_load(struct eap_state *eap,
{
struct eap_tls_state *eap_tls;
char setting_key[72];
char *domain_mask_str;
eap_tls = l_new(struct eap_tls_state, 1);
@ -974,6 +997,16 @@ bool eap_tls_common_settings_load(struct eap_state *eap,
eap_tls->passphrase = l_settings_get_string(settings, "Security",
setting_key);
snprintf(setting_key, sizeof(setting_key), "%sServerDomainMask",
prefix);
domain_mask_str = l_settings_get_string(settings, "Security",
setting_key);
if (domain_mask_str) {
eap_tls->domain_mask = l_strsplit(domain_mask_str, ';');
l_free(domain_mask_str);
}
eap_set_data(eap, eap_tls);
return true;