From 246e76c7b0d8964454c3a56c6196b5a5dc191d23 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Wed, 18 Apr 2018 07:03:22 +0200 Subject: [PATCH] eap: Validate settings, report passwords needed With the goal of requesting the required passwords/passphrases, such as the TLS private key passphrase, from the agent, add a static method eap_check_settings to validate the settings and calculate what passwords are needed for those settings, if any. This is separate from eap_load_settings because that can only be called later, once we've got an eap state machine object. We need to get all the needed EAP credentials from the user before we even start connecting. While we do this, we also validate the settings and output any error messages through l_error (this could be changed so the messages go somewhere else in the future), so I removed the error messages from eap_load_settings and that method now assumes that eap_check_settings has been called before. eap_check_settings calls the appropriate method's .check_settings method if the settings are complete enough to contain the method name. The policy is that any data can be provided inside the l_settings object (from the network provisioning/config file), but some of the more sensitive fields, like private key passwords, can be optionally omitted and then the UI will ask for them and iwd will be careful with caching them. Within struct eap_secret_info, "id" is mainly for the EAP method to locate the info in the list. "value" is the actual value returned by agent. "parameter" is an optional string to be passed to the agent. For a private key passphrase it may be the path to the key file, for a password it may be the username for which the password is requested. --- src/eap.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/eap.h | 25 +++++++++++++ 2 files changed, 123 insertions(+), 9 deletions(-) diff --git a/src/eap.c b/src/eap.c index 5e2594d7..86c0412a 100644 --- a/src/eap.c +++ b/src/eap.c @@ -347,6 +347,102 @@ void eap_rx_packet(struct eap_state *eap, const uint8_t *pkt, size_t len) } } +bool eap_secret_info_match(const void *a, const void *b) +{ + const struct eap_secret_info *s = a; + + return !strcmp(s->id, b); +} + +void eap_append_secret(struct l_queue **out_missing, enum eap_secret_type type, + const char *id, const char *parameter) +{ + struct eap_secret_info *info; + + if (!*out_missing) + *out_missing = l_queue_new(); + + info = l_new(struct eap_secret_info, 1); + info->id = l_strdup(id); + info->type = type; + info->parameter = l_strdup(parameter); + l_queue_push_tail(*out_missing, info); +} + +void eap_secret_info_free(void *data) +{ + struct eap_secret_info *info = data; + + if (!info) + return; + + if (info->value) { + memset(info->value, 0, strlen(info->value)); + l_free(info->value); + } + + if (info->parameter) { + memset(info->parameter, 0, strlen(info->parameter)); + l_free(info->parameter); + } + + l_free(info->id); + l_free(info); +} + +bool eap_check_settings(struct l_settings *settings, struct l_queue *secrets, + const char *prefix, bool set_key_material, + struct l_queue **out_missing) +{ + char setting[64]; + const char *method_name; + const struct l_queue_entry *entry; + struct eap_method *method; + + snprintf(setting, sizeof(setting), "%sMethod", prefix); + method_name = l_settings_get_value(settings, "Security", setting); + + if (!method_name) { + l_error("Property %s missing", setting); + + return false; + } + + for (entry = l_queue_get_entries(eap_methods); entry; + entry = entry->next) { + method = entry->data; + + if (!strcasecmp(method_name, method->name)) + break; + } + + if (!entry) { + l_error("EAP method \"%s\" unsupported", method_name); + + return false; + } + + /* Check if selected method is suitable for 802.1x */ + if (set_key_material && !method->exports_msk) { + l_error("EAP method \"%s\" doesn't export key material", + method_name); + + return false; + } + + snprintf(setting, sizeof(setting), "%sIdentity", prefix); + if (!l_settings_get_value(settings, "Security", setting)) { + l_error("Property %s is missing", setting); + + return false; + } + + if (!method->check_settings) + return true; + + return method->check_settings(settings, secrets, prefix, out_missing); +} + bool eap_load_settings(struct eap_state *eap, struct l_settings *settings, const char *prefix) { @@ -376,12 +472,8 @@ bool eap_load_settings(struct eap_state *eap, struct l_settings *settings, return false; /* Check if selected method is suitable for 802.1x */ - if (eap->set_key_material && !eap->method->exports_msk) { - l_error("EAP method \"%s\" doesn't export key material", - method_name); - + if (eap->set_key_material && !eap->method->exports_msk) goto err; - } if (eap->method->load_settings) if (!eap->method->load_settings(eap, settings, prefix)) @@ -396,11 +488,8 @@ bool eap_load_settings(struct eap_state *eap, struct l_settings *settings, eap->identity = l_strdup(eap->method->get_identity(eap)); } - if (!eap->identity) { - l_error("EAP Identity is missing"); - + if (!eap->identity) goto err; - } return true; diff --git a/src/eap.h b/src/eap.h index 15c17fa7..550f0974 100644 --- a/src/eap.h +++ b/src/eap.h @@ -33,6 +33,19 @@ enum eap_result { EAP_RESULT_TIMEOUT, }; +enum eap_secret_type { + EAP_SECRET_LOCAL_PKEY_PASSPHRASE, + EAP_SECRET_REMOTE_PASSWORD, + EAP_SECRET_REMOTE_USER_PASSWORD, +}; + +struct eap_secret_info { + char *id; + enum eap_secret_type type; + char *parameter; + char *value; +}; + typedef void (*eap_tx_packet_func_t)(const uint8_t *eap_data, size_t len, void *user_data); typedef void (*eap_key_material_func_t)(const uint8_t *msk_data, size_t msk_len, @@ -47,6 +60,14 @@ struct eap_state *eap_new(eap_tx_packet_func_t tx_packet, eap_complete_func_t complete, void *user_data); void eap_free(struct eap_state *eap); +bool eap_secret_info_match(const void *a, const void *b); +void eap_append_secret(struct l_queue **out_missing, enum eap_secret_type type, + const char *id, const char *parameter); +void eap_secret_info_free(void *data); + +bool eap_check_settings(struct l_settings *settings, struct l_queue *secrets, + const char *prefix, bool set_key_material, + struct l_queue **out_missing); bool eap_load_settings(struct eap_state *eap, struct l_settings *settings, const char *prefix); @@ -101,6 +122,10 @@ struct eap_method { bool exports_msk; const char *name; + bool (*check_settings)(struct l_settings *settings, + struct l_queue *secrets, const char *prefix, + struct l_queue **out_missing); + bool (*load_settings)(struct eap_state *eap, struct l_settings *settings, const char *prefix);