File nm-certificate-formats.patch of Package NetworkManager
From ac71f8308f20ccb850881da11ae7de5d74f27445 Mon Sep 17 00:00:00 2001
From: Tambet Ingo <tambet@gmail.com>
Date: Fri, 21 Nov 2008 11:14:24 +0200
Subject: [PATCH] Support multiple formats of certificates.
---
libnm-util/nm-setting-8021x.c | 15 +-
libnm-util/nm-setting-8021x.h | 3 +
libnm-util/nm-setting.h | 1 +
src/supplicant-manager/nm-supplicant-config.c | 198 ++++++++++++++++----
.../nm-supplicant-settings-verify.c | 6 +
.../plugins/keyfile/nm-keyfile-connection.c | 12 ++
system-settings/plugins/keyfile/reader.c | 79 ++++++--
7 files changed, 250 insertions(+), 64 deletions(-)
diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c
index 04d2905..e7bb8eb 100644
--- a/libnm-util/nm-setting-8021x.c
+++ b/libnm-util/nm-setting-8021x.c
@@ -707,6 +707,9 @@ need_private_key_password (GByteArray *key, const char *password)
GError *error = NULL;
gboolean needed = TRUE;
+ if (key && key->data && g_str_has_prefix ((char *) key->data, NM_SETTING_802_1X_CK_FORMAT_FILE))
+ return FALSE;
+
/* See if a private key password is needed, which basically is whether
* or not the private key is a PKCS#12 file or not, since PKCS#1 files
* are decrypted by the settings service.
@@ -1368,7 +1371,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
"CA certificate",
"CA certificate",
DBUS_TYPE_G_UCHAR_ARRAY,
- G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+ G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
g_object_class_install_property
(object_class, PROP_CA_PATH,
@@ -1384,7 +1387,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
"Client certificate",
"Client certificate",
DBUS_TYPE_G_UCHAR_ARRAY,
- G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+ G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
g_object_class_install_property
(object_class, PROP_PHASE1_PEAPVER,
@@ -1432,7 +1435,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
"Phase2 CA certificate",
"Phase2 CA certificate",
DBUS_TYPE_G_UCHAR_ARRAY,
- G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+ G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
g_object_class_install_property
(object_class, PROP_PHASE2_CA_PATH,
@@ -1448,7 +1451,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
"Phase2 client certificate",
"Phase2 client certificate",
DBUS_TYPE_G_UCHAR_ARRAY,
- G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+ G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_CERTIFICATE));
g_object_class_install_property
(object_class, PROP_PASSWORD,
@@ -1464,7 +1467,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
"Private key",
"Private key",
DBUS_TYPE_G_UCHAR_ARRAY,
- G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
+ G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_CERTIFICATE));
g_object_class_install_property
(object_class, PROP_PRIVATE_KEY_PASSWORD,
@@ -1480,7 +1483,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
"Phase2 private key",
"Phase2 private key",
DBUS_TYPE_G_UCHAR_ARRAY,
- G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
+ G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_CERTIFICATE));
g_object_class_install_property
(object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD,
diff --git a/libnm-util/nm-setting-8021x.h b/libnm-util/nm-setting-8021x.h
index 91d494d..2c063b9 100644
--- a/libnm-util/nm-setting-8021x.h
+++ b/libnm-util/nm-setting-8021x.h
@@ -82,6 +82,9 @@ GQuark nm_setting_802_1x_error_quark (void);
#define NM_SETTING_802_1X_PIN "pin"
#define NM_SETTING_802_1X_PSK "psk"
+#define NM_SETTING_802_1X_CK_FORMAT_ID "id:"
+#define NM_SETTING_802_1X_CK_FORMAT_FILE "file:"
+
typedef struct {
NMSetting parent;
} NMSetting8021x;
diff --git a/libnm-util/nm-setting.h b/libnm-util/nm-setting.h
index 8303c74..77f8d4b 100644
--- a/libnm-util/nm-setting.h
+++ b/libnm-util/nm-setting.h
@@ -56,6 +56,7 @@ GQuark nm_setting_error_quark (void);
#define NM_SETTING_PARAM_REQUIRED (1 << (1 + G_PARAM_USER_SHIFT))
#define NM_SETTING_PARAM_SECRET (1 << (2 + G_PARAM_USER_SHIFT))
#define NM_SETTING_PARAM_FUZZY_IGNORE (1 << (3 + G_PARAM_USER_SHIFT))
+#define NM_SETTING_PARAM_CERTIFICATE (1 << (4 + G_PARAM_USER_SHIFT))
#define NM_SETTING_NAME "name"
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index d087b2c..a80cc93 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -554,6 +554,165 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
return TRUE;
}
+static gboolean
+add_certificates (NMSupplicantConfig *self, NMSetting8021x *setting, const char *connection_uid)
+{
+ const GByteArray *array;
+ const char *str;
+ char *value;
+ gboolean send_private_key_passwd;
+ gboolean send_client_cert;
+ gboolean success;
+
+ array = nm_setting_802_1x_get_ca_cert (setting);
+ if (array && array->data) {
+ str = (char *) array->data;
+
+ if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID))
+ nm_supplicant_config_add_option (self, "ca_cert_id",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+ -1, FALSE);
+ else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE))
+ nm_supplicant_config_add_option (self, "ca_cert",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+ -1, FALSE);
+ else {
+ ADD_BLOB_VAL (array, "ca_cert", connection_uid);
+ }
+ }
+
+ array = nm_setting_802_1x_get_private_key (setting);
+ if (array && array->data) {
+ str = (char *) array->data;
+
+ if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+ nm_supplicant_config_add_option (self, "key_id",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+ -1, FALSE);
+
+ send_private_key_passwd = FALSE;
+ send_client_cert = TRUE;
+ } else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+ nm_supplicant_config_add_option (self, "private_key",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+ -1, FALSE);
+
+ send_private_key_passwd = TRUE;
+ send_client_cert = TRUE;
+ } else {
+ ADD_BLOB_VAL (array, "private_key", connection_uid);
+
+ if (nm_setting_802_1x_get_private_key_type (setting) == NM_SETTING_802_1X_CK_TYPE_PKCS12) {
+ send_private_key_passwd = TRUE;
+ send_client_cert = FALSE;
+ } else {
+ send_private_key_passwd = FALSE;
+ send_client_cert = TRUE;
+ }
+ }
+ }
+
+ if (send_private_key_passwd) {
+ ADD_STRING_VAL (nm_setting_802_1x_get_private_key_password (setting),
+ "private_key_passwd", FALSE, FALSE, TRUE);
+ }
+
+ if (send_client_cert) {
+ array = nm_setting_802_1x_get_client_cert (setting);
+ if (array && array->data) {
+ str = (char *) array->data;
+
+ if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID))
+ nm_supplicant_config_add_option (self, "cert_id",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+ -1, FALSE);
+ else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE))
+ nm_supplicant_config_add_option (self, "client_cert",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+ -1, FALSE);
+ else {
+ ADD_BLOB_VAL (array, "client_cert", connection_uid);
+ }
+ }
+ }
+
+ /* phase 2 */
+
+ array = nm_setting_802_1x_get_phase2_ca_cert (setting);
+ if (array && array->data) {
+ str = (char *) array->data;
+
+ if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+ nm_supplicant_config_add_option (self, "ca_cert2_id",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+ -1, FALSE);
+ } else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+ nm_supplicant_config_add_option (self, "ca_cert2",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+ -1, FALSE);
+ } else {
+ ADD_BLOB_VAL (array, "ca_cert", connection_uid);
+ }
+ }
+
+ array = nm_setting_802_1x_get_phase2_private_key (setting);
+ if (array && array->data) {
+ str = (char *) array->data;
+
+ if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+ nm_supplicant_config_add_option (self, "key2_id",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+ -1, FALSE);
+
+ send_private_key_passwd = FALSE;
+ send_client_cert = TRUE;
+ } else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+ nm_supplicant_config_add_option (self, "private_key2",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+ -1, FALSE);
+
+ send_private_key_passwd = TRUE;
+ send_client_cert = TRUE;
+ } else {
+ ADD_BLOB_VAL (array, "private_key2", connection_uid);
+
+ if (nm_setting_802_1x_get_phase2_private_key_type (setting) == NM_SETTING_802_1X_CK_TYPE_PKCS12) {
+ send_private_key_passwd = TRUE;
+ send_client_cert = FALSE;
+ } else {
+ send_private_key_passwd = FALSE;
+ send_client_cert = TRUE;
+ }
+ }
+ }
+
+ if (send_private_key_passwd) {
+ ADD_STRING_VAL (nm_setting_802_1x_get_phase2_private_key_password (setting),
+ "private_key2_passwd", FALSE, FALSE, TRUE);
+ }
+
+ if (send_client_cert) {
+ array = nm_setting_802_1x_get_phase2_client_cert (setting);
+ if (array && array->data) {
+ str = (char *) array->data;
+
+ if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_ID)) {
+ nm_supplicant_config_add_option (self, "cert2_id",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_ID),
+ -1, FALSE);
+ } else if (g_str_has_prefix (str, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+ nm_supplicant_config_add_option (self, "client_cert2",
+ str + strlen (NM_SETTING_802_1X_CK_FORMAT_FILE),
+ -1, FALSE);
+ } else {
+ ADD_BLOB_VAL (array, "client_cert2", connection_uid);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
gboolean
nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
NMSetting8021x *setting,
@@ -564,7 +723,6 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
char *value, *tmp;
gboolean success;
GString *phase1, *phase2;
- const GByteArray *array;
g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
g_return_val_if_fail (setting != NULL, FALSE);
@@ -620,45 +778,11 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
ADD_STRING_VAL (phase2->str, "phase2", FALSE, FALSE, FALSE);
g_string_free (phase2, TRUE);
- ADD_BLOB_VAL (nm_setting_802_1x_get_ca_cert (setting), "ca_cert", connection_uid);
-
- array = nm_setting_802_1x_get_private_key (setting);
- if (array) {
- ADD_BLOB_VAL (array, "private_key", connection_uid);
-
- 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);
- break;
- default:
- /* Only add the client cert if the private key is not PKCS#12 */
- ADD_BLOB_VAL (nm_setting_802_1x_get_client_cert (setting), "client_cert", connection_uid);
- break;
- }
- }
-
- ADD_BLOB_VAL (nm_setting_802_1x_get_phase2_ca_cert (setting), "ca_cert2", connection_uid);
-
- array = nm_setting_802_1x_get_phase2_private_key (setting);
- if (array) {
- ADD_BLOB_VAL (array, "private_key2", connection_uid);
-
- 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);
- break;
- default:
- /* Only add the client cert if the private key is not PKCS#12 */
- ADD_BLOB_VAL (nm_setting_802_1x_get_phase2_client_cert (setting), "client_cert2", connection_uid);
- break;
- }
- }
-
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);
+ add_certificates (self, setting, connection_uid);
+
return TRUE;
}
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c
index b8bd9fc..71b16da 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.c
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.c
@@ -102,16 +102,22 @@ static const struct Opt opt_table[] = {
{ "identity", TYPE_BYTES, 0, 0, FALSE, NULL },
{ "password", TYPE_BYTES, 0, 0, FALSE, NULL },
{ "ca_cert", TYPE_BYTES, 0, 65536, FALSE, NULL },
+ { "ca_cert_id", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "client_cert", TYPE_BYTES, 0, 65536, FALSE, NULL },
+ { "cert_id", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "private_key", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "private_key_passwd", TYPE_BYTES, 0, 1024, FALSE, NULL },
+ { "key_id", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "phase1", TYPE_KEYWORD, 0, 0, TRUE, phase1_allowed },
{ "phase2", TYPE_KEYWORD, 0, 0, TRUE, phase2_allowed },
{ "anonymous_identity", TYPE_BYTES, 0, 0, FALSE, NULL },
{ "ca_cert2", TYPE_BYTES, 0, 65536, FALSE, NULL },
+ { "ca_cert2_id", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "client_cert2", TYPE_BYTES, 0, 65536, FALSE, NULL },
+ { "cert2_id", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "private_key2", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "private_key2_passwd",TYPE_BYTES, 0, 1024, FALSE, NULL },
+ { "key2_id", TYPE_BYTES, 0, 65536, FALSE, NULL },
{ "pin", TYPE_BYTES, 0, 0, FALSE, NULL },
{ "pcsc", TYPE_BYTES, 0, 0, FALSE, NULL },
{ "nai", TYPE_BYTES, 0, 0, FALSE, NULL },
diff --git a/system-settings/plugins/keyfile/nm-keyfile-connection.c b/system-settings/plugins/keyfile/nm-keyfile-connection.c
index c65b1b6..4b7cb0d 100644
--- a/system-settings/plugins/keyfile/nm-keyfile-connection.c
+++ b/system-settings/plugins/keyfile/nm-keyfile-connection.c
@@ -114,6 +114,18 @@ add_secrets (NMSetting *setting,
} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) {
/* Flatten the string hash by pulling its keys/values out */
g_hash_table_foreach (g_value_get_boxed (value), copy_one_secret, secrets);
+ } else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY)) {
+ const GByteArray *array;
+
+ array = (GByteArray *) g_value_get_boxed (value);
+ if (array && array->len > 0) {
+ GValue *v;
+
+ v = g_slice_new0 (GValue);
+ g_value_init (v, DBUS_TYPE_G_UCHAR_ARRAY);
+ g_value_copy (value, v);
+ g_hash_table_insert (secrets, g_strdup (key), v);
+ }
} else
g_message ("%s: unhandled secret %s type %s", __func__, key, G_VALUE_TYPE_NAME (value));
}
diff --git a/system-settings/plugins/keyfile/reader.c b/system-settings/plugins/keyfile/reader.c
index 9efd130..b8c4099 100644
--- a/system-settings/plugins/keyfile/reader.c
+++ b/system-settings/plugins/keyfile/reader.c
@@ -29,6 +29,7 @@
#include <nm-setting-ip4-config.h>
#include <nm-setting-vpn.h>
#include <nm-setting-connection.h>
+#include <nm-setting-8021x.h>
#include <arpa/inet.h>
#include <string.h>
@@ -337,6 +338,56 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
g_strfreev (keys);
}
+static void
+read_guchar_array (GKeyFile *file, NMSetting *setting, const char *key)
+{
+ gint *tmp;
+ GByteArray *array;
+ gsize length;
+ int i;
+
+ tmp = g_key_file_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
+ array = g_byte_array_sized_new (length);
+ for (i = 0; i < length; i++) {
+ int val = tmp[i];
+ unsigned char v = (unsigned char) (val & 0xFF);
+
+ if (val < 0 || val > 255)
+ g_warning ("Value out of range for a byte value");
+ else
+ g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
+ }
+
+ g_object_set (setting, key, array, NULL);
+ g_byte_array_free (array, TRUE);
+ g_free (tmp);
+}
+
+static void
+read_certificate (NMSetting *setting, GKeyFile *file, const char *key)
+{
+ char *value;
+
+ value = g_key_file_get_value (file, nm_setting_get_name (setting), key, NULL);
+ if (!value)
+ return;
+
+ if (g_str_has_prefix (value, NM_SETTING_802_1X_CK_FORMAT_ID) ||
+ g_str_has_prefix (value, NM_SETTING_802_1X_CK_FORMAT_FILE)) {
+ GByteArray *array;
+ gsize len;
+
+ len = strlen (value);
+ array = g_byte_array_sized_new (len);
+ g_byte_array_append (array, (guint8 *) value, len);
+ g_object_set (setting, key, array, NULL);
+ g_byte_array_free (array, TRUE);
+ } else
+ read_guchar_array (file, setting, key);
+
+ g_free (value);
+}
+
typedef struct {
GKeyFile *keyfile;
gboolean secrets;
@@ -390,6 +441,12 @@ read_one_setting_value (NMSetting *setting,
return;
}
+ /* Certificates are handled differently */
+ if (flags & NM_SETTING_PARAM_CERTIFICATE) {
+ read_certificate (setting, file, key);
+ return;
+ }
+
type = G_VALUE_TYPE (value);
if (type == G_TYPE_STRING) {
@@ -432,27 +489,7 @@ read_one_setting_value (NMSetting *setting,
g_free (tmp_str);
g_object_set (setting, key, uint_val, NULL);
} else if (type == DBUS_TYPE_G_UCHAR_ARRAY) {
- gint *tmp;
- GByteArray *array;
- gsize length;
- int i;
-
- tmp = g_key_file_get_integer_list (file, setting_name, key, &length, NULL);
-
- array = g_byte_array_sized_new (length);
- for (i = 0; i < length; i++) {
- int val = tmp[i];
- unsigned char v = (unsigned char) (val & 0xFF);
-
- if (val < 0 || val > 255)
- g_warning ("Value out of range for a byte value");
- else
- g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
- }
-
- g_object_set (setting, key, array, NULL);
- g_byte_array_free (array, TRUE);
- g_free (tmp);
+ read_guchar_array (file, setting, key);
} else if (type == DBUS_TYPE_G_LIST_OF_STRING) {
gchar **sa;
gsize length;
--
1.6.0.2