From: Shivani Baranwal Date: Sun, 4 Aug 2024 22:49:48 +0000 (+0530) Subject: P2P2: Add device identity block to wpa_supplicant configuration X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=417c67468b8d9a205ee48a1fec9affe75650301f;p=thirdparty%2Fhostap.git P2P2: Add device identity block to wpa_supplicant configuration Add device identity block to store DIK, PMK, PMKID, and cipher version. This persistent data is used during pairing verification of previously paired peers. This commit defines the data structures and adds reading and writing routines. The actual use of the information will be added in following commits. Signed-off-by: Shivani Baranwal --- diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 13043afe9..6284b0ec8 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3028,6 +3028,7 @@ void wpa_config_free(struct wpa_config *config) { struct wpa_ssid *ssid, *prev = NULL; struct wpa_cred *cred, *cprev; + struct wpa_dev_ik *identity, *iprev; int i; ssid = config->ssid; @@ -3044,6 +3045,13 @@ void wpa_config_free(struct wpa_config *config) wpa_config_free_cred(cprev); } + identity = config->identity; + while (identity) { + iprev = identity; + identity = identity->next; + wpa_config_free_identity(iprev); + } + wpa_config_flush_blobs(config); wpabuf_free(config->wps_vendor_ext_m1); @@ -5763,3 +5771,129 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line) return ret; } + + +int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var, + const char *value, int line) +{ + char *val; + size_t len; + int ret = 0; + + if (os_strcmp(var, "dik_cipher") == 0) { + identity->dik_cipher = atoi(value); + return 0; + } + + val = wpa_config_parse_string(value, &len); + if (!val) { + wpa_printf(MSG_ERROR, + "Line %d: invalid field '%s' string value '%s'.", + line, var, value); + return -1; + } + + if (os_strcmp(var, "dik") == 0) { + wpabuf_free(identity->dik); + identity->dik = wpabuf_alloc_copy(val, len); + if (!identity->dik) + ret = -1; + } else if (os_strcmp(var, "pmk") == 0) { + wpabuf_free(identity->pmk); + identity->pmk = wpabuf_alloc_copy(val, len); + if (!identity->pmk) + ret = -1; + } else if (os_strcmp(var, "pmkid") == 0) { + if (len == PMKID_LEN) { + wpabuf_free(identity->pmkid); + identity->pmkid = wpabuf_alloc_copy(val, len); + if (!identity->pmkid) + ret = -1; + } else { + wpa_printf(MSG_ERROR, + "Line %d: invalid field '%s' string value '%s'.", + line, var, value); + ret = -1; + } + } else if (line) { + wpa_printf(MSG_ERROR, "Line %d: unknown identity field '%s'.", + line, var); + ret = -1; + } + + os_free(val); + return ret; +} + + +void wpa_config_free_identity(struct wpa_dev_ik *identity) +{ + wpabuf_clear_free(identity->dik); + wpabuf_clear_free(identity->pmk); + wpabuf_free(identity->pmkid); + os_free(identity); +} + + +/** + * wpa_config_add_identity - Add a new device identity with empty configuration + * @config: Configuration data from wpa_config_read() + * Returns: The new device identity or %NULL if operation failed + */ +struct wpa_dev_ik * wpa_config_add_identity(struct wpa_config *config) +{ + int id; + struct wpa_dev_ik *identity, *last = NULL; + + id = -1; + identity = config->identity; + while (identity) { + if (identity->id > id) + id = identity->id; + last = identity; + identity = identity->next; + } + id++; + + identity = os_zalloc(sizeof(*identity)); + if (!identity) + return NULL; + identity->id = id; + if (last) + last->next = identity; + else + config->identity = identity; + + return identity; +} + + +/** + * wpa_config_remove_identity - Remove a configured identity based on id + * @config: Configuration data from wpa_config_read() + * @id: Unique network id to search for + * Returns: 0 on success, or -1 if the network was not found + */ +int wpa_config_remove_identity(struct wpa_config *config, int id) +{ + struct wpa_dev_ik *identity, *prev = NULL; + + identity = config->identity; + while (identity) { + if (id == identity->id) + break; + prev = identity; + identity = identity->next; + } + + if (!identity) + return -1; + + if (prev) + prev->next = identity->next; + else + config->identity = identity->next; + + wpa_config_free_identity(identity); + return 0; +} diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 979f083da..b860dd154 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -417,6 +417,47 @@ struct wpa_cred { int sim_num; }; +struct wpa_dev_ik { + /** + * next - Next device identity in the list + * + * This pointer can be used to iterate over all device identity keys. + * The head of this list is stored in the dev_ik field of struct + * wpa_config. + */ + struct wpa_dev_ik *next; + + /** + * id - Unique id for the identity + * + * This identifier is used as a unique identifier for each identity + * block when using the control interface. Each identity is allocated + * an id when it is being created, either when reading the + * configuration file or when a new identity is added. + */ + int id; + + /** + * dik_cipher - Device identity key cipher version + */ + int dik_cipher; + + /** + * dik - Device identity key which is unique for the device + */ + struct wpabuf *dik; + + /** + * pmk - PMK associated with the previous connection with the device + */ + struct wpabuf *pmk; + + /** + * pmkid - PMKID used in the previous connection with the device + */ + struct wpabuf *pmkid; +}; + #define CFG_CHANGED_DEVICE_NAME BIT(0) #define CFG_CHANGED_CONFIG_METHODS BIT(1) @@ -1820,6 +1861,13 @@ struct wpa_config { /* DevIK */ struct wpabuf *dik; + + /** + * identity - P2P2 peer device identities + * + * This is the head for the list of all the paired devices. + */ + struct wpa_dev_ik *identity; }; @@ -1866,6 +1914,12 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, const char *value, int line); char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var); +int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var, + const char *value, int line); +void wpa_config_free_identity(struct wpa_dev_ik *identity); +struct wpa_dev_ik * wpa_config_add_identity(struct wpa_config *config); +int wpa_config_remove_identity(struct wpa_config *config, int id); + struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, const char *driver_param); #ifndef CONFIG_NO_STDOUT_DEBUG diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 20b309a7f..9bbe44db6 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -296,6 +296,65 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f, #endif /* CONFIG_NO_CONFIG_BLOBS */ +static struct wpa_dev_ik * wpa_config_read_identity(FILE *f, int *line, int id) +{ + struct wpa_dev_ik *identity; + int errors = 0, end = 0; + char buf[256], *pos, *pos2; + + wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new identity block", + *line); + identity = os_zalloc(sizeof(*identity)); + if (!identity) + return NULL; + identity->id = id; + + while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { + if (os_strcmp(pos, "}") == 0) { + end = 1; + break; + } + + pos2 = os_strchr(pos, '='); + if (!pos2) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid identity line '%s'.", + *line, pos); + errors++; + continue; + } + + *pos2++ = '\0'; + if (*pos2 == '"') { + if (os_strchr(pos2 + 1, '"') == NULL) { + wpa_printf(MSG_ERROR, + "Line %d: invalid quotation '%s'.", + *line, pos2); + errors++; + continue; + } + } + + if (wpa_config_set_identity(identity, pos, pos2, *line) < 0) + errors++; + } + + if (!end) { + wpa_printf(MSG_ERROR, + "Line %d: identity block was not terminated properly.", + *line); + errors++; + } + + if (errors) { + wpa_config_free_identity(identity); + identity = NULL; + } + + return identity; +} + + struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, bool ro) { @@ -304,9 +363,11 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, int errors = 0, line = 0; struct wpa_ssid *ssid, *tail, *head; struct wpa_cred *cred, *cred_tail, *cred_head; + struct wpa_dev_ik *identity, *identity_tail, *identity_head; struct wpa_config *config; static int id = 0; static int cred_id = 0; + static int identity_id = 0; if (name == NULL) return NULL; @@ -325,6 +386,9 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, cred_tail = cred_head = config->cred; while (cred_tail && cred_tail->next) cred_tail = cred_tail->next; + identity_tail = identity_head = config->identity; + while (identity_tail && identity_tail->next) + identity_tail = identity_tail->next; wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name); f = fopen(name, "r"); @@ -383,6 +447,22 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, continue; } #endif /* CONFIG_NO_CONFIG_BLOBS */ + } else if (os_strcmp(pos, "identity={") == 0) { + identity = wpa_config_read_identity(f, &line, + identity_id++); + if (!identity) { + wpa_printf(MSG_ERROR, + "Line %d: failed to parse identity block.", + line); + errors++; + continue; + } + if (!identity_head) { + identity_head = identity_tail = identity; + } else { + identity_tail->next = identity; + identity_tail = identity; + } } else if (wpa_config_process_global(config, pos, line) < 0) { wpa_printf(MSG_ERROR, "Line %d: Invalid configuration " "line '%s'.", line, pos); @@ -396,6 +476,7 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, config->ssid = head; wpa_config_debug_dump_networks(config); config->cred = cred_head; + config->identity = identity_head; #ifndef WPA_IGNORE_CONFIG_ERRORS if (errors) { @@ -1635,6 +1716,20 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) } } +static void wpa_config_write_identity(FILE *f, struct wpa_dev_ik *dev_ik) +{ + fprintf(f, "\tdik_cipher=%d\n", dev_ik->dik_cipher); + + if (dev_ik->dik) + write_global_bin(f, "\tdik", dev_ik->dik); + + if (dev_ik->pmk) + write_global_bin(f, "\tpmk", dev_ik->pmk); + + if (dev_ik->pmkid) + write_global_bin(f, "\tpmkid", dev_ik->pmkid); +} + #endif /* CONFIG_NO_CONFIG_WRITE */ @@ -1644,6 +1739,7 @@ int wpa_config_write(const char *name, struct wpa_config *config) FILE *f; struct wpa_ssid *ssid; struct wpa_cred *cred; + struct wpa_dev_ik *dev_ik; #ifndef CONFIG_NO_CONFIG_BLOBS struct wpa_config_blob *blob; #endif /* CONFIG_NO_CONFIG_BLOBS */ @@ -1698,6 +1794,12 @@ int wpa_config_write(const char *name, struct wpa_config *config) fprintf(f, "}\n"); } + for (dev_ik = config->identity; dev_ik; dev_ik = dev_ik->next) { + fprintf(f, "\nidentity={\n"); + wpa_config_write_identity(f, dev_ik); + fprintf(f, "}\n"); + } + #ifndef CONFIG_NO_CONFIG_BLOBS for (blob = config->blobs; blob; blob = blob->next) { ret = wpa_config_write_blob(f, blob);