Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > af1bd5b8834d29f2abe159c559eb6bea > files > 42

NetworkManager-0.7.0-10.el5_5.1.src.rpm

commit f3c9887472ef6d773aeabd0bb7fcf102cf725398
Author: Dan Williams <dcbw@redhat.com>
Date:   Sat May 9 22:34:35 2009 -0400

    wifi: handle WEP & WPA passphrases (bgo #513820) (rh #441070)
    
    Instead of requiring applets to hash passphrases, just do it in NM instead.
    This should fix confusion where people don't understand that they are seeing
    their hashed passphrase.

diff --git a/configure.in b/configure.in
index 1766c49..47a7f61 100644
--- a/configure.in
+++ b/configure.in
@@ -464,6 +464,7 @@ src/named-manager/Makefile
 src/vpn-manager/Makefile
 src/dhcp-manager/Makefile
 src/supplicant-manager/Makefile
+src/supplicant-manager/tests/Makefile
 src/ppp-manager/Makefile
 src/dnsmasq-manager/Makefile
 src/backends/Makefile
diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
index bc86e08..9fdc235 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -239,6 +239,7 @@ global:
 	nm_setting_wireless_security_get_psk;
 	nm_setting_wireless_security_get_type;
 	nm_setting_wireless_security_get_wep_key;
+	nm_setting_wireless_security_get_wep_key_type;
 	nm_setting_wireless_security_get_wep_tx_keyidx;
 	nm_setting_wireless_security_new;
 	nm_setting_wireless_security_remove_group;
diff --git a/libnm-util/nm-setting-wireless-security.c b/libnm-util/nm-setting-wireless-security.c
index e5304f7..926e3af 100644
--- a/libnm-util/nm-setting-wireless-security.c
+++ b/libnm-util/nm-setting-wireless-security.c
@@ -93,6 +93,7 @@ typedef struct {
 	char *wep_key3;
 	char *psk;
 	char *leap_password;
+	NMWepKeyType wep_key_type;
 } NMSettingWirelessSecurityPrivate;
 
 enum {
@@ -110,6 +111,7 @@ enum {
 	PROP_WEP_KEY3,
 	PROP_PSK,
 	PROP_LEAP_PASSWORD,
+	PROP_WEP_KEY_TYPE,
 
 	LAST_PROP
 };
@@ -425,8 +427,16 @@ nm_setting_wireless_security_get_auth_alg (NMSettingWirelessSecurity *setting)
 	return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->auth_alg;
 }
 
+NMWepKeyType
+nm_setting_wireless_security_get_wep_key_type (NMSettingWirelessSecurity *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (setting), 0);
+
+	return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting)->wep_key_type;
+}
+
 static gboolean
-verify_wep_key (const char *key)
+verify_wep_key (const char *key, NMWepKeyType wep_type)
 {
 	int keylen, i;
 
@@ -434,11 +444,24 @@ verify_wep_key (const char *key)
 		return FALSE;
 
 	keylen = strlen (key);
-	if (keylen != 10 && keylen != 26)
-		return FALSE;
+	if (wep_type == NM_WEP_KEY_TYPE_KEY || NM_WEP_KEY_TYPE_UNKNOWN) {
+		if (keylen == 10 || keylen == 26) {
+			/* Hex key */
+			for (i = 0; i < keylen; i++) {
+				if (!isxdigit (key[i]))
+					return FALSE;
+			}
+		} else if (keylen == 5 || keylen == 13) {
+			/* ASCII key */
+			for (i = 0; i < keylen; i++) {
+				if (!isascii (key[i]))
+					return FALSE;
+			}
+		} else
+			return FALSE;
 
-	for (i = 0; i < keylen; i++) {
-		if (!isxdigit (key[i]))
+	} else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
+		if (!keylen || keylen > 64)
 			return FALSE;
 	}
 
@@ -454,12 +477,15 @@ verify_wpa_psk (const char *psk)
 		return FALSE;
 
 	psklen = strlen (psk);
-	if (psklen != 64)
+	if (psklen < 8 || psklen > 64)
 		return FALSE;
 
-	for (i = 0; i < psklen; i++) {
-		if (!isxdigit (psk[i]))
-			return FALSE;
+	if (psklen == 64) {
+		/* Hex PSK */
+		for (i = 0; i < psklen; i++) {
+			if (!isxdigit (psk[i]))
+				return FALSE;
+		}
 	}
 
 	return TRUE;
@@ -483,19 +509,19 @@ need_secrets (NMSetting *setting)
 
 	/* Static WEP */
 	if (strcmp (priv->key_mgmt, "none") == 0) {
-		if ((priv->wep_tx_keyidx == 0) && !verify_wep_key (priv->wep_key0)) {
+		if ((priv->wep_tx_keyidx == 0) && !verify_wep_key (priv->wep_key0, priv->wep_key_type)) {
 			g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
 			return secrets;
 		}
-		if ((priv->wep_tx_keyidx == 1) && !verify_wep_key (priv->wep_key1)) {
+		if ((priv->wep_tx_keyidx == 1) && !verify_wep_key (priv->wep_key1, priv->wep_key_type)) {
 			g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1);
 			return secrets;
 		}
-		if ((priv->wep_tx_keyidx == 2) && !verify_wep_key (priv->wep_key2)) {
+		if ((priv->wep_tx_keyidx == 2) && !verify_wep_key (priv->wep_key2, priv->wep_key_type)) {
 			g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2);
 			return secrets;
 		}
-		if ((priv->wep_tx_keyidx == 3) && !verify_wep_key (priv->wep_key3)) {
+		if ((priv->wep_tx_keyidx == 3) && !verify_wep_key (priv->wep_key3, priv->wep_key_type)) {
 			g_ptr_array_add (secrets, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3);
 			return secrets;
 		}
@@ -627,28 +653,36 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
 		return FALSE;
 	}
 
-	if (priv->wep_key0 && !strlen (priv->wep_key0)) {
+	if (priv->wep_key_type > NM_WEP_KEY_TYPE_LAST) {
+		g_set_error (error,
+		             NM_SETTING_WIRELESS_SECURITY_ERROR,
+		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
+		             NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE);
+		return FALSE;
+	}
+
+	if (priv->wep_key0 && !verify_wep_key (priv->wep_key0, priv->wep_key_type)) {
 		g_set_error (error,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
 		             NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
 		return FALSE;
 	}
-	if (priv->wep_key1 && !strlen (priv->wep_key1)) {
+	if (priv->wep_key1 && !verify_wep_key (priv->wep_key1, priv->wep_key_type)) {
 		g_set_error (error,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
 		             NM_SETTING_WIRELESS_SECURITY_WEP_KEY1);
 		return FALSE;
 	}
-	if (priv->wep_key2 && !strlen (priv->wep_key2)) {
+	if (priv->wep_key2 && !verify_wep_key (priv->wep_key2, priv->wep_key_type)) {
 		g_set_error (error,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
 		             NM_SETTING_WIRELESS_SECURITY_WEP_KEY2);
 		return FALSE;
 	}
-	if (priv->wep_key3 && !strlen (priv->wep_key3)) {
+	if (priv->wep_key3 && !verify_wep_key (priv->wep_key3, priv->wep_key_type)) {
 		g_set_error (error,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR,
 		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
@@ -825,6 +859,9 @@ set_property (GObject *object, guint prop_id,
 		g_free (priv->leap_password);
 		priv->leap_password = g_value_dup_string (value);
 		break;
+	case PROP_WEP_KEY_TYPE:
+		priv->wep_key_type = g_value_get_uint (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -878,6 +915,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_LEAP_PASSWORD:
 		g_value_set_string (value, priv->leap_password);
 		break;
+	case PROP_WEP_KEY_TYPE:
+		g_value_set_uint (value, priv->wep_key_type);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1004,4 +1044,14 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *setting
 						  "LEAP Password",
 						  NULL,
 						  G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
+
+	g_object_class_install_property
+		(object_class, PROP_WEP_KEY_TYPE,
+		 g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
+						"WEP Key Type",
+						"WEP Key Type",
+						NM_WEP_KEY_TYPE_UNKNOWN,
+						NM_WEP_KEY_TYPE_LAST,
+						NM_WEP_KEY_TYPE_UNKNOWN,
+						G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE));
 }
diff --git a/libnm-util/nm-setting-wireless-security.h b/libnm-util/nm-setting-wireless-security.h
index d72c9bf..772a2d6 100644
--- a/libnm-util/nm-setting-wireless-security.h
+++ b/libnm-util/nm-setting-wireless-security.h
@@ -56,6 +56,14 @@ GType nm_setting_wireless_security_error_get_type (void);
 #define NM_SETTING_WIRELESS_SECURITY_ERROR nm_setting_wireless_security_error_quark ()
 GQuark nm_setting_wireless_security_error_quark (void);
 
+typedef enum {
+	NM_WEP_KEY_TYPE_UNKNOWN = 0,
+	NM_WEP_KEY_TYPE_KEY = 1,          /* Hex or ASCII */
+	NM_WEP_KEY_TYPE_PASSPHRASE = 2,   /* 104/128-bit Passphrase */
+
+	NM_WEP_KEY_TYPE_LAST = NM_WEP_KEY_TYPE_PASSPHRASE
+} NMWepKeyType;
+
 #define NM_SETTING_WIRELESS_SECURITY_KEY_MGMT "key-mgmt"
 #define NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX "wep-tx-keyidx"
 #define NM_SETTING_WIRELESS_SECURITY_AUTH_ALG "auth-alg"
@@ -69,6 +77,7 @@ GQuark nm_setting_wireless_security_error_quark (void);
 #define NM_SETTING_WIRELESS_SECURITY_WEP_KEY3 "wep-key3"
 #define NM_SETTING_WIRELESS_SECURITY_PSK "psk"
 #define NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD "leap-password"
+#define NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE "wep-key-type"
 
 typedef struct {
 	NMSetting parent;
@@ -111,6 +120,7 @@ const char *nm_setting_wireless_security_get_wep_key       (NMSettingWirelessSec
 void        nm_setting_wireless_security_set_wep_key       (NMSettingWirelessSecurity *setting, guint32 idx, const char *key);
 guint32     nm_setting_wireless_security_get_wep_tx_keyidx (NMSettingWirelessSecurity *setting);
 const char *nm_setting_wireless_security_get_auth_alg      (NMSettingWirelessSecurity *setting);
+NMWepKeyType nm_setting_wireless_security_get_wep_key_type (NMSettingWirelessSecurity *setting);
 
 G_END_DECLS
 
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 519e57d..26a4010 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -182,61 +182,6 @@ nm_utils_ip4_prefix_to_netmask (guint32 prefix)
 	return (guint32) htonl (netmask);
 }
 
-
-/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
-
-static int hex2num (char c)
-{
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	if (c >= 'A' && c <= 'F')
-		return c - 'A' + 10;
-	return -1;
-}
-
-static int hex2byte (const char *hex)
-{
-	int a, b;
-	a = hex2num(*hex++);
-	if (a < 0)
-		return -1;
-	b = hex2num(*hex++);
-	if (b < 0)
-		return -1;
-	return (a << 4) | b;
-}
-
-char *
-nm_utils_hexstr2bin (const char *hex,
-                     size_t len)
-{
-	size_t       i;
-	int          a;
-	const char * ipos = hex;
-	char *       buf = NULL;
-	char *       opos;
-
-	/* Length must be a multiple of 2 */
-	if ((len % 2) != 0)
-		return NULL;
-
-	opos = buf = g_malloc0 ((len / 2) + 1);
-	for (i = 0; i < len; i += 2) {
-		a = hex2byte (ipos);
-		if (a < 0) {
-			g_free (buf);
-			return NULL;
-		}
-		*opos++ = a;
-		ipos += 2;
-	}
-	return buf;
-}
-
-/* End from hostap */
-
 char *
 nm_ether_ntop (const struct ether_addr *mac)
 {
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 147a972..c412c46 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -37,8 +37,6 @@ int nm_spawn_process (const char *args);
 
 struct nl_addr *nm_utils_ip4_addr_to_nl_addr (guint32 ip4_addr);
 
-char *nm_utils_hexstr2bin (const char *hex, size_t len);
-
 char *nm_ether_ntop (const struct ether_addr *mac);
 
 void nm_utils_merge_ip4_config (NMIP4Config *ip4_config, NMSettingIP4Config *setting);
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 2d6e023..7806c91 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -2803,10 +2803,8 @@ build_supplicant_config (NMDeviceWifi *self,
 			goto error;
 		}
 	} else {
-		/* Unencrypted, wpa_supplicant needs key_mgmt=NONE here */
-		if (!nm_supplicant_config_add_option (config, "key_mgmt", "NONE", -1, FALSE)) {
-			nm_warning ("Couldn't add 802-11-wireless (no security) setting to"
-			            " supplicant config.");
+		if (!nm_supplicant_config_add_no_security (config)) {
+			nm_warning ("Couldn't add unsecured option to supplicant config.");
 			goto error;
 		}
 	}
diff --git a/src/supplicant-manager/Makefile.am b/src/supplicant-manager/Makefile.am
index df27d5c..d613e83 100644
--- a/src/supplicant-manager/Makefile.am
+++ b/src/supplicant-manager/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS=. tests
+
 INCLUDES = \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/include \
@@ -16,7 +18,9 @@ libsupplicant_manager_la_SOURCES = \
 	nm-supplicant-interface.c \
 	nm-supplicant-interface.h \
 	nm-supplicant-settings-verify.h \
-	nm-supplicant-settings-verify.c
+	nm-supplicant-settings-verify.c \
+	gnome-keyring-md5.h \
+	gnome-keyring-md5.c
 
 libsupplicant_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
diff --git a/src/supplicant-manager/gnome-keyring-md5.c b/src/supplicant-manager/gnome-keyring-md5.c
new file mode 100644
index 0000000..0a3dd71
--- /dev/null
+++ b/src/supplicant-manager/gnome-keyring-md5.c
@@ -0,0 +1,291 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * GnomeKeyringMD5Context structure, pass it to gnome_keyring_md5_init, call
+ * gnome_keyring_md5_update as needed on buffers full of bytes, and then call
+ * gnome_keyring_md5_final, which will fill a supplied 32-byte array with the
+ * digest in ascii form. 
+ *
+ */
+
+#include "gnome-keyring-md5.h"
+#include <string.h>
+
+static void gnome_keyring_md5_transform (guint32                 buf[4],
+					 guint32 const           in[16]);
+
+void
+gnome_keyring_md5_string (const char *string, unsigned char digest[16])
+{
+  struct GnomeKeyringMD5Context md5_context;
+  
+  gnome_keyring_md5_init (&md5_context);
+  gnome_keyring_md5_update (&md5_context, (const unsigned char *)string, strlen (string));
+  gnome_keyring_md5_final (digest, &md5_context);
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define byteReverse(buf, len)	/* Nothing */
+#else
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void
+byteReverse(unsigned char *buf, unsigned longs)
+{
+    guint32 t;
+    do {
+	t = (guint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+	    ((unsigned) buf[1] << 8 | buf[0]);
+	*(guint32 *) buf = t;
+	buf += 4;
+    } while (--longs);
+}
+
+#endif
+
+char *
+gnome_keyring_md5_digest_to_ascii (unsigned char digest[16])
+{
+  static char hex_digits[] = "0123456789abcdef";
+  char *res;
+  int i;
+  
+  res = g_malloc (33);
+  
+  for (i = 0; i < 16; i++) {
+    res[2*i] = hex_digits[digest[i] >> 4];
+    res[2*i+1] = hex_digits[digest[i] & 0xf];
+  }
+  
+  res[32] = 0;
+  
+  return res;
+}
+
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void 
+gnome_keyring_md5_init (struct GnomeKeyringMD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void 
+gnome_keyring_md5_update (struct GnomeKeyringMD5Context *ctx,
+			  unsigned char const *buf,
+			  unsigned len)
+{
+    guint32 t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((guint32) len << 3)) < t)
+	ctx->bits[1]++;		/* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+	unsigned char *p = (unsigned char *) ctx->in + t;
+
+	t = 64 - t;
+	if (len < t) {
+	    memcpy (p, buf, len);
+	    return;
+	}
+	memcpy (p, buf, t);
+	byteReverse (ctx->in, 16);
+	gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in);
+	buf += t;
+	len -= t;
+    }
+
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+	memcpy (ctx->in, buf, 64);
+	byteReverse (ctx->in, 16);
+	gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in);
+	buf += 64;
+	len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void 
+gnome_keyring_md5_final (unsigned char digest[16], struct GnomeKeyringMD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+	/* Two lots of padding:  Pad the first block to 64 bytes */
+	memset (p, 0, count);
+	byteReverse (ctx->in, 16);
+	gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in);
+
+	/* Now fill the next block with 56 bytes */
+	memset(ctx->in, 0, 56);
+    } else {
+	/* Pad block to 56 bytes */
+	memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((guint32 *) ctx->in)[14] = ctx->bits[0];
+    ((guint32 *) ctx->in)[15] = ctx->bits[1];
+
+    gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in);
+    byteReverse ((unsigned char *) ctx->buf, 4);
+    memcpy (digest, ctx->buf, 16);
+    memset (ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1 (z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define gnome_keyring_md5_step(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  GnomeKeyringMD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void 
+gnome_keyring_md5_transform (guint32 buf[4], guint32 const in[16])
+{
+    register guint32 a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    gnome_keyring_md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    gnome_keyring_md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    gnome_keyring_md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    gnome_keyring_md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    gnome_keyring_md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    gnome_keyring_md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    gnome_keyring_md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    gnome_keyring_md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    gnome_keyring_md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    gnome_keyring_md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    gnome_keyring_md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    gnome_keyring_md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    gnome_keyring_md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    gnome_keyring_md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    gnome_keyring_md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    gnome_keyring_md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+		
+    gnome_keyring_md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    gnome_keyring_md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    gnome_keyring_md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    gnome_keyring_md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    gnome_keyring_md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    gnome_keyring_md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    gnome_keyring_md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    gnome_keyring_md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    gnome_keyring_md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    gnome_keyring_md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    gnome_keyring_md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    gnome_keyring_md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    gnome_keyring_md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    gnome_keyring_md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    gnome_keyring_md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    gnome_keyring_md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+		
+    gnome_keyring_md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    gnome_keyring_md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    gnome_keyring_md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    gnome_keyring_md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    gnome_keyring_md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    gnome_keyring_md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    gnome_keyring_md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    gnome_keyring_md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    gnome_keyring_md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    gnome_keyring_md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    gnome_keyring_md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    gnome_keyring_md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    gnome_keyring_md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    gnome_keyring_md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    gnome_keyring_md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    gnome_keyring_md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+		
+    gnome_keyring_md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    gnome_keyring_md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    gnome_keyring_md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    gnome_keyring_md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    gnome_keyring_md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    gnome_keyring_md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    gnome_keyring_md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    gnome_keyring_md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    gnome_keyring_md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    gnome_keyring_md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    gnome_keyring_md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    gnome_keyring_md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    gnome_keyring_md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    gnome_keyring_md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    gnome_keyring_md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    gnome_keyring_md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+
diff --git a/src/supplicant-manager/gnome-keyring-md5.h b/src/supplicant-manager/gnome-keyring-md5.h
new file mode 100644
index 0000000..3dff998
--- /dev/null
+++ b/src/supplicant-manager/gnome-keyring-md5.h
@@ -0,0 +1,41 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * GnomeKeyringMD5Context structure, pass it to gnome_keyring_md5_init, call
+ * gnome_keyring_md5_update as needed on buffers full of bytes, and then call
+ * gnome_keyring_md5_final, which will fill a supplied 32-byte array with the
+ * digest in ascii form. 
+ *
+ */
+
+#ifndef GNOME_KEYRING_MD5_H
+#define GNOME_KEYRING_MD5_H
+
+#include <glib.h>
+
+struct GnomeKeyringMD5Context {
+	guint32 buf[4];
+	guint32 bits[2];
+	unsigned char in[64];
+};
+
+char *gnome_keyring_md5_digest_to_ascii (unsigned char                  digest[16]);
+void  gnome_keyring_md5_string          (const char                    *string,
+					 unsigned char                  digest[16]);
+void  gnome_keyring_md5_init            (struct GnomeKeyringMD5Context *ctx);
+void  gnome_keyring_md5_update          (struct GnomeKeyringMD5Context *ctx,
+					 unsigned char const           *buf,
+					 unsigned                       len);
+void  gnome_keyring_md5_final           (unsigned char                  digest[16],
+					 struct GnomeKeyringMD5Context *ctx);
+
+#endif /* GNOME_KEYRING_MD5_H */
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index e2208ec..4fb6a1e 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -35,6 +35,10 @@
 #include "nm-setting.h"
 #include "NetworkManagerUtils.h"
 
+#include "gnome-keyring-md5.h"
+
+static char *hexstr2bin (const char *hex, size_t len);
+
 #define NM_SUPPLICANT_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                              NM_TYPE_SUPPLICANT_CONFIG, \
                                              NMSupplicantConfigPrivate))
@@ -44,7 +48,7 @@ G_DEFINE_TYPE (NMSupplicantConfig, nm_supplicant_config, G_TYPE_OBJECT)
 typedef struct {
 	char *value;
 	guint32 len;	
-	enum OptType type;
+	OptType type;
 } ConfigOption;
 
 typedef struct
@@ -80,8 +84,8 @@ nm_supplicant_config_init (NMSupplicantConfig * self)
 	NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
 	priv->config = g_hash_table_new_full (g_str_hash, g_str_equal,
-										  (GDestroyNotify) g_free,
-										  (GDestroyNotify) config_option_free);
+	                                      (GDestroyNotify) g_free,
+	                                      (GDestroyNotify) config_option_free);
 
 	priv->blobs = g_hash_table_new_full (g_str_hash, g_str_equal,
 	                                     (GDestroyNotify) g_free,
@@ -91,12 +95,13 @@ nm_supplicant_config_init (NMSupplicantConfig * self)
 	priv->dispose_has_run = FALSE;
 }
 
-gboolean
-nm_supplicant_config_add_option (NMSupplicantConfig *self,
-                                 const char * key,
-                                 const char * value,
-                                 gint32 len,
-                                 gboolean secret)
+static gboolean
+nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self,
+                                           const char *key,
+                                           const char *value,
+                                           gint32 len,
+                                           OptType opt_type,
+                                           gboolean secret)
 {
 	NMSupplicantConfigPrivate *priv;
 	ConfigOption *old_opt;
@@ -112,13 +117,17 @@ nm_supplicant_config_add_option (NMSupplicantConfig *self,
 	if (len < 0)
 		len = strlen (value);
 
-	type = nm_supplicant_settings_verify_setting (key, value, len);
-	if (type == TYPE_INVALID) {
-		char buf[255];
-		memset (&buf[0], 0, sizeof (buf));
-		memcpy (&buf[0], value, len > 254 ? 254 : len);
-		nm_debug ("Key '%s' and/or value '%s' invalid.", key, buf);
-		return FALSE;
+	if (opt_type != TYPE_INVALID)
+		type = opt_type;
+	else {
+		type = nm_supplicant_settings_verify_setting (key, value, len);
+		if (type == TYPE_INVALID) {
+			char buf[255];
+			memset (&buf[0], 0, sizeof (buf));
+			memcpy (&buf[0], value, len > 254 ? 254 : len);
+			nm_debug ("Key '%s' and/or value '%s' invalid.", key, buf);
+			return FALSE;
+		}
 	}
 
 	old_opt = (ConfigOption *) g_hash_table_lookup (priv->config, key);
@@ -155,6 +164,15 @@ nm_info ("Config: added '%s' value '%s'", key, secret ? "<omitted>" : &buf[0]);
 	return TRUE;
 }
 
+static gboolean
+nm_supplicant_config_add_option (NMSupplicantConfig *self,
+                                 const char *key,
+                                 const char *value,
+                                 gint32 len,
+                                 gboolean secret)
+{
+	return nm_supplicant_config_add_option_with_type (self, key, value, len, TYPE_INVALID, secret);
+}
 
 static gboolean
 nm_supplicant_config_add_blob (NMSupplicantConfig *self,
@@ -283,6 +301,7 @@ get_hash_cb (gpointer key, gpointer value, gpointer user_data)
 		g_byte_array_free (array, TRUE);
 		break;
 	case TYPE_KEYWORD:
+	case TYPE_STRING:
 		g_value_init (variant, G_TYPE_STRING);
 		g_value_set_string (variant, opt->value);
 		break;
@@ -306,17 +325,17 @@ destroy_hash_value (gpointer data)
 GHashTable *
 nm_supplicant_config_get_hash (NMSupplicantConfig * self)
 {
+	NMSupplicantConfigPrivate *priv;
 	GHashTable *hash;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), NULL);
 
 	hash = g_hash_table_new_full (g_str_hash, g_str_equal,
-								  (GDestroyNotify) g_free,
-								  destroy_hash_value);
-
-	g_hash_table_foreach (NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->config,
-						  get_hash_cb, hash);
+	                              (GDestroyNotify) g_free,
+	                              destroy_hash_value);
 
+	priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
+	g_hash_table_foreach (priv->config, get_hash_cb, hash);
 	return hash;
 }
 
@@ -412,23 +431,26 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 	return TRUE;
 }
 
-#define ADD_STRING_VAL(field, name, ucase, unhexify, secret) \
-	if (field) { \
-		int len = -1; \
-		if (ucase) \
-			value = g_ascii_strup (field, -1); \
-		else if (unhexify) { \
-			value = nm_utils_hexstr2bin (field, strlen (field)); \
-			len = strlen (field) / 2; \
-		} else \
-			value = g_strdup (field); \
-		success = nm_supplicant_config_add_option (self, name, value, len, secret); \
-		g_free (value); \
-		if (!success) { \
-			nm_warning ("Error adding %s to supplicant config.", name); \
-			return FALSE; \
-		} \
-	}
+static gboolean
+add_string_val (NMSupplicantConfig *self,
+                const char *field,
+                const char *name,
+                gboolean ucase,
+                gboolean secret)
+{
+	gboolean success;
+	char *value;
+
+	if (!field)
+		return TRUE;
+
+	value = ucase ? g_ascii_strup (field, -1) : g_strdup (field);
+	success = nm_supplicant_config_add_option (self, name, value, strlen (field), secret);
+	if (!success)
+		nm_warning ("Error adding %s to supplicant config.", name);
+	g_free (value);
+	return success;
+}
 
 #define ADD_STRING_LIST_VAL(setting, setting_name, field, field_plural, name, ucase, secret) \
 	if (nm_setting_##setting_name##_get_num_##field_plural (setting)) { \
@@ -444,7 +466,7 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
 			} \
 		} \
 		if (ucase) \
-		  g_string_ascii_up (str); \
+			g_string_ascii_up (str); \
 		if (str->len) \
 			success = nm_supplicant_config_add_option (self, name, str->str, -1, secret); \
 		else \
@@ -479,6 +501,75 @@ get_blob_id (const char *name, const char *seed_uid)
 		} \
 	}
 
+
+static unsigned char *
+wep128_passphrase_hash (const char *input, size_t input_len, size_t *out_len)
+{
+	char md5_data[65];
+	unsigned char *digest;
+	int i;
+
+	*out_len = 16;
+	digest = g_malloc0 (*out_len);
+
+	/* Get at least 64 bytes */
+	for (i = 0; i < 64; i++)
+		md5_data[i] = input[i % input_len];
+
+	/* Null terminate md5 seed data and hash it */
+	md5_data[64] = 0;
+	gnome_keyring_md5_string (md5_data, digest);
+	return digest;
+}
+
+static gboolean
+add_wep_key (NMSupplicantConfig *self,
+             const char *key,
+             const char *name,
+             NMWepKeyType wep_type)
+{
+	char *value;
+	gboolean success;
+	size_t key_len = key ? strlen (key) : 0;
+
+	if (!key || !key_len)
+		return TRUE;
+
+	if (   (wep_type == NM_WEP_KEY_TYPE_UNKNOWN)
+	    || (wep_type == NM_WEP_KEY_TYPE_KEY)) {
+		if ((key_len == 10) || (key_len == 26)) {
+			value = hexstr2bin (key, strlen (key));
+			success = nm_supplicant_config_add_option (self, name, value, key_len / 2, TRUE);
+			g_free (value);
+			if (!success) {
+				nm_warning ("Error adding %s to supplicant config.", name);
+				return FALSE;
+			}
+		} else if ((key_len == 5) || (key_len == 13)) {
+			if (!nm_supplicant_config_add_option (self, name, key, key_len, TRUE)) {
+				nm_warning ("Error adding %s to supplicant config.", name);
+				return FALSE;
+			}
+		} else {
+			nm_warning ("Invalid WEP key '%s'", name);
+			return FALSE;
+		}
+	} else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
+		char *digest;
+		size_t digest_len;
+
+		digest = (char *) wep128_passphrase_hash (key, key_len, &digest_len);
+		success = nm_supplicant_config_add_option (self, name, digest, 13, TRUE);
+		g_free (digest);
+		if (!success) {
+			nm_warning ("Error adding %s to supplicant config.", name);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
 gboolean
 nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                     NMSettingWirelessSecurity *setting,
@@ -489,6 +580,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 	char *value;
 	gboolean success;
 	const char *key_mgmt, *auth_alg;
+	const char *psk;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
@@ -497,12 +589,42 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 	priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
 	key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting);
-	ADD_STRING_VAL (key_mgmt, "key_mgmt", TRUE, FALSE, FALSE);
+	if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE))
+		return FALSE;
 
 	auth_alg = nm_setting_wireless_security_get_auth_alg (setting);
-	ADD_STRING_VAL (auth_alg, "auth_alg", TRUE, FALSE, FALSE);
+	if (!add_string_val (self, auth_alg, "auth_alg", TRUE, FALSE))
+		return FALSE;
+
+	psk = nm_setting_wireless_security_get_psk (setting);
+	if (psk) {
+		size_t psk_len = strlen (psk);
 
-	ADD_STRING_VAL (nm_setting_wireless_security_get_psk (setting), "psk", FALSE, TRUE, TRUE);
+		if (psk_len == 64) {
+			/* Hex PSK */
+			value = hexstr2bin (psk, psk_len);
+			success = nm_supplicant_config_add_option (self, "psk", value, psk_len / 2, TRUE);
+			g_free (value);
+			if (!success) {
+				nm_warning ("Error adding 'psk' to supplicant config.");
+				return FALSE;
+			}
+		} else if (psk_len >= 8 && psk_len < 63) {
+			/* Use TYPE_STRING here so that it gets pushed to the
+			 * supplicant as a string, and therefore gets quoted,
+			 * and therefore the supplicant will interpret it as a
+			 * passphrase and not a hex key.
+			 */
+			if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, TRUE)) {
+				nm_warning ("Error adding 'psk' to supplicant config.");
+				return FALSE;
+			}
+		} else {
+			/* Invalid PSK */
+			nm_warning ("Invalid PSK length %d: not between 8 and 63 characters inclusive.", psk_len);
+			return FALSE;
+		}
+	}
 
 	/* Only WPA-specific things when using WPA */
 	if (   !strcmp (key_mgmt, "wpa-none")
@@ -515,15 +637,20 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 
 	/* WEP keys if required */
 	if (!strcmp (key_mgmt, "none")) {
+		NMWepKeyType wep_type = nm_setting_wireless_security_get_wep_key_type (setting);
 		const char *wep0 = nm_setting_wireless_security_get_wep_key (setting, 0);
 		const char *wep1 = nm_setting_wireless_security_get_wep_key (setting, 1);
 		const char *wep2 = nm_setting_wireless_security_get_wep_key (setting, 2);
 		const char *wep3 = nm_setting_wireless_security_get_wep_key (setting, 3);
 
-		ADD_STRING_VAL (wep0, "wep_key0", FALSE, TRUE, TRUE);
-		ADD_STRING_VAL (wep1, "wep_key1", FALSE, TRUE, TRUE);
-		ADD_STRING_VAL (wep2, "wep_key2", FALSE, TRUE, TRUE);
-		ADD_STRING_VAL (wep3, "wep_key3", FALSE, TRUE, TRUE);
+		if (!add_wep_key (self, wep0, "wep_key0", wep_type))
+			return FALSE;
+		if (!add_wep_key (self, wep1, "wep_key1", wep_type))
+			return FALSE;
+		if (!add_wep_key (self, wep2, "wep_key2", wep_type))
+			return FALSE;
+		if (!add_wep_key (self, wep3, "wep_key3", wep_type))
+			return FALSE;
 
 		if (wep0 || wep1 || wep2 || wep3) {
 			value = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (setting));
@@ -539,9 +666,18 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 	if (auth_alg && !strcmp (auth_alg, "leap")) {
 		/* LEAP */
 		if (!strcmp (key_mgmt, "ieee8021x")) {
-			ADD_STRING_VAL (nm_setting_wireless_security_get_leap_username (setting), "identity", FALSE, FALSE, FALSE);
-			ADD_STRING_VAL (nm_setting_wireless_security_get_leap_password (setting), "password", FALSE, FALSE, TRUE);
-			ADD_STRING_VAL ("leap", "eap", TRUE, FALSE, FALSE);
+			const char *tmp;
+
+			tmp = nm_setting_wireless_security_get_leap_username (setting);
+			if (!add_string_val (self, tmp, "identity", FALSE, FALSE))
+				return FALSE;
+
+			tmp = nm_setting_wireless_security_get_leap_password (setting);
+			if (!add_string_val (self, tmp, "password", FALSE, TRUE))
+				return FALSE;
+
+			if (!add_string_val (self, "leap", "eap", TRUE, FALSE))
+				return FALSE;
 		} else {
 			return FALSE;
 		}
@@ -565,7 +701,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                         gboolean wired)
 {
 	NMSupplicantConfigPrivate *priv;
-	char *value, *tmp;
+	char *tmp;
+	const char *value;
 	gboolean success;
 	GString *phase1, *phase2;
 	const GByteArray *array;
@@ -577,13 +713,19 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 
 	priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
-	ADD_STRING_VAL (nm_setting_802_1x_get_password (setting), "password", FALSE, FALSE, TRUE);
-	ADD_STRING_VAL (nm_setting_802_1x_get_pin (setting), "pin", FALSE, FALSE, TRUE);
+	value = nm_setting_802_1x_get_password (setting);
+	if (!add_string_val (self, value, "password", FALSE, TRUE))
+		return FALSE;
+	value = nm_setting_802_1x_get_pin (setting);
+	if (!add_string_val (self, value, "pin", FALSE, TRUE))
+		return FALSE;
 
 	if (wired) {
-		ADD_STRING_VAL ("IEEE8021X", "key_mgmt", TRUE, FALSE, FALSE);
+		if (!add_string_val (self, "IEEE8021X", "key_mgmt", FALSE, FALSE))
+			return FALSE;
 		/* Wired 802.1x must always use eapol_flags=0 */
-		ADD_STRING_VAL ("0", "eapol_flags", FALSE, FALSE, FALSE);
+		if (!add_string_val (self, "0", "eapol_flags", FALSE, FALSE))
+			return FALSE;
 	}
 
 	ADD_STRING_LIST_VAL (setting, 802_1x, eap_method, eap_methods, "eap", TRUE, FALSE);
@@ -607,8 +749,12 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		g_string_append_printf (phase1, "peaplabel=%s", nm_setting_802_1x_get_phase1_peaplabel (setting));
 	}
 
-	if (phase1->len)
-		ADD_STRING_VAL (phase1->str, "phase1", FALSE, FALSE, FALSE);
+	if (phase1->len) {
+		if (!add_string_val (self, phase1->str, "phase1", FALSE, FALSE)) {
+			g_string_free (phase1, TRUE);
+			return FALSE;
+		}
+	}
 	g_string_free (phase1, TRUE);
 
 	phase2 = g_string_new (NULL);
@@ -626,12 +772,17 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		g_free (tmp);
 	}
 
-	if (phase2->len)
-		ADD_STRING_VAL (phase2->str, "phase2", FALSE, FALSE, FALSE);
+	if (phase2->len) {
+		if (!add_string_val (self, phase2->str, "phase2", FALSE, FALSE)) {
+			g_string_free (phase2, TRUE);
+			return FALSE;
+		}
+	}
 	g_string_free (phase2, TRUE);
 
 	if (nm_setting_802_1x_get_system_ca_certs (setting)) {
-		ADD_STRING_VAL (SYSTEM_CA_PATH, "ca_path", FALSE, FALSE, FALSE);
+		if (!add_string_val (self, SYSTEM_CA_PATH, "ca_path", FALSE, FALSE))
+			return FALSE;
 	} else {
 		ADD_BLOB_VAL (nm_setting_802_1x_get_ca_cert (setting), "ca_cert", connection_uid);
 	}
@@ -643,7 +794,9 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		switch (nm_setting_802_1x_get_private_key_type (setting)) {
 		case NM_SETTING_802_1X_CK_TYPE_PKCS12:
 			/* Only add the private key password for PKCS#12 keys */
-			ADD_STRING_VAL (nm_setting_802_1x_get_private_key_password (setting), "private_key_passwd", FALSE, FALSE, TRUE);
+			value = nm_setting_802_1x_get_private_key_password (setting);
+			if (!add_string_val (self, value, "private_key_passwd", FALSE, TRUE))
+				return FALSE;
 			break;
 		default:
 			/* Only add the client cert if the private key is not PKCS#12 */
@@ -653,7 +806,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	}
 
 	if (nm_setting_802_1x_get_system_ca_certs (setting)) {
-		ADD_STRING_VAL (SYSTEM_CA_PATH, "ca_path2", FALSE, FALSE, FALSE);
+		if (!add_string_val (self, SYSTEM_CA_PATH, "ca_path2", FALSE, FALSE))
+			return FALSE;
 	} else {
 		ADD_BLOB_VAL (nm_setting_802_1x_get_phase2_ca_cert (setting), "ca_cert2", connection_uid);
 	}
@@ -665,7 +819,9 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		switch (nm_setting_802_1x_get_phase2_private_key_type (setting)) {
 		case NM_SETTING_802_1X_CK_TYPE_PKCS12:
 			/* Only add the private key password for PKCS#12 keys */
-			ADD_STRING_VAL (nm_setting_802_1x_get_phase2_private_key_password (setting), "private_key2_passwd", FALSE, FALSE, TRUE);
+			value = nm_setting_802_1x_get_phase2_private_key_password (setting);
+			if (!add_string_val (self, value, "private_key2_passwd", FALSE, TRUE))
+				return FALSE;
 			break;
 		default:
 			/* Only add the client cert if the private key is not PKCS#12 */
@@ -674,9 +830,72 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		}
 	}
 
-	ADD_STRING_VAL (nm_setting_802_1x_get_identity (setting), "identity", FALSE, FALSE, FALSE);
-	ADD_STRING_VAL (nm_setting_802_1x_get_anonymous_identity (setting), "anonymous_identity", FALSE, FALSE, FALSE);
+	value = nm_setting_802_1x_get_identity (setting);
+	if (!add_string_val (self, value, "identity", FALSE, FALSE))
+		return FALSE;
+	value = nm_setting_802_1x_get_anonymous_identity (setting);
+	if (!add_string_val (self, value, "anonymous_identity", FALSE, FALSE))
+		return FALSE;
 
 	return TRUE;
 }
 
+gboolean
+nm_supplicant_config_add_no_security (NMSupplicantConfig *self)
+{
+	return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, FALSE);
+}
+
+/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
+
+static int hex2num (char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+static int hex2byte (const char *hex)
+{
+	int a, b;
+	a = hex2num(*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num(*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+static char *
+hexstr2bin (const char *hex, size_t len)
+{
+	size_t       i;
+	int          a;
+	const char * ipos = hex;
+	char *       buf = NULL;
+	char *       opos;
+
+	/* Length must be a multiple of 2 */
+	if ((len % 2) != 0)
+		return NULL;
+
+	opos = buf = g_malloc0 ((len / 2) + 1);
+	for (i = 0; i < len; i += 2) {
+		a = hex2byte (ipos);
+		if (a < 0) {
+			g_free (buf);
+			return NULL;
+		}
+		*opos++ = a;
+		ipos += 2;
+	}
+	return buf;
+}
+
+/* End from hostap */
+
diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h
index 9fc8d71..dad23e2 100644
--- a/src/supplicant-manager/nm-supplicant-config.h
+++ b/src/supplicant-manager/nm-supplicant-config.h
@@ -50,25 +50,19 @@ typedef struct
 
 GType nm_supplicant_config_get_type (void);
 
-NMSupplicantConfig * nm_supplicant_config_new (void);
+NMSupplicantConfig *nm_supplicant_config_new (void);
 
-guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig * self);
+guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self);
 
-void nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self,
+void nm_supplicant_config_set_ap_scan (NMSupplicantConfig *self,
                                        guint32 ap_scan);
 
-gboolean nm_supplicant_config_add_option (NMSupplicantConfig *self,
-                                          const char * key,
-                                          const char * value,
-                                          gint32 len,
-                                          gboolean secret);
+GHashTable *nm_supplicant_config_get_hash (NMSupplicantConfig *self);
 
-GHashTable *nm_supplicant_config_get_hash (NMSupplicantConfig * self);
+GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig *self);
 
-GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig * self);
-
-gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
-                                                    NMSettingWireless * setting,
+gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self,
+                                                    NMSettingWireless *setting,
                                                     gboolean is_broadcast,
                                                     guint32 adhoc_freq,
                                                     gboolean has_scan_capa_ssid,
@@ -78,6 +72,8 @@ gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig
                                                              NMSetting8021x *setting_8021x,
                                                              const char *connection_uid);
 
+gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self);
+
 gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                                  NMSetting8021x *setting,
                                                  const char *connection_uid,
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.h b/src/supplicant-manager/nm-supplicant-settings-verify.h
index 8752b43..0939ebd 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.h
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.h
@@ -25,7 +25,8 @@ typedef enum OptType {
 	TYPE_INVALID = 0,
 	TYPE_INT,
 	TYPE_BYTES,
-	TYPE_KEYWORD
+	TYPE_KEYWORD,
+	TYPE_STRING
 } OptType;
 
 OptType nm_supplicant_settings_verify_setting (const char * key,
diff --git a/src/supplicant-manager/tests/Makefile.am b/src/supplicant-manager/tests/Makefile.am
new file mode 100644
index 0000000..757f654
--- /dev/null
+++ b/src/supplicant-manager/tests/Makefile.am
@@ -0,0 +1,24 @@
+INCLUDES = \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/libnm-util \
+	-I$(top_srcdir)/src \
+	-I$(top_srcdir)/src/supplicant-manager
+
+noinst_PROGRAMS = test-supplicant-config
+
+test_supplicant_config_SOURCES = \
+	test-supplicant-config.c \
+	nm-test-helpers.h
+
+test_supplicant_config_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(DBUS_CFLAGS)
+
+test_supplicant_config_LDADD = \
+	$(DBUS_LIBS) \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/src/supplicant-manager/libsupplicant-manager.la
+
+check-local: test-supplicant-config
+	$(abs_builddir)/test-supplicant-config
+
diff --git a/src/supplicant-manager/tests/nm-test-helpers.h b/src/supplicant-manager/tests/nm-test-helpers.h
new file mode 100644
index 0000000..d0868b5
--- /dev/null
+++ b/src/supplicant-manager/tests/nm-test-helpers.h
@@ -0,0 +1,48 @@
+/* NetworkManager -- Network link manager
+ *
+ * Dan Williams <dcbw@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef NM_TEST_HELPERS_H
+#define NM_TEST_HELPERS_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+static void
+FAIL(const char *test_name, const char *fmt, ...)
+{
+    va_list args;
+    char buf[500];
+
+	snprintf (buf, 500, "FAIL: (%s) %s\n", test_name, fmt);
+
+    va_start (args, fmt);
+	vfprintf (stderr, buf, args);
+    va_end (args);
+	_exit (1);
+}
+
+#define ASSERT(x, test_name, fmt, ...) \
+	if (!(x)) { \
+		FAIL (test_name, fmt, ## __VA_ARGS__); \
+	}
+
+#endif /* NM_TEST_HELPERS_H */
+
diff --git a/src/supplicant-manager/tests/test-supplicant-config.c b/src/supplicant-manager/tests/test-supplicant-config.c
new file mode 100644
index 0000000..d0868b5
--- /dev/null
+++ b/src/supplicant-manager/tests/test-supplicant-config.c
@@ -0,0 +1,518 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2008 - 2009 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/ether.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dbus/dbus-glib.h>
+
+#include <nm-utils.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-wireless-security.h>
+#include <nm-setting-ip4-config.h>
+#include <nm-setting-8021x.h>
+
+#include "nm-test-helpers.h"
+
+#include "nm-supplicant-config.h"
+#include "nm-supplicant-settings-verify.h"
+
+static gboolean
+validate_opt (const char *detail,
+              GHashTable *hash,
+              const char *key,
+              OptType val_type,
+              gconstpointer expected,
+              size_t expected_len)
+{
+	GValue *value;
+	gint int_val;
+	GByteArray *array;
+	const char *s;
+	const unsigned char *expected_array = expected;
+	int result;
+
+	ASSERT (hash != NULL, detail, "hash was NULL");
+
+	value = g_hash_table_lookup (hash, key);
+	ASSERT (value != NULL,
+	        detail, "option '%s' expected but not found in config hash.");
+
+	switch (val_type) {
+	case TYPE_INT:
+		ASSERT (G_VALUE_HOLDS_INT (value),
+		        detail, "config hash item '%s' was not TYPE_INT.", key);
+		int_val = g_value_get_int (value);
+		ASSERT (int_val == GPOINTER_TO_INT (expected),
+		        detail, "unexpected config hash item '%s' value %d (expected %d)",
+		        key, int_val, GPOINTER_TO_INT (expected));
+		break;
+	case TYPE_BYTES:
+		ASSERT (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY),
+		        detail, "config hash item '%s' was not TYPE_BYTES.", key);
+		array = g_value_get_boxed (value);
+		ASSERT (array->len == expected_len,
+		        detail, "unexpected config hash item '%s' length %d (expected %d)",
+		        key, array->len, expected_len);
+		result = memcmp (array->data, expected_array, expected_len);
+		ASSERT (result == 0, detail, "unexpected config hash item '%s' value", key);
+		break;
+	case TYPE_KEYWORD:
+	case TYPE_STRING:
+		ASSERT (G_VALUE_HOLDS_STRING (value),
+		        detail, "config hash item '%s' was not TYPE_STRING or TYPE_KEYWORD.", key);
+		if (expected_len == -1)
+			expected_len = strlen ((const char *) expected);
+		s = g_value_get_string (value);
+		ASSERT (s != NULL, detail, "unexpected NULL config hash string item '%s'.", key);
+		ASSERT (strlen (s) == expected_len,
+		        detail, "unexpected config hash string item '%s' length %d (expected %d)",
+		        key, strlen (s), expected_len);
+		result = strcmp (s, (const char *) expected);
+		ASSERT (result == 0,
+		        detail, "unexpected config hash string item '%s' value '%s' (expected '%s')",
+		        key, s, (const char *) expected);
+		break;
+	default:
+		g_warning ("unknown supplicant config hash item '%s' option type %d",
+		           key, val_type);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+test_wifi_open (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingIP4Config *s_ip4;
+	NMSupplicantConfig *config;
+	GHashTable *hash;
+	char *uuid;
+	gboolean success;
+	GError *error = NULL;
+	GByteArray *ssid;
+	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	GByteArray *bssid;
+	const unsigned char bssid_data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+	const char *bssid_str = "11:22:33:44:55:66";
+
+	connection = nm_connection_new ();
+	ASSERT (connection != NULL,
+	        "wifi-open", "failed to allocate new connection");
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	ASSERT (s_con != NULL,
+	        "wifi-open", "failed to allocate new %s setting",
+	        NM_SETTING_CONNECTION_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Wifi Open",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wifi setting */
+	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+	ASSERT (s_wifi != NULL,
+	        "wifi-open", "failed to allocate new %s setting",
+	        NM_SETTING_WIRELESS_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	ssid = g_byte_array_sized_new (sizeof (ssid_data));
+	g_byte_array_append (ssid, ssid_data, sizeof (ssid_data));
+	bssid = g_byte_array_sized_new (sizeof (bssid_data));
+	g_byte_array_append (bssid, bssid_data, sizeof (bssid_data));
+
+	g_object_set (s_wifi,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NM_SETTING_WIRELESS_BSSID, bssid,
+	              NM_SETTING_WIRELESS_MODE, "infrastructure",
+	              NM_SETTING_WIRELESS_BAND, "bg",
+	              NULL);
+
+	g_byte_array_free (ssid, TRUE);
+	g_byte_array_free (bssid, TRUE);
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	ASSERT (s_ip4 != NULL,
+	        "wifi-open", "failed to allocate new %s setting",
+	        NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        "wifi-open", "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	config = nm_supplicant_config_new ();
+	ASSERT (config != NULL,
+	        "wifi-open", "failed to create new supplicant config");
+
+	success = nm_supplicant_config_add_setting_wireless (config, s_wifi, TRUE, 0, TRUE, FALSE);
+	ASSERT (success == TRUE,
+	        "wifi-open", "failed to add wireless setting to supplicant config.");
+
+	success = nm_supplicant_config_add_no_security (config);
+	ASSERT (success == TRUE,
+	        "wifi-open", "failed to add wireless security to supplicant config.");
+
+	hash = nm_supplicant_config_get_hash (config);
+	ASSERT (hash != NULL,
+	        "wifi-open", "failed to hash supplicant config options.");
+
+	validate_opt ("wifi-open", hash, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
+	validate_opt ("wifi-open", hash, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
+	validate_opt ("wifi-open", hash, "bssid", TYPE_KEYWORD, bssid_str, -1);
+	validate_opt ("wifi-open", hash, "key_mgmt", TYPE_KEYWORD, "NONE", -1);
+
+	g_object_unref (connection);
+}
+
+static void
+test_wifi_wep_key (const char *detail,
+                   NMWepKeyType wep_type,
+                   const char *key_data,
+                   const unsigned char *expected,
+                   size_t expected_size)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	NMSettingIP4Config *s_ip4;
+	NMSupplicantConfig *config;
+	GHashTable *hash;
+	char *uuid;
+	gboolean success;
+	GError *error = NULL;
+	GByteArray *ssid;
+	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	GByteArray *bssid;
+	const unsigned char bssid_data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+	const char *bssid_str = "11:22:33:44:55:66";
+
+	connection = nm_connection_new ();
+	ASSERT (connection != NULL,
+	        detail, "failed to allocate new connection");
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	ASSERT (s_con != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_CONNECTION_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Wifi WEP Key",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wifi setting */
+	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+	ASSERT (s_wifi != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_WIRELESS_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	ssid = g_byte_array_sized_new (sizeof (ssid_data));
+	g_byte_array_append (ssid, ssid_data, sizeof (ssid_data));
+	bssid = g_byte_array_sized_new (sizeof (bssid_data));
+	g_byte_array_append (bssid, bssid_data, sizeof (bssid_data));
+
+	g_object_set (s_wifi,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NM_SETTING_WIRELESS_BSSID, bssid,
+	              NM_SETTING_WIRELESS_MODE, "infrastructure",
+	              NM_SETTING_WIRELESS_BAND, "bg",
+	              NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	              NULL);
+
+	g_byte_array_free (ssid, TRUE);
+	g_byte_array_free (bssid, TRUE);
+
+	/* Wifi Security setting */
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	ASSERT (s_wsec != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
+	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, wep_type,
+	              NULL);
+	nm_setting_wireless_security_set_wep_key (s_wsec, 0, key_data);	
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	ASSERT (s_ip4 != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        detail, "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	config = nm_supplicant_config_new ();
+	ASSERT (config != NULL,
+	        detail, "failed to create new supplicant config");
+
+	success = nm_supplicant_config_add_setting_wireless (config, s_wifi, TRUE, 0, TRUE, FALSE);
+	ASSERT (success == TRUE,
+	        detail, "failed to add wireless setting to supplicant config.");
+
+	success = nm_supplicant_config_add_setting_wireless_security (config,
+	                                                              s_wsec,
+	                                                              NULL,
+	                                                              "376aced7-b28c-46be-9a62-fcdf072571da");
+	ASSERT (success == TRUE,
+	        detail, "failed to add wireless security to supplicant config.");
+
+	hash = nm_supplicant_config_get_hash (config);
+	ASSERT (hash != NULL,
+	        detail, "failed to hash supplicant config options.");
+
+	validate_opt (detail, hash, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
+	validate_opt (detail, hash, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
+	validate_opt (detail, hash, "bssid", TYPE_KEYWORD, bssid_str, -1);
+	validate_opt (detail, hash, "key_mgmt", TYPE_KEYWORD, "NONE", -1);
+	validate_opt (detail, hash, "wep_tx_keyidx", TYPE_INT, GINT_TO_POINTER (0), -1);
+	validate_opt (detail, hash, "wep_key0", TYPE_BYTES, expected, expected_size);
+
+	g_object_unref (connection);
+}
+
+static void
+test_wifi_wep (void)
+{
+	const char *key1 = "12345";
+	const unsigned char key1_expected[] = { 0x31, 0x32, 0x33, 0x34, 0x35 };
+	const char *key2 = "ascii test$$$";
+	const unsigned char key2_expected[] = { 0x61, 0x73, 0x63, 0x69, 0x69, 0x20, 0x74, 0x65, 0x73, 0x74, 0x24, 0x24, 0x24 };
+	const char *key3 = "abcdef1234";
+	const unsigned char key3_expected[] = { 0xab, 0xcd, 0xef, 0x12, 0x34 };
+	const char *key4 = "96aec785c6392675f87f592972";
+	const unsigned char key4_expected[] = { 0x96, 0xae, 0xc7, 0x85, 0xc6, 0x39, 0x26, 0x75, 0xf8, 0x7f, 0x59, 0x29, 0x72 };
+	const char *key5 = "r34lly l33t w3p p4ssphr4s3 for t3st1ng";
+	const unsigned char key5_expected[] = { 0xce, 0x68, 0x8b, 0x35, 0xf6, 0x0a, 0x2b, 0xbf, 0xc9, 0x8f, 0xed, 0x10, 0xda };
+
+	test_wifi_wep_key ("wifi-wep-ascii-40", NM_WEP_KEY_TYPE_KEY, key1, key1_expected, sizeof (key1_expected));
+	test_wifi_wep_key ("wifi-wep-ascii-104", NM_WEP_KEY_TYPE_KEY, key2, key2_expected, sizeof (key2_expected));
+	test_wifi_wep_key ("wifi-wep-hex-40", NM_WEP_KEY_TYPE_KEY, key3, key3_expected, sizeof (key3_expected));
+	test_wifi_wep_key ("wifi-wep-hex-104", NM_WEP_KEY_TYPE_KEY, key4, key4_expected, sizeof (key4_expected));
+	test_wifi_wep_key ("wifi-wep-passphrase-104", NM_WEP_KEY_TYPE_PASSPHRASE, key5, key5_expected, sizeof (key5_expected));
+
+	test_wifi_wep_key ("wifi-wep-old-hex-104", NM_WEP_KEY_TYPE_UNKNOWN, key4, key4_expected, sizeof (key4_expected));
+}
+
+static void
+test_wifi_wpa_psk (const char *detail,
+                   OptType key_type,
+                   const char *key_data,
+                   const unsigned char *expected,
+                   size_t expected_size)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	NMSettingIP4Config *s_ip4;
+	NMSupplicantConfig *config;
+	GHashTable *hash;
+	char *uuid;
+	gboolean success;
+	GError *error = NULL;
+	GByteArray *ssid;
+	const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 };
+	GByteArray *bssid;
+	const unsigned char bssid_data[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+	const char *bssid_str = "11:22:33:44:55:66";
+
+	connection = nm_connection_new ();
+	ASSERT (connection != NULL,
+	        detail, "failed to allocate new connection");
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	ASSERT (s_con != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_CONNECTION_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Wifi WEP Key",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wifi setting */
+	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+	ASSERT (s_wifi != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_WIRELESS_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	ssid = g_byte_array_sized_new (sizeof (ssid_data));
+	g_byte_array_append (ssid, ssid_data, sizeof (ssid_data));
+	bssid = g_byte_array_sized_new (sizeof (bssid_data));
+	g_byte_array_append (bssid, bssid_data, sizeof (bssid_data));
+
+	g_object_set (s_wifi,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NM_SETTING_WIRELESS_BSSID, bssid,
+	              NM_SETTING_WIRELESS_MODE, "infrastructure",
+	              NM_SETTING_WIRELESS_BAND, "bg",
+	              NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	              NULL);
+
+	g_byte_array_free (ssid, TRUE);
+	g_byte_array_free (bssid, TRUE);
+
+	/* Wifi Security setting */
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	ASSERT (s_wsec != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
+	              NM_SETTING_WIRELESS_SECURITY_PSK, key_data,
+	              NULL);
+
+	nm_setting_wireless_security_add_proto (s_wsec, "wpa");
+	nm_setting_wireless_security_add_proto (s_wsec, "rsn");
+	nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
+	nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp");
+	nm_setting_wireless_security_add_group (s_wsec, "tkip");
+	nm_setting_wireless_security_add_group (s_wsec, "ccmp");
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	ASSERT (s_ip4 != NULL,
+	        detail, "failed to allocate new %s setting",
+	        NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        detail, "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	config = nm_supplicant_config_new ();
+	ASSERT (config != NULL,
+	        detail, "failed to create new supplicant config");
+
+	success = nm_supplicant_config_add_setting_wireless (config, s_wifi, TRUE, 0, TRUE, FALSE);
+	ASSERT (success == TRUE,
+	        detail, "failed to add wireless setting to supplicant config.");
+
+	success = nm_supplicant_config_add_setting_wireless_security (config,
+	                                                              s_wsec,
+	                                                              NULL,
+	                                                              "376aced7-b28c-46be-9a62-fcdf072571da");
+	ASSERT (success == TRUE,
+	        detail, "failed to add wireless security to supplicant config.");
+
+	hash = nm_supplicant_config_get_hash (config);
+	ASSERT (hash != NULL,
+	        detail, "failed to hash supplicant config options.");
+
+	validate_opt (detail, hash, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1), -1);
+	validate_opt (detail, hash, "ssid", TYPE_BYTES, ssid_data, sizeof (ssid_data));
+	validate_opt (detail, hash, "bssid", TYPE_KEYWORD, bssid_str, -1);
+	validate_opt (detail, hash, "key_mgmt", TYPE_KEYWORD, "WPA-PSK", -1);
+	validate_opt (detail, hash, "proto", TYPE_KEYWORD, "WPA RSN", -1);
+	validate_opt (detail, hash, "pairwise", TYPE_KEYWORD, "TKIP CCMP", -1);
+	validate_opt (detail, hash, "group", TYPE_KEYWORD, "TKIP CCMP", -1);
+	validate_opt (detail, hash, "psk", key_type, expected, expected_size);
+
+	g_object_unref (connection);
+}
+
+static void
+test_wifi_wpa_psk_types (void)
+{
+	const char *key1 = "d4721e911461d3cdef9793858e977fcda091779243abb7316c2f11605a160893";
+	const unsigned char key1_expected[] = { 0xd4, 0x72, 0x1e, 0x91, 0x14, 0x61, 0xd3, 0xcd,
+	                                        0xef, 0x97, 0x93, 0x85, 0x8e, 0x97, 0x7f, 0xcd,
+	                                        0xa0, 0x91, 0x77, 0x92, 0x43, 0xab, 0xb7, 0x31,
+	                                        0x6c, 0x2f, 0x11, 0x60, 0x5a, 0x16, 0x08, 0x93 };
+	const char *key2 = "r34lly l33t wp4 p4ssphr4s3 for t3st1ng";
+
+	test_wifi_wpa_psk ("wifi-wpa-psk-hex", TYPE_BYTES, key1, key1_expected, sizeof (key1_expected));
+	test_wifi_wpa_psk ("wifi-wep-psk-passphrase", TYPE_STRING, key2, (gconstpointer) key2, strlen (key2));
+}
+
+int main (int argc, char **argv)
+{
+	GError *error = NULL;
+	DBusGConnection *bus;
+	char *base;
+
+	g_type_init ();
+	bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+
+	if (!nm_utils_init (&error))
+		FAIL ("nm-utils-init", "failed to initialize libnm-util: %s", error->message);
+
+	/* The tests */
+	test_wifi_open ();
+	test_wifi_wep ();
+	test_wifi_wpa_psk_types ();
+
+	base = g_path_get_basename (argv[0]);
+	fprintf (stdout, "%s: SUCCESS\n", base);
+	g_free (base);
+	return 0;
+}
+