summary refs log tree commit diff
path: root/libnm-util/nm-setting-8021x.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-util/nm-setting-8021x.c')
-rw-r--r--libnm-util/nm-setting-8021x.c86
1 files changed, 56 insertions, 30 deletions
diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c
index 6d5268a1..678d70ab 100644
--- a/libnm-util/nm-setting-8021x.c
+++ b/libnm-util/nm-setting-8021x.c
@@ -33,6 +33,7 @@
 #include "crypto.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
+#include "nm-macros-internal.h"
 
 /**
  * SECTION:nm-setting-8021x
@@ -430,13 +431,52 @@ get_cert_scheme (GByteArray *array)
 	if (!array || !array->len)
 		return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
 
-	if (   (array->len > strlen (SCHEME_PATH))
-	    && !memcmp (array->data, SCHEME_PATH, strlen (SCHEME_PATH)))
-		return NM_SETTING_802_1X_CK_SCHEME_PATH;
+	/* interpret the blob as PATH if it starts with "file://". */
+	if (   array->len >= STRLEN (SCHEME_PATH)
+	    && !memcmp (array->data, SCHEME_PATH, STRLEN (SCHEME_PATH))) {
+		/* But it must also be NUL terminated, contain at least
+		 * one non-NUL character, and contain only one trailing NUL
+		 * chracter.
+		 * And ensure it's UTF-8 valid too so we can pass it through
+		 * D-Bus and stuff like that. */
+		if (   array->len > STRLEN (SCHEME_PATH) + 1
+		    && array->data[array->len - 1] == '\0'
+		    && g_utf8_validate ((const char *) &array->data[STRLEN (SCHEME_PATH)], array->len - (STRLEN (SCHEME_PATH) + 1), NULL))
+			return NM_SETTING_802_1X_CK_SCHEME_PATH;
+		return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+	}
 
 	return NM_SETTING_802_1X_CK_SCHEME_BLOB;
 }
 
+static GByteArray *
+load_and_verify_certificate (const char *cert_path,
+                             NMSetting8021xCKScheme scheme,
+                             NMCryptoFileFormat *out_file_format,
+                             GError **error)
+{
+	NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	GByteArray *array;
+
+	array = crypto_load_and_verify_certificate (cert_path, &format, error);
+
+	if (!array || !array->len || format == NM_CRYPTO_FILE_FORMAT_UNKNOWN)
+		format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+		/* If we load the file as blob, we must ensure that the binary data does not
+		 * start with file://. NMSetting8021x cannot represent blobs that start with
+		 * file://.
+		 * If that's the case, coerce the format to UNKNOWN. The callers will take care
+		 * of that and not set the blob. */
+		if (get_cert_scheme (array) != NM_SETTING_802_1X_CK_SCHEME_BLOB)
+			format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	}
+
+	if (out_file_format)
+		*out_file_format = format;
+	return array;
+}
+
 /**
  * nm_setting_802_1x_get_ca_cert_scheme:
  * @setting: the #NMSetting8021x
@@ -511,14 +551,16 @@ static GByteArray *
 path_to_scheme_value (const char *path)
 {
 	GByteArray *array;
+	gsize len;
+
+	g_return_val_if_fail (path != NULL && path[0], NULL);
 
-	g_return_val_if_fail (path != NULL, NULL);
+	len = strlen (path);
 
-	/* Add the path scheme tag to the front, then the fielname */
-	array = g_byte_array_sized_new (strlen (path) + strlen (SCHEME_PATH) + 1);
-	g_assert (array);
+	/* Add the path scheme tag to the front, then the filename */
+	array = g_byte_array_sized_new (len + strlen (SCHEME_PATH) + 1);
 	g_byte_array_append (array, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH));
-	g_byte_array_append (array, (const guint8 *) path, strlen (path));
+	g_byte_array_append (array, (const guint8 *) path, len);
 	g_byte_array_append (array, (const guint8 *) "\0", 1);
 	return array;
 }
@@ -578,7 +620,7 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *setting,
 		return TRUE;
 	}
 
-	data = crypto_load_and_verify_certificate (cert_path, &format, error);
+	data = load_and_verify_certificate (cert_path, scheme, &format, error);
 	if (data) {
 		/* wpa_supplicant can only use raw x509 CA certs */
 		if (format == NM_CRYPTO_FILE_FORMAT_X509) {
@@ -894,7 +936,7 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *setting,
 		return TRUE;
 	}
 
-	data = crypto_load_and_verify_certificate (cert_path, &format, error);
+	data = load_and_verify_certificate (cert_path, scheme, &format, error);
 	if (data) {
 		gboolean valid = FALSE;
 
@@ -1159,7 +1201,7 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *setting,
 		return TRUE;
 	}
 
-	data = crypto_load_and_verify_certificate (cert_path, &format, error);
+	data = load_and_verify_certificate (cert_path, scheme, &format, error);
 	if (data) {
 		/* wpa_supplicant can only use raw x509 CA certs */
 		if (format == NM_CRYPTO_FILE_FORMAT_X509) {
@@ -1479,7 +1521,7 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *setting,
 		return TRUE;
 	}
 
-	data = crypto_load_and_verify_certificate (cert_path, &format, error);
+	data = load_and_verify_certificate (cert_path, scheme, &format, error);
 	if (data) {
 		gboolean valid = FALSE;
 
@@ -2604,25 +2646,9 @@ need_secrets (NMSetting *setting)
 static gboolean
 verify_cert (GByteArray *array, const char *prop_name, GError **error)
 {
-	if (!array)
-		return TRUE;
-
-	switch (get_cert_scheme (array)) {
-	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
+	if (   !array
+	    || get_cert_scheme (array) != NM_SETTING_802_1X_CK_SCHEME_UNKNOWN)
 		return TRUE;
-	case NM_SETTING_802_1X_CK_SCHEME_PATH:
-		/* For path-based schemes, verify that the path is zero-terminated */
-		if (array->data[array->len - 1] == '\0') {
-			/* And ensure it's UTF-8 valid too so we can pass it through
-			 * D-Bus and stuff like that.
-			 */
-			if (g_utf8_validate ((const char *) (array->data + strlen (SCHEME_PATH)), -1, NULL))
-				return TRUE;
-		}
-		break;
-	default:
-		break;
-	}
 
 	g_set_error_literal (error,
 	                     NM_SETTING_802_1X_ERROR,