diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index d0957eb..f9d34b2 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3027,6 +3027,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;
@@ -3043,6 +3044,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);
@@ -4105,6 +4113,60 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
 	return -1;
 }
 
+int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var,
+			    const char *value, int line)
+{
+	char *val;
+	size_t len;
+
+	if (os_strcmp(var, "dik_cipher") == 0) {
+		identity->dik_cipher = atoi(value);
+		return 0;
+	}
+
+	if (os_strcmp(var, "dik_len") == 0) {
+		identity->dik_len = atoi(value);
+		return 0;
+	}
+
+	val = wpa_config_parse_string(value, &len);
+	if (val == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
+			   "value '%s'.", line, var, value);
+		return -1;
+	}
+
+	if (os_strcmp(var, "dik_data") == 0) {
+		os_free(identity->dik_data);
+		identity->dik_data = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "pmk_len") == 0) {
+		identity->pmk_len = atoi(value);
+		return 0;
+	}
+
+	if (os_strcmp(var, "pmk") == 0) {
+		os_free(identity->pmk);
+		identity->pmk = val;
+		return 0;
+	}
+	if (os_strcmp(var, "pmkid") == 0) {
+		os_free(identity->pmkid);
+		identity->pmkid = val;
+		return 0;
+	}
+
+	if (line) {
+		wpa_printf(MSG_ERROR, "Line %d: unknown identity field '%s'.",
+			   line, var);
+	}
+
+	os_free(val);
+
+	return -1;
+}
 
 static char * alloc_int_str(int val)
 {
@@ -5763,3 +5825,73 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
 
 	return ret;
 }
+
+void wpa_config_free_identity(struct wpa_dev_ik *identity)
+{
+	os_free(identity->dik_data);
+	os_free(identity->pmk);
+	os_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 == NULL)
+		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 == NULL)
+		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 6b8f0cb..3333125 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -417,6 +417,57 @@ 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 Indetity 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 credential
+	 *
+	 * 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 through the
+	 * control interface.
+	 */
+	int id;
+
+	/**
+	 * dik_cipher - Device Identity key cipher version
+	 */
+	int dik_cipher;
+
+	/**
+	 * dik_len - Device Identity key length
+	 */
+	int dik_len;
+
+	/**
+	 * dik_data - Device Identity key which is unique for the device
+	 */
+	char *dik_data;
+
+	/**
+	 * pmk_len - PMK length
+	 */
+	int pmk_len;
+
+	/**
+	 * pmk - pmk associated of previous connection with the given device
+	 */
+	char *pmk;
+
+	/**
+	 * pmkid - pmkid of previous connection with the given device
+	 */
+	char *pmkid;
+};
 
 #define CFG_CHANGED_DEVICE_NAME BIT(0)
 #define CFG_CHANGED_CONFIG_METHODS BIT(1)
@@ -1823,6 +1874,12 @@ struct wpa_config {
 
 	/* length of DevIK */
 	size_t dik_len;
+	/**
+	 * identity - Head of the list of peer device identities
+	 *
+	 * This is the head for the list of all the paired devices.
+	 */
+	struct wpa_dev_ik *identity;
 };
 
 
@@ -1867,6 +1924,8 @@ int wpa_config_remove_cred(struct wpa_config *config, int id);
 void wpa_config_free_cred(struct wpa_cred *cred);
 int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
 			const char *value, int line);
+int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var,
+			    const char *value, int line);
 char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var);
 
 struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
@@ -1919,5 +1978,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp,
  * Each configuration backend needs to implement this function.
  */
 int wpa_config_write(const char *name, struct wpa_config *config);
+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);
 
 #endif /* CONFIG_H */
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 68aed57..f79b301 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -296,6 +296,60 @@ 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 == NULL)
+		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 == NULL) {
+			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 +358,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 +381,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 +442,20 @@ 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 == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to "
+					   "parse identity block.", line);
+				errors++;
+				continue;
+			}
+			if (identity_head == NULL) {
+				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 +469,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) {
@@ -1075,6 +1149,21 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
 			cred->imsi_privacy_attr);
 }
 
+static void wpa_config_write_identity(FILE *f, struct wpa_dev_ik *dev_ik)
+{
+	fprintf(f, "\tdik_cipher=%d\n", dev_ik->dik_cipher);
+
+	fprintf(f, "\tdik_len=%d\n", dev_ik->dik_len);
+	if (dev_ik->dik_data)
+		fprintf(f, "\tdik_data=\"%s\"\n", dev_ik->dik_data);
+
+	fprintf(f, "\tpmk_len=%d\n", dev_ik->pmk_len);
+	if (dev_ik->pmk)
+		fprintf(f, "\tpmk=\"%s\"\n", dev_ik->pmk);
+
+	if (dev_ik->pmkid)
+		fprintf(f, "\tpmkid=\"%s\"\n", dev_ik->pmkid);
+}
 
 #ifndef CONFIG_NO_CONFIG_BLOBS
 static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
@@ -1646,6 +1735,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 */
@@ -1700,6 +1790,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);
