diff --git a/tests/hwsim/test_dbus.py b/tests/hwsim/test_dbus.py
index 1143802c6..1822e0a2c 100644
--- a/tests/hwsim/test_dbus.py
+++ b/tests/hwsim/test_dbus.py
@@ -6091,3 +6091,29 @@ def test_dbus_roam(dev, apdev):
     with TestDbusConnect(bus) as t:
         if not t.success():
             raise Exception("Expected signals not seen")
+
+def test_dbus_creds(dev, apdev):
+    "D-Bus interworking credentials"
+    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    args = {'domain': 'server.w1.fi',
+            'realm': 'server.w1.fi',
+            'eap': 'TTLS',
+            'phase2': 'auth=MSCHAPV2',
+            'username': 'user',
+            'password': 'password',
+            'domain_suffix_match': 'server.w1.fi',
+            'ca_cert': 'auth_serv/ca.pem'}
+
+    path = iface.AddCred(dbus.Dictionary(args, signature='sv'))
+    for k, v in args.items():
+        if k == 'password':
+            continue
+        prop = dev[0].get_cred(0, k)
+        if prop != v:
+            raise Exception('Credential add failed: %s does not match %s' % (prop, v))
+
+    iface.RemoveCred(path)
+    if not "FAIL" in dev[0].get_cred(0, 'domain'):
+        raise Exception("Credential remove failed")
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 2c01943f7..413396a9f 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3570,6 +3570,23 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
 		  END_ARGS
 	  }
 	},
+#ifdef CONFIG_INTERWORKING
+	{ "AddCred", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_add_cred,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "RemoveCred", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_cred,
+	  {
+		  { "path", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_INTERWORKING */
 	{ NULL, NULL, NULL, { END_ARGS } }
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 42db3892e..8ae0afeaa 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -16,6 +16,7 @@
 struct wpa_global;
 struct wpa_supplicant;
 struct wpa_ssid;
+struct wpa_cred;
 struct wps_event_m2d;
 struct wps_event_fail;
 struct wps_credential;
@@ -96,6 +97,9 @@ enum wpas_dbus_sta_prop {
 #define WPAS_DBUS_NEW_P2P_PEERS_PART	"Peers"
 #define	WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
 
+#define WPAS_DBUS_NEW_CREDENTIALS_PART "Credentials"
+#define WPAS_DBUS_NEW_IFACE_CREDENTIAL WPAS_DBUS_NEW_INTERFACE ".Credential"
+
 /* Top-level Errors */
 #define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
 	WPAS_DBUS_NEW_INTERFACE ".UnknownError"
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index db9f30c9a..2b2cefb76 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -148,6 +148,9 @@ static const char * const dont_quote[] = {
 #ifdef CONFIG_P2P
 	"go_p2p_dev_addr", "p2p_client_list", "psk_list",
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+  "roaming_consortium",
+#endif /* CONFIG_INTERWORKING */
 	NULL
 };
 
@@ -328,6 +331,110 @@ error:
 }
 
 
+/**
+ * set_cred_properties - Set the properties of a configured set of
+ * crendentials.
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @cred: wpa_cred structure for a configured credential
+ * @iter: DBus message iterator containing dictionary of network
+ * properties to set.
+ * @error: On failure, an error describing the failure
+ * Returns: TRUE if the request succeeds, FALSE if it failed
+ */
+dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s,
+				struct wpa_cred *cred,
+				DBusMessageIter *iter,
+				DBusError *error)
+{
+	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+	DBusMessageIter	iter_dict;
+	char *value = NULL;
+
+	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
+		return FALSE;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		size_t size = 50;
+		int ret;
+
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		value = NULL;
+		if (entry.type == DBUS_TYPE_ARRAY &&
+		    entry.array_type == DBUS_TYPE_BYTE) {
+			if (entry.array_len <= 0)
+				goto error;
+
+			size = entry.array_len * 2 + 1;
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+
+			ret = wpa_snprintf_hex(value, size,
+					       (u8 *) entry.bytearray_value,
+					       entry.array_len);
+			if (ret <= 0)
+				goto error;
+		} else if (entry.type == DBUS_TYPE_STRING) {
+			if (should_quote_opt(entry.key)) {
+				size = os_strlen(entry.str_value);
+
+				size += 3;
+				value = os_zalloc(size);
+				if (value == NULL)
+					goto error;
+
+				ret = os_snprintf(value, size, "\"%s\"",
+						  entry.str_value);
+				if (os_snprintf_error(size, ret))
+					goto error;
+			} else {
+				value = os_strdup(entry.str_value);
+				if (value == NULL)
+					goto error;
+			}
+		} else if (entry.type == DBUS_TYPE_UINT32) {
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+
+			ret = os_snprintf(value, size, "%u",
+					  entry.uint32_value);
+			if (os_snprintf_error(size, ret))
+				goto error;
+		} else if (entry.type == DBUS_TYPE_INT32) {
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+
+			ret = os_snprintf(value, size, "%d",
+					  entry.int32_value);
+			if (os_snprintf_error(size, ret))
+				goto error;
+		} else
+			goto error;
+
+		ret = wpa_config_set_cred(cred, entry.key, value, 0);
+		if (ret < 0)
+			goto error;
+
+		os_free(value);
+		value = NULL;
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	return TRUE;
+
+error:
+	os_free(value);
+	wpa_dbus_dict_entry_clear(&entry);
+	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+			     "invalid message format");
+	return FALSE;
+}
+
+
 /**
  * wpas_dbus_simple_property_getter - Get basic type property
  * @iter: Message iter to use when appending arguments
@@ -1514,6 +1621,127 @@ DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
 	return NULL;
 }
 
+/**
+ * wpas_dbus_new_iface_add_cred - Add a new set of credentials
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new credential
+ *
+ * Handler function for "AddCred" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter	iter;
+	struct wpa_cred *cred = NULL;
+	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+	DBusError error;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (wpa_s->dbus_new_path)
+		cred = wpa_config_add_cred(wpa_s->conf);
+	if (cred == NULL) {
+		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
+			   __func__);
+		reply = wpas_dbus_error_unknown_error(
+			message,
+			"wpa_supplicant could not add a credential on this interface.");
+		goto err;
+	}
+
+	dbus_error_init(&error);
+	if (!set_cred_properties(wpa_s, cred, &iter, &error)) {
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: control interface couldn't set credential properties",
+			   __func__);
+		reply = wpas_dbus_reply_new_from_error(message, &error,
+						       DBUS_ERROR_INVALID_ARGS,
+						       "Failed to add credential");
+		dbus_error_free(&error);
+		goto err;
+	}
+
+	/* Construct the object path for this network. */
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%d",
+		    wpa_s->dbus_new_path, cred->id);
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL) {
+		reply = wpas_dbus_error_no_memory(message);
+		goto err;
+	}
+	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+				      DBUS_TYPE_INVALID)) {
+		dbus_message_unref(reply);
+		reply = wpas_dbus_error_no_memory(message);
+		goto err;
+	}
+
+	return reply;
+
+err:
+	if (cred) {
+		wpa_config_remove_cred(wpa_s->conf, cred->id);
+	}
+	return reply;
+}
+
+/**
+ * wpas_dbus_handler_remove_cred - Remove a configured set of credentials
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveCred" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *op;
+	char *iface, *cred_id;
+	int id;
+	int result;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+			      DBUS_TYPE_INVALID);
+
+	/* Extract the network ID and ensure the network */
+	/* is actually a child of this interface */
+	iface = wpas_dbus_new_decompose_object_path(op,
+						    WPAS_DBUS_NEW_CREDENTIALS_PART,
+						    &cred_id);
+	if (iface == NULL || cred_id == NULL || !wpa_s->dbus_new_path ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	errno = 0;
+	id = strtoul(cred_id, NULL, 10);
+	if (errno != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	result = wpa_config_remove_cred(wpa_s->conf, id);
+	if (result == -1) {
+		wpa_printf(MSG_ERROR,
+			   "%s[dbus]: error occurred when removing cred %d",
+			   __func__, id);
+		reply = wpas_dbus_error_unknown_error(
+			message,
+			"error removing the specified credential on its interface.");
+		goto out;
+	}
+
+out:
+	os_free(iface);
+	return reply;
+}
 
 /**
  * wpas_dbus_handler_signal_poll - Request immediate signal properties
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index c36383f05..5b01ab527 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -144,6 +144,17 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
 					  struct wpa_supplicant *wpa_s);
 
+dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s,
+				struct wpa_cred *cred,
+				DBusMessageIter *iter,
+				DBusError *error);
+
+DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s);
+
 DECLARE_ACCESSOR(wpas_dbus_getter_capabilities);
 DECLARE_ACCESSOR(wpas_dbus_getter_state);
 DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
