]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P2: Add device identity block to wpa_supplicant configuration
authorShivani Baranwal <quic_shivbara@quicinc.com>
Sun, 4 Aug 2024 22:49:48 +0000 (04:19 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 1 Nov 2024 16:07:24 +0000 (18:07 +0200)
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 <quic_shivbara@quicinc.com>
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c

index 13043afe94d878772717ebaf689f3adbe59cd499..6284b0ec8d395fd2e80e184d29dc1f95e47a48d2 100644 (file)
@@ -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;
+}
index 979f083dab54aa4ee2bf6e70134bb23f7a356beb..b860dd154ad1a7c96365e8afe1dd757bdd9d52e1 100644 (file)
@@ -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
index 20b309a7f4884de17e8f53c57f99bbf6d2fbc760..9bbe44db66b890352bf558418da95ebc8b628cae 100644 (file)
@@ -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);