/libnm-core/tests/test-crypto
/libnm-core/tests/test-settings-defaults
/libnm-core/tests/test-general
+/libnm-core/tests/test-keyfile
/libnm-core/tests/test-need-secrets
/libnm-core/tests/test-secrets
/libnm-core/tests/test-setting-8021x
#define NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB "data:;base64,"
#define NM_KEYFILE_CERT_SCHEME_PREFIX_PATH "file://"
+char *nm_keyfile_detect_unqualified_path_scheme (const char *base_dir,
+ gconstpointer pdata,
+ gsize data_len,
+ gboolean consider_exists,
+ gboolean *out_exists);
+
typedef enum {
NM_KEYFILE_READ_TYPE_WARN = 1,
} NMKeyfileReadType;
typedef enum {
NM_KEYFILE_WARN_SEVERITY_DEBUG = 1000,
NM_KEYFILE_WARN_SEVERITY_INFO = 2000,
+ NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE = 2901,
NM_KEYFILE_WARN_SEVERITY_WARN = 3000,
} NMKeyfileWarnSeverity;
#include <glib/gi18n-lib.h>
#include "nm-core-internal.h"
+#include "nm-utils-internal.h"
#include "gsystem-local-alloc.h"
#include "nm-glib-compat.h"
#include "nm-keyfile-internal.h"
}
static gboolean
-handle_as_scheme (GBytes *bytes, NMSetting *setting, const char *key)
+handle_as_scheme (KeyfileReaderInfo *info, GBytes *bytes, NMSetting *setting, const char *key)
{
- const guint8 *data;
- gsize data_len;
+ const char *data;
+ gsize data_len, bin_len;
data = g_bytes_get_data (bytes, &data_len);
- /* It's the PATH scheme, can just set plain data */
- if ( (data_len > strlen (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH))
- && g_str_has_prefix ((const char *) data, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)
- && (data[data_len - 1] == '\0')) {
- g_object_set (setting, key, bytes, NULL);
+ g_return_val_if_fail (data && data_len > 0, FALSE);
+
+ /* to be a scheme, @data must be a zero terminated string, which is counted by @data_len */
+ if (data[data_len - 1] != '\0')
+ return FALSE;
+ data_len--;
+
+ /* It's the PATH scheme, can just set plain data.
+ * In this case, @data_len includes */
+ if ( data_len >= STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)
+ && g_str_has_prefix (data, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)) {
+ if (nm_setting_802_1x_check_cert_scheme (data, data_len + 1, NULL) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+ const char *path = &data[STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)];
+ gs_free char *path_free = NULL;
+
+ if (path[0] != '/') {
+ /* we want to read absolute paths because we use keyfile as exchange
+ * between different processes which might not have the same cwd. */
+ path = path_free = get_cert_path (info->base_dir, (const guint8 *) path,
+ data_len - STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH));
+ }
+
+ g_object_set (setting, key, bytes, NULL);
+ if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
+ handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE,
+ _("certificate or key file '%s' does not exist"),
+ path);
+ }
+ } else {
+ handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+ _("invalid key/cert value path \"%s\""), data);
+ }
+ return TRUE;
+ }
+ if ( data_len > STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)
+ && g_str_has_prefix (data, NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)) {
+ const char *cdata = data + STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB);
+ guchar *bin;
+ GBytes *bytes2;
+ gsize i;
+ gboolean valid_base64;
+
+ data_len -= STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB);
+
+ /* Let's be strict here. We expect valid base64, no funny stuff!!
+ * We didn't write such invalid data ourselfes and refuse to read it as blob. */
+ if ((valid_base64 = (data_len % 4 == 0))) {
+ for (i = 0; i < data_len; i++) {
+ char c = cdata[i];
+
+ if (!( (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || (c == '+' || c == '/'))) {
+ if (c != '=' || i < data_len - 2)
+ valid_base64 = FALSE;
+ else {
+ for (; i < data_len; i++) {
+ if (cdata[i] != '=')
+ valid_base64 = FALSE;
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (!valid_base64) {
+ handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+ _("invalid key/cert value data:;base64, is not base64"));
+ return TRUE;
+ }
+
+ bin = g_base64_decode (cdata, &bin_len);
+
+ g_return_val_if_fail (bin_len > 0, FALSE);
+ if (nm_setting_802_1x_check_cert_scheme (bin, bin_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+ /* The blob probably starts with "file://". Setting the cert data will confuse NMSetting8021x.
+ * In fact this is a limitation of NMSetting8021x which does not support setting blobs that start
+ * with file://. Just warn and return TRUE to signal that we ~handled~ the setting. */
+ g_free (bin);
+ handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+ _("invalid key/cert value data:;base64,file://"));
+ } else {
+ bytes2 = g_bytes_new_take (bin, bin_len);
+ g_object_set (setting, key, bytes2, NULL);
+ g_bytes_unref (bytes2);
+ }
return TRUE;
}
return FALSE;
}
-static gboolean
-handle_as_path (KeyfileReaderInfo *info,
- GBytes *bytes,
- NMSetting *setting,
- const char *key)
+char *
+nm_keyfile_detect_unqualified_path_scheme (const char *base_dir,
+ gconstpointer pdata,
+ gsize data_len,
+ gboolean consider_exists,
+ gboolean *out_exists)
{
- const guint8 *data;
- gsize data_len;
+ const char *data = pdata;
+ gboolean exists = FALSE;
+ gboolean success = FALSE;
gsize validate_len;
char *path;
- gboolean exists, success = FALSE;
+ GByteArray *tmp;
- data = g_bytes_get_data (bytes, &data_len);
+ g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL);
+
+ if (!pdata)
+ return NULL;
+ if (data_len == -1)
+ data_len = strlen (data);
if (data_len > 500 || data_len < 1)
- return FALSE;
+ return NULL;
/* If there's a trailing zero tell g_utf8_validate() to validate until the zero */
if (data[data_len - 1] == '\0') {
validate_len = data_len - 1;
} else
validate_len = data_len;
-
if ( validate_len == 0
|| g_utf8_validate ((const char *) data, validate_len, NULL) == FALSE)
- return FALSE;
+ return NULL;
/* Might be a bare path without the file:// prefix; in that case
* if it's an absolute path, use that, otherwise treat it as a
* relative path to the current directory.
*/
- path = get_cert_path (info->base_dir, data, data_len);
- exists = g_file_test (path, G_FILE_TEST_EXISTS);
- if ( exists
- || memchr (data, '/', data_len)
- || has_cert_ext (path)) {
- GByteArray *tmp;
- GBytes *val;
-
- /* Construct the proper value as required for the PATH scheme */
- tmp = g_byte_array_sized_new (strlen (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + strlen (path) + 1);
- g_byte_array_append (tmp, (const guint8 *) NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, strlen (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH));
- g_byte_array_append (tmp, (const guint8 *) path, strlen (path));
- g_byte_array_append (tmp, (const guint8 *) "\0", 1);
- val = g_byte_array_free_to_bytes (tmp);
- g_object_set (setting, key, val, NULL);
- g_bytes_unref (val);
+ path = get_cert_path (base_dir, (const guint8 *) data, data_len);
+ if ( !memchr (data, '/', data_len)
+ && !has_cert_ext (path)) {
+ if (!consider_exists)
+ goto out;
+ exists = g_file_test (path, G_FILE_TEST_EXISTS);
+ if (!exists)
+ goto out;
+ } else if (out_exists)
+ exists = g_file_test (path, G_FILE_TEST_EXISTS);
+
+ /* Construct the proper value as required for the PATH scheme */
+ tmp = g_byte_array_sized_new (strlen (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + strlen (path) + 1);
+ g_byte_array_append (tmp, (const guint8 *) NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, strlen (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH));
+ g_byte_array_append (tmp, (const guint8 *) path, strlen (path) + 1);
+ if (nm_setting_802_1x_check_cert_scheme (tmp->data, tmp->len, NULL) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+ g_free (path);
+ path = (char *) g_byte_array_free (tmp, FALSE);
+ /* when returning TRUE, we must also be sure that @data_len does not look like
+ * the deprecated format of list of integers. With this implementation that is the
+ * case, as long as @consider_exists is FALSE. */
success = TRUE;
+ } else
+ g_byte_array_unref (tmp);
- /* Warn if the certificate didn't exist */
- if (exists == FALSE)
- handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
- _("certificate or key '%s' does not exist"),
- path);
+out:
+ if (!success) {
+ g_free (path);
+ return NULL;
}
- g_free (path);
+ if (out_exists)
+ *out_exists = exists;
+ return path;
+}
+
+static gboolean
+handle_as_path (KeyfileReaderInfo *info,
+ GBytes *bytes,
+ NMSetting *setting,
+ const char *key)
+{
+ const guint8 *data;
+ gsize data_len;
+ char *path;
+ gboolean exists = FALSE;
+ GBytes *val;
- return success;
+ data = g_bytes_get_data (bytes, &data_len);
+
+ path = nm_keyfile_detect_unqualified_path_scheme (info->base_dir, data, data_len, TRUE, &exists);
+ if (!path)
+ return FALSE;
+
+ /* Construct the proper value as required for the PATH scheme */
+ val = g_bytes_new_take (path, strlen (path) + 1);
+ g_object_set (setting, key, val, NULL);
+
+ /* Warn if the certificate didn't exist */
+ if (!exists) {
+ handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE,
+ _("certificate or key file '%s' does not exist"),
+ path);
+ }
+ g_bytes_unref (val);
+
+ return TRUE;
}
static void
cert_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
const char *setting_name = nm_setting_get_name (setting);
- GBytes *bytes;
- gboolean success = FALSE;
+ gs_unref_bytes GBytes *bytes = NULL;
+ gsize bin_len;
+ const char *bin;
bytes = get_bytes (info, setting_name, key, TRUE, FALSE);
if (bytes) {
/* Try as a path + scheme (ie, starts with "file://") */
- success = handle_as_scheme (bytes, setting, key);
+ if (handle_as_scheme (info, bytes, setting, key))
+ return;
+ if (info->error)
+ return;
/* If not, it might be a plain path */
- if (success == FALSE)
- success = handle_as_path (info, bytes, setting, key);
+ if (handle_as_path (info, bytes, setting, key))
+ return;
if (info->error)
- goto out_error;
-
- /* If neither of those two, assume blob with certificate data */
- if (success == FALSE)
+ return;
+
+ bin = g_bytes_get_data (bytes, &bin_len);
+ if (nm_setting_802_1x_check_cert_scheme (bin, bin_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+ /* The blob probably starts with "file://" but contains invalid characters for a path.
+ * Setting the cert data will confuse NMSetting8021x.
+ * In fact, NMSetting8021x does not support setting such binary data, so just warn and
+ * continue. */
+ handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+ _("invalid key/cert value is not a valid blob"));
+ } else
g_object_set (setting, key, bytes, NULL);
} else if (!info->error) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("invalid key/cert value"));
}
-
-out_error:
- if (bytes)
- g_bytes_unref (bytes);
}
static void
#include "nm-setting-8021x.h"
#include "nm-utils.h"
+#include "gsystem-local-alloc.h"
#include "nm-glib-compat.h"
#include "nm-keyfile-internal.h"
#include "nm-keyfile-utils.h"
{ NULL },
};
+/**************************************************************************/
+
+static void
+cert_writer_default (NMConnection *connection,
+ GKeyFile *file,
+ NMKeyfileWriteTypeDataCert *cert_data)
+{
+ const char *setting_name = nm_setting_get_name (NM_SETTING (cert_data->setting));
+ NMSetting8021xCKScheme scheme;
+
+ scheme = cert_data->scheme_func (cert_data->setting);
+ if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+ const char *path;
+ char *path_free = NULL, *tmp;
+ gs_free char *base_dir = NULL;
+
+ path = cert_data->path_func (cert_data->setting);
+ g_assert (path);
+
+ /* If the path is relative, make it an absolute path.
+ * Relative paths make a keyfile not easily usable in another
+ * context. */
+ if (path[0] && path[0] != '/') {
+ base_dir = g_get_current_dir ();
+ path = path_free = g_strconcat (base_dir, "/", path, NULL);
+ } else
+ base_dir = g_path_get_dirname (path);
+
+ /* path cannot start with "file://" or "data:;base64,", because it is an absolute path.
+ * Still, make sure that a prefix-less path will be recognized. This can happen
+ * for example if the path is longer then 500 chars. */
+ tmp = nm_keyfile_detect_unqualified_path_scheme (base_dir, path, -1, FALSE, NULL);
+ if (tmp)
+ g_clear_pointer (&tmp, g_free);
+ else
+ path = tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL);
+
+ /* Path contains at least a '/', hence it cannot be recognized as the old
+ * binary format consisting of a list of integers. */
+
+ nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, path);
+ g_free (tmp);
+ g_free (path_free);
+ } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+ GBytes *blob;
+ const guint8 *blob_data;
+ gsize blob_len;
+ char *blob_base64, *val;
+
+ blob = cert_data->blob_func (cert_data->setting);
+ g_assert (blob);
+ blob_data = g_bytes_get_data (blob, &blob_len);
+
+ blob_base64 = g_base64_encode (blob_data, blob_len);
+ val = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB, blob_base64, NULL);
+
+ nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, val);
+ g_free (val);
+ g_free (blob_base64);
+ } else {
+ /* scheme_func() returns UNKNOWN in all other cases. The only valid case
+ * where a scheme is allowed to be UNKNOWN, is unsetting the value. In this
+ * case, we don't expect the writer to be called, because the default value
+ * will not be serialized.
+ * The only other reason for the scheme to be UNKNOWN is an invalid cert.
+ * But our connection verifies, so that cannot happen either. */
+ g_return_if_reached ();
+ }
+}
+
static void
cert_writer (KeyfileWriterInfo *info,
NMSetting *setting,
if (!objtype)
g_return_if_reached ();
- if (!info->handler)
- goto out_unhandled;
-
type_data.setting = NM_SETTING_802_1X (setting);
type_data.property_name = key;
type_data.suffix = objtype->suffix;
type_data.path_func = objtype->path_func;
type_data.blob_func = objtype->blob_func;
- if (info->handler (info->connection,
- info->keyfile,
- NM_KEYFILE_WRITE_TYPE_CERT,
- &type_data,
- info->user_data,
- &info->error))
- return;
-
-out_unhandled:
-
- /* scheme_func() would not return UNKNOWN, because UNKNOWN happens only
- * if the cert is unset (1) or if the cert is invalid (2).
- * (1) cannot happen, because we only reach cert_writer() for non-default
- * properties. (2) cannot happen, because we verified the connection.
- *
- * Hence, at this point we do have a certifiacte, but no default implementation
- * to write it. The handler *must* do something with these certifications. */
- if (!info->error) {
- g_set_error (&info->error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
- _("Failed to write unhandled certificate property %s.%s"),
- nm_setting_get_name (setting), key);
+ if (info->handler) {
+ if (info->handler (info->connection,
+ info->keyfile,
+ NM_KEYFILE_WRITE_TYPE_CERT,
+ &type_data,
+ info->user_data,
+ &info->error))
+ return;
+ if (info->error)
+ return;
}
+
+ cert_writer_default (info->connection, info->keyfile, &type_data);
}
+/**************************************************************************/
+
typedef struct {
const char *setting_name;
const char *key;
test-compare \
test-crypto \
test-general \
+ test-keyfile \
test-secrets \
test-setting-8021x \
test-setting-dcb \
certs/test-aes-key.pem \
certs/test_ca_cert.der \
certs/test_ca_cert.pem \
+ certs/test-ca-cert.pem \
certs/test-cert.p12 \
certs/test_key_and_cert.pem \
+ certs/test-key-and-cert.pem \
certs/test-key-only-decrypted.der \
certs/test-key-only-decrypted.pem \
certs/test-key-only.pem
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIEjzCCA3egAwIBAgIJAOvnZPt59yIZMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYD
+VQQGEwJVUzESMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcw
+FQYDVQQKEw5NeSBDb21wYW55IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UE
+AxMEdGVzdDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTAeFw0wOTAzMTAx
+NTEyMTRaFw0xOTAzMDgxNTEyMTRaMIGLMQswCQYDVQQGEwJVUzESMBAGA1UECBMJ
+QmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5NeSBDb21wYW55
+IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UEAxMEdGVzdDEcMBoGCSqGSIb3
+DQEJARYNdGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAKot9j+/+CX1/gZLgJHIXCRgCItKLGnf7qGbgqB9T2ACBqR0jllKWwDKrcWU
+xjXNIc+GF9Wnv+lX6G0Okn4Zt3/uRNobL+2b/yOF7M3Td3/9W873zdkQQX930YZc
+Rr8uxdRPP5bxiCgtcw632y21sSEbG9mjccAUnV/0jdvfmMNj0i8gN6E0fMBiJ9S3
+FkxX/KFvt9JWE9CtoyL7ki7UIDq+6vj7Gd5N0B3dOa1y+rRHZzKlJPcSXQSEYUS4
+HmKDwiKSVahft8c4tDn7KPi0vex91hlgZVd3usL2E/Vq7o5D9FAZ5kZY0AdFXwdm
+J4lO4Mj7ac7GE4vNERNcXVIX59sCAwEAAaOB8zCB8DAdBgNVHQ4EFgQUuDU3Mr7P
+T3n1e3Sy8hBauoDFahAwgcAGA1UdIwSBuDCBtYAUuDU3Mr7PT3n1e3Sy8hBauoDF
+ahChgZGkgY4wgYsxCzAJBgNVBAYTAlVTMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAO
+BgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMRAwDgYDVQQL
+EwdUZXN0aW5nMQ0wCwYDVQQDEwR0ZXN0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRl
+c3QuY29tggkA6+dk+3n3IhkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC
+AQEAVRG4aALIvCXCiKfe7K+iJxjBVRDFPEf7JWA9LGgbFOn6pNvbxonrR+0BETdc
+JV1ET4ct2xsE7QNFIkp9GKRC+6J32zCo8qtLCD5+v436r8TUG2/t2JRMkb9I2XVT
+p7RJoot6M0Ltf8KNQUPYh756xmKZ4USfQUwc58MOSDGY8VWEXJOYij9Pf0e0c52t
+qiCEjXH7uXiS8Pgq9TYm7AkWSOrglYhSa83x0f8mtT8Q15nBESIHZ6o8FAS2bBgn
+B0BkrKRjtBUkuJG3vTox+bYINh2Gxi1JZHWSV1tN5z3hd4VFcKqanW5OgQwToBqp
+3nniskIjbH0xjgZf/nVMyLnjxg==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,4DE0615F23D82107
+
+QPNCO5Dobvz9dDhN32KkZRoEifW+HDm2PCbRQhKDiscGwB6LgypvVjHNsZiFKwzz
+L4R51UqgQeJx7GSGJqE626e9z9J+UNBhop02aOO2X0eSPdvBzr/uJ6Umiyr1xqD7
+zWf7u9l5kXElDJRhK+87GMBewp4Ie9NeXDjhF8hzC5Kiulen4AH3AYnfH3S7DimU
+h8GFMg8inrudrTbcjBhCdPeHG2jCygOxw3InRFz7uaN6LIhOaPQvmvpP4Cc1WRnW
+ZPq9o+eU3fPWPD5t+Op/VzYLvKwgBy/yK1rQXUm6ZMO7MhhRJ94ZCsJv+nVWpJlv
+QyBlxDKxwfkfYbDELdnnDQdHdMbKatLqa0KhSkgpp8LywBtanPz731tyT0r7b3na
+eLdra59lRU7ZQLPEdS3lPZd2O/KQvWf8wbg7MjXS9LxQ7R5HOPu6DNJlwXVZBmmo
+cAfu2q8ubU2IePvWLD1GOrBi6hE9TiGvFJkw+wBK+t72sz3njv9Xm/zlxruaEk5m
+RW/kybU3FP4PtjriBbskz3/VZaaxuRN7OoOYTkmyHmG1ADgcRUV6fea19qqsBlN8
+xb+SRtoH28oT/JVWU5neE2dbNzk5LeVO+w70NNdR5s5xqkBhbGGaJxvXwNP4ltFr
+T06SMh8znOLKwWB00aRtwfU7jOwR3mOleQO4ugIHmau3zp1TqzAHW8XtpuV7qVeI
+ESZOZuf0vW43BtNzgLXt1+r+bmsMsRwhnyomL9M0TUyyBdVYY9GkzTG9pOESheRo
+RSvAZ8qKGUliTpgBcbt2v1+NqkszcHa6FxuvS8YU4uo5/GqsgTxHTNIB232hIrrZ
+EIm6QL9TC5oFXMjy6UNqoCm5Nb8DBJ6aErt7pt7aoktqUW3O3QIzQT3IbZ4nAcTt
+lVF4d7j29I9t7bcC8GOVU1neilguZUss4ghJg9x4zI5UZdR7hZ8fbFT47TyxB+j5
+r0YdmjbjVTaSyaN2JGh1wvb4TzawGNVx/U2EJE16HigOtPfsfQRJ3x+FROKBdVa4
+aIFYXkRBeIPxX6n9pcw0lBCsnXo6/5iTjQSk2VqO3rHO/wyWiEjNczhL33dY2A8W
+GG5ECMO5SqXZHQQzpABqK94dxe3UC8aEESO5NhEqDuV7qQGol0qPKrUA3wb0jb2e
+DrejJ9HS2m1SUDmjpvvmEGy6GN7CRibbKt5rNZdJNNvWArOF5d0F6wkixQLl73oE
+lq5gLQQk9n7ClleKLhlQpBCorxilBbzmSUekkJLi0eaZiBBFWBX9udqnUZloXTgO
+8qwuO8K/GPR9Jy1/UH2Vh1H+wivaqKTVgEb0NotzgzECgTEFKJafl7rUNs1OZRZ3
+VBjevi6+iDpxVFgF71kXfdUC4ph0E1XDl0ja2rrKQGivMkUhWJ57+4EV5+hBkAnt
+G0RV45NwHXLrK2bd8F9PlRk2XHW6mIcFRXsW1DjeBhk/sQjvlO9R01GRSgcXtekJ
+tmX17FWrMrzXHpvy1IC3fk4RVnSjpzQ8O+17YE8/la9wVaeZZzHyYFmMT7VXjIhW
+QozJQ0vJ2jxJRh5GYn3tpJzdaeRfvTBik0pChNdUTnWP+BJ35xoCTs8iwJbmgVZ1
+-----END RSA PRIVATE KEY-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: C=US, ST=Berkshire, L=Newbury, O=My Company Ltd, OU=Testing, CN=test/emailAddress=test@test.com
+ Validity
+ Not Before: Mar 10 15:13:16 2009 GMT
+ Not After : Mar 8 15:13:16 2019 GMT
+ Subject: C=US, ST=Berkshire, O=My Company Ltd, OU=Testing, CN=test1/emailAddress=test@test.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:cd:34:b1:2e:b0:04:c6:f4:2b:a2:c0:a0:39:7a:
+ 82:ed:96:c4:f7:19:83:91:5c:b4:e7:9c:de:ec:48:
+ ec:2d:e4:51:08:26:42:ac:d3:98:26:7a:72:f7:49:
+ c2:9e:66:05:c6:47:29:fe:3b:ac:6b:af:6f:5e:a8:
+ 03:5a:73:33:ba:19:03:00:35:f5:00:bc:a8:be:14:
+ ce:46:69:e3:6d:ed:34:37:85:55:87:62:b3:b7:c9:
+ c0:cc:9a:aa:61:05:5b:cd:a2:17:42:d3:e5:6f:1c:
+ 60:8d:c2:15:41:46:f8:12:54:d0:38:57:e1:fd:8d:
+ 44:c8:fb:56:b3:b9:6c:e9:f8:9e:21:11:57:1b:8b:
+ f9:cf:e3:17:e7:d8:fd:ac:d1:01:c6:92:30:f3:2d:
+ c9:d6:c1:f0:3d:fd:ca:30:dd:75:74:e7:d1:6b:75:
+ d8:c5:4d:43:61:fe:f6:ad:7e:4c:63:7c:03:17:a2:
+ 06:8f:d0:8b:69:d3:7a:07:0f:0b:a2:cf:0c:70:38:
+ ba:cc:55:35:60:84:58:d8:d2:be:1f:ef:76:a9:ba:
+ ae:6a:dc:08:97:80:de:42:00:b7:d4:ce:9a:b0:36:
+ 2a:c7:6f:45:04:7c:ea:41:19:d8:b9:19:04:1f:11:
+ a9:22:80:bd:69:08:15:0d:3c:de:cd:7e:88:6c:0f:
+ a3:43
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ CE:03:7E:EF:E7:DE:C9:87:BF:DE:56:F4:C8:A3:40:F6:C8:6F:05:8C
+ X509v3 Authority Key Identifier:
+ keyid:B8:35:37:32:BE:CF:4F:79:F5:7B:74:B2:F2:10:5A:BA:80:C5:6A:10
+ DirName:/C=US/ST=Berkshire/L=Newbury/O=My Company Ltd/OU=Testing/CN=test/emailAddress=test@test.com
+ serial:EB:E7:64:FB:79:F7:22:19
+
+ Signature Algorithm: md5WithRSAEncryption
+ 7a:20:93:63:40:73:7d:33:01:2e:c0:13:52:a4:a7:e1:4d:82:
+ f4:fb:b2:7b:d0:2b:5a:3f:0e:3c:28:61:71:ab:01:4d:fe:89:
+ b5:cd:2f:97:59:93:53:9d:51:86:48:dd:b9:e4:73:5e:22:0b:
+ 12:0d:25:39:76:16:44:06:0c:40:45:21:6b:a6:b1:e0:bf:76:
+ 1b:36:f3:1e:41:82:57:d9:59:b7:60:40:43:1c:1d:79:f6:48:
+ 32:5c:4e:e2:06:89:96:41:d2:54:1f:4a:6f:f6:78:a5:3c:02:
+ 85:21:e2:65:e1:8a:6d:24:19:95:f8:c0:35:ab:bd:ff:3d:f1:
+ fb:50:2d:30:1e:67:a6:7c:50:f9:d5:77:66:77:5a:14:0f:5c:
+ cd:21:09:9b:a3:92:57:19:dd:01:a4:18:c5:f9:70:e4:17:43:
+ 8d:b1:e6:61:e9:50:89:83:4f:ce:a4:57:68:58:40:70:ae:71:
+ 1c:47:66:d2:30:54:50:ea:3a:87:32:64:3b:18:42:fe:5a:19:
+ 07:64:f7:f1:b1:10:07:fd:a7:d2:a7:a8:05:79:5b:25:ba:69:
+ 7b:1a:3e:b1:3e:e4:17:17:01:ba:eb:54:ae:83:00:ed:66:62:
+ 8d:c0:3e:8a:b4:27:5f:e9:01:ce:20:c3:34:a9:28:c0:6f:c7:
+ 3b:65:fe:f9
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCVVMx
+EjAQBgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMO
+TXkgQ29tcGFueSBMdGQxEDAOBgNVBAsTB1Rlc3RpbmcxDTALBgNVBAMTBHRlc3Qx
+HDAaBgkqhkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wHhcNMDkwMzEwMTUxMzE2WhcN
+MTkwMzA4MTUxMzE2WjB6MQswCQYDVQQGEwJVUzESMBAGA1UECBMJQmVya3NoaXJl
+MRcwFQYDVQQKEw5NeSBDb21wYW55IEx0ZDEQMA4GA1UECxMHVGVzdGluZzEOMAwG
+A1UEAxMFdGVzdDExHDAaBgkqhkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNNLEusATG9CuiwKA5eoLtlsT3GYOR
+XLTnnN7sSOwt5FEIJkKs05gmenL3ScKeZgXGRyn+O6xrr29eqANaczO6GQMANfUA
+vKi+FM5GaeNt7TQ3hVWHYrO3ycDMmqphBVvNohdC0+VvHGCNwhVBRvgSVNA4V+H9
+jUTI+1azuWzp+J4hEVcbi/nP4xfn2P2s0QHGkjDzLcnWwfA9/cow3XV059FrddjF
+TUNh/vatfkxjfAMXogaP0Itp03oHDwuizwxwOLrMVTVghFjY0r4f73apuq5q3AiX
+gN5CALfUzpqwNirHb0UEfOpBGdi5GQQfEakigL1pCBUNPN7NfohsD6NDAgMBAAGj
+ggEfMIIBGzAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVy
+YXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUzgN+7+feyYe/3lb0yKNA9shvBYww
+gcAGA1UdIwSBuDCBtYAUuDU3Mr7PT3n1e3Sy8hBauoDFahChgZGkgY4wgYsxCzAJ
+BgNVBAYTAlVTMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkx
+FzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMRAwDgYDVQQLEwdUZXN0aW5nMQ0wCwYD
+VQQDEwR0ZXN0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tggkA6+dk+3n3
+IhkwDQYJKoZIhvcNAQEEBQADggEBAHogk2NAc30zAS7AE1Kkp+FNgvT7snvQK1o/
+DjwoYXGrAU3+ibXNL5dZk1OdUYZI3bnkc14iCxINJTl2FkQGDEBFIWumseC/dhs2
+8x5BglfZWbdgQEMcHXn2SDJcTuIGiZZB0lQfSm/2eKU8AoUh4mXhim0kGZX4wDWr
+vf898ftQLTAeZ6Z8UPnVd2Z3WhQPXM0hCZujklcZ3QGkGMX5cOQXQ42x5mHpUImD
+T86kV2hYQHCucRxHZtIwVFDqOocyZDsYQv5aGQdk9/GxEAf9p9KnqAV5WyW6aXsa
+PrE+5BcXAbrrVK6DAO1mYo3APoq0J1/pAc4gwzSpKMBvxztl/vk=
+-----END CERTIFICATE-----
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ *
+ * 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, 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 2015 Red Hat, Inc.
+ *
+ */
+
+#include "config.h"
+
+#include "nm-utils-internal.h"
+#include "nm-keyfile-utils.h"
+#include "nm-keyfile-internal.h"
+
+#include "nm-simple-connection.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-wired.h"
+#include "nm-setting-8021x.h"
+
+#include "nm-test-utils.h"
+
+
+#define TEST_WIRED_TLS_CA_CERT TEST_CERT_DIR"/test-ca-cert.pem"
+#define TEST_WIRED_TLS_PRIVKEY TEST_CERT_DIR"/test-key-and-cert.pem"
+
+
+/******************************************************************************/
+
+#define CLEAR(con, keyfile) \
+ G_STMT_START { \
+ NMConnection **_con = (con); \
+ GKeyFile **_keyfile = (keyfile); \
+ \
+ g_clear_object (_con); \
+ g_clear_pointer (_keyfile, g_key_file_unref); \
+ } G_STMT_END
+
+static void
+_assert_gbytes (GBytes *bytes, gconstpointer data, gssize len)
+{
+ g_assert ((data && len > 0) || !len || (data && len == -1));
+
+ if (len == -1)
+ len = strlen (data);
+
+ if (!len)
+ g_assert (!bytes);
+ else {
+ g_assert_cmpint (g_bytes_get_size (bytes), ==, len);
+ g_assert (memcmp (g_bytes_get_data (bytes, NULL), data, len) == 0);
+ }
+}
+
+static GKeyFile *
+_keyfile_load_from_data (const char *str)
+{
+ GError *error = NULL;
+ gboolean success;
+ GKeyFile *keyfile;
+
+ g_assert (str);
+
+ keyfile = g_key_file_new ();
+ success = g_key_file_load_from_data (keyfile, str, strlen (str), G_KEY_FILE_NONE, &error);
+ g_assert_no_error (error);
+ g_assert (success);
+
+ return keyfile;
+}
+
+static gboolean
+_keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b)
+{
+ gs_strfreev char **groups = NULL;
+ guint i, j;
+
+ if (kf_a == kf_b)
+ return TRUE;
+
+ groups = g_key_file_get_groups (kf_a, NULL);
+ for (i = 0; groups && groups[i]; i++) {
+ gs_strfreev char **keys = NULL;
+
+ keys = g_key_file_get_keys (kf_a, groups[i], NULL, NULL);
+ if (keys) {
+ for (j = 0; keys[j]; j++) {
+ gs_free char *key_a = g_key_file_get_value (kf_a, groups[i], keys[j], NULL);
+ gs_free char *key_b = g_key_file_get_value (kf_b, groups[i], keys[j], NULL);
+
+ if (g_strcmp0 (key_a, key_b) != 0)
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+_keyfile_equals (GKeyFile *kf_a, GKeyFile *kf_b)
+{
+ return _keyfile_a_contains_all_in_b (kf_a, kf_b) && _keyfile_a_contains_all_in_b (kf_b, kf_a);
+}
+
+static void
+_keyfile_convert (NMConnection **con,
+ GKeyFile **keyfile,
+ const char *keyfile_name,
+ const char *base_dir,
+ NMKeyfileReadHandler read_handler,
+ void *read_data,
+ NMKeyfileWriteHandler write_handler,
+ void *write_data,
+ gboolean needs_normalization)
+{
+ NMConnection *c, *c2;
+ GKeyFile *k, *k2;
+ GError *error = NULL;
+ NMSetting8021x *s1, *s2;
+
+ /* convert from @con to @keyfile and check that we can make
+ * full round trips and obtaining the same result. */
+
+ g_assert (con);
+ g_assert (keyfile);
+ g_assert (*con || *keyfile);
+
+ if (!*keyfile) {
+ k = nm_keyfile_write (*con, write_handler, read_data, &error);
+ g_assert_no_error (error);
+ g_assert (k);
+ *keyfile = k;
+ } else
+ k = *keyfile;
+ if (!*con) {
+ c = nm_keyfile_read (*keyfile, keyfile_name, base_dir, read_handler, read_data, &error);
+ g_assert_no_error (error);
+ g_assert (c);
+ if (needs_normalization)
+ nmtst_assert_connection_verifies_after_normalization (c, 0, 0);
+ else
+ nmtst_assert_connection_verifies_without_normalization (c);
+ *con = c;
+ } else
+ c = *con;
+
+ k2 = nm_keyfile_write (c, write_handler, read_data, &error);
+ g_assert_no_error (error);
+ g_assert (k2);
+
+ c2 = nm_keyfile_read (k, keyfile_name, base_dir, read_handler, read_data, &error);
+ g_assert_no_error (error);
+ g_assert (c2);
+ if (needs_normalization)
+ nmtst_assert_connection_verifies_after_normalization (c2, 0, 0);
+ else
+ nmtst_assert_connection_verifies_without_normalization (c2);
+
+ s1 = nm_connection_get_setting_802_1x (*con);
+ s2 = nm_connection_get_setting_802_1x (c2);
+ if (s1 || s2) {
+ g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s1), ==, nm_setting_802_1x_get_ca_cert_scheme (s2));
+ switch (nm_setting_802_1x_get_ca_cert_scheme (s1)) {
+ case NM_SETTING_802_1X_CK_SCHEME_PATH:
+ nmtst_assert_resolve_relative_path_equals (nm_setting_802_1x_get_ca_cert_path (s1), nm_setting_802_1x_get_ca_cert_path (s2));
+ break;
+ case NM_SETTING_802_1X_CK_SCHEME_BLOB: {
+ GBytes *b1, *b2;
+
+ b1 = nm_setting_802_1x_get_ca_cert_blob (s1);
+ b2 = nm_setting_802_1x_get_ca_cert_blob (s2);
+ g_assert_cmpint (g_bytes_get_size (b1), ==, g_bytes_get_size (b2));
+ g_assert (memcmp (g_bytes_get_data (b1, NULL), g_bytes_get_data (b2, NULL), g_bytes_get_size (b1)) == 0);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ nmtst_assert_connection_equals (c2, FALSE, *con, FALSE);
+ _keyfile_equals (k2, *keyfile);
+
+ g_object_unref (c2);
+ g_key_file_unref (k2);
+}
+
+/******************************************************************************/
+
+static void
+_test_8021x_cert_check (NMConnection *con,
+ NMSetting8021xCKScheme expected_scheme,
+ const void *value,
+ gssize val_len)
+{
+ GKeyFile *keyfile = NULL;
+ NMSetting8021x *s_8021x;
+ gs_free char *kval = NULL;
+
+ _keyfile_convert (&con, &keyfile, NULL, NULL, NULL, NULL, NULL, NULL, FALSE);
+
+ s_8021x = nm_connection_get_setting_802_1x (con);
+
+ g_assert (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == expected_scheme);
+
+ if (expected_scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+ const char *path = nm_setting_802_1x_get_ca_cert_path (s_8021x);
+
+ g_assert_cmpstr (path, ==, value);
+ g_assert (val_len == -1 || strlen (path) == val_len);
+
+ kval = g_key_file_get_string (keyfile, "802-1x", "ca-cert", NULL);
+ g_assert (kval);
+ g_assert_cmpstr (kval, ==, value);
+ } else if (expected_scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+ GBytes *blob = nm_setting_802_1x_get_ca_cert_blob (s_8021x);
+ gs_free char *file_blob = NULL;
+
+ if (val_len == -1) {
+ gsize l;
+ gboolean success;
+
+ success = g_file_get_contents (value, &file_blob, &l, NULL);
+ g_assert (success);
+
+ value = file_blob;
+ val_len = l;
+ }
+
+ g_assert (blob);
+ g_assert_cmpint (g_bytes_get_size (blob), ==, val_len);
+ g_assert (!memcmp (g_bytes_get_data (blob, NULL), value, val_len));
+
+ kval = g_key_file_get_string (keyfile, "802-1x", "ca-cert", NULL);
+ g_assert (kval);
+ g_assert (g_str_has_prefix (kval, NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB));
+ }
+
+ g_key_file_unref (keyfile);
+}
+
+static void
+_test_8021x_cert_check_blob_full (NMConnection *con, const void *data, gsize len)
+{
+ GBytes *bytes;
+ NMSetting8021x *s_8021x = nm_connection_get_setting_802_1x (con);
+
+ bytes = g_bytes_new (data, len);
+ g_object_set (s_8021x,
+ NM_SETTING_802_1X_CA_CERT,
+ bytes,
+ NULL);
+ _test_8021x_cert_check (con, NM_SETTING_802_1X_CK_SCHEME_BLOB, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
+ g_bytes_unref (bytes);
+}
+#define _test_8021x_cert_check_blob(con, data) _test_8021x_cert_check_blob_full(con, data, STRLEN (data))
+
+static void
+test_8021x_cert (void)
+{
+ NMSetting8021x *s_8021x;
+ gs_unref_object NMConnection *con = nmtst_create_minimal_connection ("test-cert", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
+ GError *error = NULL;
+ gboolean success;
+ NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
+ gs_free char *full_TEST_WIRED_TLS_CA_CERT = nmtst_file_resolve_relative_path (TEST_WIRED_TLS_CA_CERT, NULL);
+ gs_free char *full_TEST_WIRED_TLS_PRIVKEY = nmtst_file_resolve_relative_path (TEST_WIRED_TLS_PRIVKEY, NULL);
+
+ /* test writing/reading of certificates of NMSetting8021x */
+
+ /* create a valid connection with NMSetting8021x */
+ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+ nm_setting_802_1x_add_eap_method (s_8021x, "tls");
+ g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL);
+ success = nm_setting_802_1x_set_ca_cert (s_8021x,
+ full_TEST_WIRED_TLS_CA_CERT,
+ scheme,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (success);
+ success = nm_setting_802_1x_set_client_cert (s_8021x,
+ full_TEST_WIRED_TLS_CA_CERT,
+ scheme,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (success);
+ success = nm_setting_802_1x_set_private_key (s_8021x,
+ full_TEST_WIRED_TLS_PRIVKEY,
+ "test1",
+ scheme,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (success);
+
+
+ /* test reseting ca-cert to different values and see whether we can write/read. */
+
+ nm_connection_add_setting (con, NM_SETTING (s_8021x));
+ nmtst_assert_connection_verifies_and_normalizable (con);
+
+
+ _test_8021x_cert_check (con, scheme, full_TEST_WIRED_TLS_CA_CERT, -1);
+
+ scheme = NM_SETTING_802_1X_CK_SCHEME_BLOB;
+ success = nm_setting_802_1x_set_ca_cert (s_8021x,
+ full_TEST_WIRED_TLS_CA_CERT,
+ scheme,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (success);
+ _test_8021x_cert_check (con, scheme, full_TEST_WIRED_TLS_CA_CERT, -1);
+
+ _test_8021x_cert_check_blob (con, "a");
+ _test_8021x_cert_check_blob (con, "\0");
+ _test_8021x_cert_check_blob (con, "10");
+ _test_8021x_cert_check_blob (con, "data:;base64,a");
+ _test_8021x_cert_check_blob_full (con, "data:;base64,a", STRLEN ("data:;base64,a") + 1);
+ _test_8021x_cert_check_blob (con, "data:;base64,file://a");
+ _test_8021x_cert_check_blob (con, "123");
+
+}
+
+/******************************************************************************/
+
+static void
+test_8021x_cert_read (void)
+{
+ GKeyFile *keyfile = NULL;
+ gs_unref_object NMConnection *con = NULL;
+ NMSetting8021x *s_8021x;
+
+ keyfile = _keyfile_load_from_data (
+ "[connection]\n"
+ "type=ethernet"
+ );
+ _keyfile_convert (&con, &keyfile, "/test_8021x_cert_read/test1", NULL, NULL, NULL, NULL, NULL, TRUE);
+ CLEAR (&con, &keyfile);
+
+ keyfile = _keyfile_load_from_data (
+ "[connection]\n"
+ "type=802-3-ethernet\n"
+
+ "[802-1x]\n"
+ "eap=tls;\n"
+ "identity=Bill Smith\n"
+ "ca-cert=48;130;2;52;48;130;1;161;2;16;2;173;102;126;78;69;254;94;87;111;60;152;25;94;221;192;48;13;6;9;42;134;72;134;247;13;1;1;2;5;0;48;95;49;11;48;9;6;3;85;4;6;19;2;85;83;49;32;48;30;6;3;85;4;10;19;23;82;83;65;32;68;97;116;97;32;83;101;99;117;114;105;116;121;44;32;73;110;99;46;49;46;48;44;6;3;85;4;11;19;37;83;101;99;117;114;101;32;83;101;114;118;101;114;32;67;101;114;116;105;102;105;99;97;116;105;111;110;32;65;117;116;104;111;114;105;116;121;48;30;23;13;57;52;49;49;48;57;48;48;48;48;48;48;90;23;13;49;48;48;49;48;55;50;51;53;57;53;57;90;48;95;49;11;48;9;6;3;85;4;6;19;2;85;83;49;32;48;30;6;3;85;4;10;19;23;82;83;65;32;68;97;116;97;32;83;101;99;117;114;105;116;121;44;32;73;110;99;46;49;46;48;44;6;3;85;4;11;19;37;83;101;99;117;114;101;32;83;101;114;118;101;114;32;67;101;114;116;105;102;105;99;97;116;105;111;110;32;65;117;116;104;111;114;105;116;121;48;129;155;48;13;6;9;42;134;72;134;247;13;1;1;1;5;0;3;129;137;0;48;129;133;2;126;0;146;206;122;193;174;131;62;90;170;137;131;87;172;37;1;118;12;173;174;142;44;55;206;235;53;120;100;84;3;229;132;64;81;201;191;143;8;226;138;130;8;210;22;134;55;85;233;177;33;2;173;118;104;129;154;5;162;75;201;75;37;102;34;86;108;136;7;143;247;129;89;109;132;7;101;112;19;113;118;62;155;119;76;227;80;137;86;152;72;185;29;167;41;26;19;46;74;17;89;156;30;21;213;73;84;44;115;58;105;130;177;151;57;156;109;112;103;72;229;221;45;214;200;30;123;2;3;1;0;1;48;13;6;9;42;134;72;134;247;13;1;1;2;5;0;3;126;0;101;221;126;225;178;236;176;226;58;224;236;113;70;154;25;17;184;211;199;160;180;3;64;38;2;62;9;156;225;18;179;209;90;246;55;165;183;97;3;182;91;22;105;59;198;68;8;12;136;83;12;107;151;73;199;62;53;220;108;185;187;170;223;92;187;58;47;147;96;182;169;75;77;242;32;247;205;95;127;100;123;142;220;0;92;215;250;119;202;57;22;89;111;14;234;211;181;131;127;77;77;66;86;118;180;201;95;4;248;56;248;235;210;95;117;95;205;123;252;229;142;128;124;252;80;\n"
+ "client-cert=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;\n"
+ "private-key=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;\n"
+ "private-key-password=12345testing\n"
+ );
+ _keyfile_convert (&con, &keyfile, "/test_8021x_cert_read/test2", NULL, NULL, NULL, NULL, NULL, TRUE);
+ CLEAR (&con, &keyfile);
+
+
+ keyfile = _keyfile_load_from_data (
+ "[connection]\n"
+ "type=802-3-ethernet\n"
+
+ "[802-1x]\n"
+ "eap=tls;\n"
+ "identity=Bill Smith\n"
+ /* unqualified strings are only recognized as path up to 500 chars*/
+ "ca-cert=" "/111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
+ "/111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
+ "/111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
+ "/111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
+ "/11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
+ "client-cert=/222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221"
+ "/222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221"
+ "/222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221"
+ "/222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221"
+ "/222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
+ "private-key=file://"
+ "/333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333331"
+ "/333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333331"
+ "/333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333331"
+ "/333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333331"
+ "/33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333111111\n"
+ "private-key-password=12345testing\n"
+ );
+ _keyfile_convert (&con, &keyfile, "/test_8021x_cert_read/test2", NULL, NULL, NULL, NULL, NULL, TRUE);
+ s_8021x = nm_connection_get_setting_802_1x (con);
+
+ g_assert (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
+ g_assert (g_str_has_prefix (nm_setting_802_1x_get_ca_cert_path (s_8021x), "/111111111111"));
+ g_assert_cmpint (strlen (nm_setting_802_1x_get_ca_cert_path (s_8021x)), ==, 499);
+
+ g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB);
+ g_assert (g_str_has_prefix (g_bytes_get_data (nm_setting_802_1x_get_client_cert_blob (s_8021x), NULL), "/2222222222"));
+ g_assert_cmpint (g_bytes_get_size (nm_setting_802_1x_get_client_cert_blob (s_8021x)), ==, 500 + 1 /* keyfile reader adds a trailing NUL */);
+
+ g_assert (nm_setting_802_1x_get_private_key_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
+ g_assert (g_str_has_prefix (nm_setting_802_1x_get_private_key_path (s_8021x), "/333333333"));
+ g_assert_cmpint (strlen (nm_setting_802_1x_get_private_key_path (s_8021x)), ==, 505);
+ CLEAR (&con, &keyfile);
+
+
+ keyfile = _keyfile_load_from_data (
+ "[connection]\n"
+ "type=802-3-ethernet\n"
+
+ "[802-1x]\n"
+ "eap=tls;\n"
+ "identity=Bill Smith\n"
+ "ca-cert=/\n"
+ "client-cert=a.pem\n"
+ "private-key=data:;base64,aGFsbG8=\n" // hallo
+ "private-key-password=12345testing\n"
+ );
+ _keyfile_convert (&con, &keyfile, "/test_8021x_cert_read/test2", NULL, NULL, NULL, NULL, NULL, TRUE);
+ s_8021x = nm_connection_get_setting_802_1x (con);
+
+ g_assert (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
+ g_assert_cmpstr (nm_setting_802_1x_get_ca_cert_path (s_8021x), ==, "/");
+
+ g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
+ g_assert_cmpstr (nm_setting_802_1x_get_client_cert_path (s_8021x), ==, "/test_8021x_cert_read/a.pem");
+
+ g_assert (nm_setting_802_1x_get_private_key_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB);
+ _assert_gbytes (nm_setting_802_1x_get_private_key_blob (s_8021x), "hallo", -1);
+ CLEAR (&con, &keyfile);
+
+
+ keyfile = _keyfile_load_from_data (
+ "[connection]\n"
+ "type=802-3-ethernet\n"
+
+ "[802-1x]\n"
+ "eap=tls;\n"
+ "identity=Bill Smith\n"
+ "ca-cert=file://data:;base64,x\n"
+ "client-cert=abc.der\n"
+ "private-key=abc.deR\n"
+ "private-key-password=12345testing\n"
+ );
+ _keyfile_convert (&con, &keyfile, "/test_8021x_cert_read/test2", NULL, NULL, NULL, NULL, NULL, TRUE);
+ s_8021x = nm_connection_get_setting_802_1x (con);
+
+ g_assert (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
+ g_assert_cmpstr (nm_setting_802_1x_get_ca_cert_path (s_8021x), ==, "data:;base64,x");
+
+ g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
+ g_assert_cmpstr (nm_setting_802_1x_get_client_cert_path (s_8021x), ==, "/test_8021x_cert_read/abc.der");
+
+ g_assert (nm_setting_802_1x_get_private_key_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB);
+ _assert_gbytes (nm_setting_802_1x_get_private_key_blob (s_8021x), "abc.deR\0", 8);
+ CLEAR (&con, &keyfile);
+
+
+ keyfile = _keyfile_load_from_data (
+ "[connection]\n"
+ "type=802-3-ethernet\n"
+
+ "[802-1x]\n"
+ "eap=tls;\n"
+ "identity=Bill Smith\n"
+ "ca-cert=104;97;108;108;111;\n" /* "hallo" without trailing NUL */
+ "client-cert=104;097;108;108;111;0;\n"
+ "private-key=hallo\n"
+ "private-key-password=12345testing\n"
+ );
+ _keyfile_convert (&con, &keyfile, "/test_8021x_cert_read/test2", NULL, NULL, NULL, NULL, NULL, TRUE);
+ s_8021x = nm_connection_get_setting_802_1x (con);
+
+ g_assert (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB);
+ _assert_gbytes (nm_setting_802_1x_get_ca_cert_blob (s_8021x), "hallo", 5);
+
+ g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB);
+ _assert_gbytes (nm_setting_802_1x_get_client_cert_blob (s_8021x), "hallo\0", 6);
+
+ g_assert (nm_setting_802_1x_get_private_key_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_BLOB);
+ _assert_gbytes (nm_setting_802_1x_get_private_key_blob (s_8021x), "hallo\0", 6);
+ CLEAR (&con, &keyfile);
+}
+
+/******************************************************************************/
+
+NMTST_DEFINE ();
+
+int main (int argc, char **argv)
+{
+ nmtst_init (&argc, &argv, TRUE);
+
+ g_test_add_func ("/core/keyfile/test_8021x_cert", test_8021x_cert);
+ g_test_add_func ("/core/keyfile/test_8021x_cert_read", test_8021x_cert_read);
+
+ return g_test_run ();
+}
+
level = LOGL_ERR;
else if (warn_data->severity >= NM_KEYFILE_WARN_SEVERITY_WARN)
level = LOGL_WARN;
+ else if (warn_data->severity == NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE)
+ level = LOGL_WARN;
else
level = LOGL_INFO;
eap=tls;
identity=Bill Smith
ca-cert=48;130;2;52;48;130;1;161;2;16;2;173;102;126;78;69;254;94;87;111;60;152;25;94;221;192;48;13;6;9;42;134;72;134;247;13;1;1;2;5;0;48;95;49;11;48;9;6;3;85;4;6;19;2;85;83;49;32;48;30;6;3;85;4;10;19;23;82;83;65;32;68;97;116;97;32;83;101;99;117;114;105;116;121;44;32;73;110;99;46;49;46;48;44;6;3;85;4;11;19;37;83;101;99;117;114;101;32;83;101;114;118;101;114;32;67;101;114;116;105;102;105;99;97;116;105;111;110;32;65;117;116;104;111;114;105;116;121;48;30;23;13;57;52;49;49;48;57;48;48;48;48;48;48;90;23;13;49;48;48;49;48;55;50;51;53;57;53;57;90;48;95;49;11;48;9;6;3;85;4;6;19;2;85;83;49;32;48;30;6;3;85;4;10;19;23;82;83;65;32;68;97;116;97;32;83;101;99;117;114;105;116;121;44;32;73;110;99;46;49;46;48;44;6;3;85;4;11;19;37;83;101;99;117;114;101;32;83;101;114;118;101;114;32;67;101;114;116;105;102;105;99;97;116;105;111;110;32;65;117;116;104;111;114;105;116;121;48;129;155;48;13;6;9;42;134;72;134;247;13;1;1;1;5;0;3;129;137;0;48;129;133;2;126;0;146;206;122;193;174;131;62;90;170;137;131;87;172;37;1;118;12;173;174;142;44;55;206;235;53;120;100;84;3;229;132;64;81;201;191;143;8;226;138;130;8;210;22;134;55;85;233;177;33;2;173;118;104;129;154;5;162;75;201;75;37;102;34;86;108;136;7;143;247;129;89;109;132;7;101;112;19;113;118;62;155;119;76;227;80;137;86;152;72;185;29;167;41;26;19;46;74;17;89;156;30;21;213;73;84;44;115;58;105;130;177;151;57;156;109;112;103;72;229;221;45;214;200;30;123;2;3;1;0;1;48;13;6;9;42;134;72;134;247;13;1;1;2;5;0;3;126;0;101;221;126;225;178;236;176;226;58;224;236;113;70;154;25;17;184;211;199;160;180;3;64;38;2;62;9;156;225;18;179;209;90;246;55;165;183;97;3;182;91;22;105;59;198;68;8;12;136;83;12;107;151;73;199;62;53;220;108;185;187;170;223;92;187;58;47;147;96;182;169;75;77;242;32;247;205;95;127;100;123;142;220;0;92;215;250;119;202;57;22;89;111;14;234;211;181;131;127;77;77;66;86;118;180;201;95;4;248;56;248;235;210;95;117;95;205;123;252;229;142;128;124;252;80;
-client-cert=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
-private-key=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
+client-cert=102;105;108;101;58;47;47;47;67;65;83;65;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
+private-key=102;105;108;101;58;47;47;47;67;65;83;65;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
private-key-password=12345testing
[ipv4]
[802-1x]
eap=tls;
identity=Bill Smith
-ca-cert=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;67;65;47;101;97;112;116;101;115;116;95;99;97;95;99;101;114;116;46;112;101;109;0;
-client-cert=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
-private-key=102;105;108;101;58;47;47;47;104;111;109;101;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
+ca-cert=102;105;108;101;58;47;47;47;67;65;83;65;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;67;65;47;101;97;112;116;101;115;116;95;99;97;95;99;101;114;116;46;112;101;109;0;
+client-cert=102;105;108;101;58;47;47;47;67;65;83;65;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
+private-key=102;105;108;101;58;47;47;47;67;65;83;65;47;100;99;98;119;47;68;101;115;107;116;111;112;47;99;101;114;116;105;110;102;114;97;47;99;108;105;101;110;116;46;112;101;109;0;
private-key-password=12345testing
[ipv4]
gboolean success;
GBytes *blob;
+ g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
+ "*<warn> keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
+ g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
+ "*<warn> keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_TLS_BLOB_FILE, &error);
if (connection == NULL) {
g_assert (error);
g_assert_cmpint (g_bytes_get_size (blob), ==, 568);
tmp = nm_setting_802_1x_get_client_cert_path (s_8021x);
- g_assert_cmpstr (tmp, ==, "/home/dcbw/Desktop/certinfra/client.pem");
+ g_assert_cmpstr (tmp, ==, "/CASA/dcbw/Desktop/certinfra/client.pem");
tmp = nm_setting_802_1x_get_private_key_path (s_8021x);
- g_assert_cmpstr (tmp, ==, "/home/dcbw/Desktop/certinfra/client.pem");
+ g_assert_cmpstr (tmp, ==, "/CASA/dcbw/Desktop/certinfra/client.pem");
g_object_unref (connection);
}
const char *tmp;
gboolean success;
+ g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
+ "*<warn> keyfile: 802-1x.ca-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem' does not exist*");
+ g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
+ "*<warn> keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
+ g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING,
+ "*<warn> keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_TLS_OLD_FILE, &error);
if (connection == NULL) {
g_assert (error);
g_assert (g_strcmp0 (tmp, "12345testing") == 0);
tmp = nm_setting_802_1x_get_ca_cert_path (s_8021x);
- g_assert (g_strcmp0 (tmp, "/home/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem") == 0);
+ g_assert (g_strcmp0 (tmp, "/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem") == 0);
tmp = nm_setting_802_1x_get_client_cert_path (s_8021x);
- g_assert (g_strcmp0 (tmp, "/home/dcbw/Desktop/certinfra/client.pem") == 0);
+ g_assert (g_strcmp0 (tmp, "/CASA/dcbw/Desktop/certinfra/client.pem") == 0);
tmp = nm_setting_802_1x_get_private_key_path (s_8021x);
- g_assert (g_strcmp0 (tmp, "/home/dcbw/Desktop/certinfra/client.pem") == 0);
+ g_assert (g_strcmp0 (tmp, "/CASA/dcbw/Desktop/certinfra/client.pem") == 0);
g_object_unref (connection);
}
scheme = cert_data->scheme_func (cert_data->setting);
if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+ char *tmp = NULL;
+ const char *accepted_path = NULL;
+
path = cert_data->path_func (cert_data->setting);
g_assert (path);
- /* If the path is rooted in the keyfile directory, just use a
- * relative path instead of an absolute one.
- */
if (g_str_has_prefix (path, info->keyfile_dir)) {
const char *p = path + strlen (info->keyfile_dir);
+ /* If the path is rooted in the keyfile directory, just use a
+ * relative path instead of an absolute one.
+ */
if (*p == '/') {
while (*p == '/')
p++;
- if (p[0])
- path = p;
+ if (p[0]) {
+ /* If @p looks like an integer list, the following detection will fail too and
+ * we will file:// qualify the path below. We thus avoid writing a path string
+ * that would be interpreted as legacy binary format by reader. */
+ tmp = nm_keyfile_detect_unqualified_path_scheme (info->keyfile_dir, p, -1, FALSE, NULL);
+ if (tmp) {
+ g_clear_pointer (&tmp, g_free);
+ accepted_path = p;
+ }
+ }
+ }
+ }
+ if (!accepted_path) {
+ /* What we are about to write, must also be understood by the reader.
+ * Otherwise, add a file:// prefix */
+ tmp = nm_keyfile_detect_unqualified_path_scheme (info->keyfile_dir, path, -1, FALSE, NULL);
+ if (tmp) {
+ g_clear_pointer (&tmp, g_free);
+ accepted_path = path;
}
}
- nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, path);
+ if (!accepted_path)
+ accepted_path = tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL);
+ nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, accepted_path);
+ g_free (tmp);
} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
GBytes *blob;
const guint8 *blob_data;
success = write_cert_key_file (new_path, blob_data, blob_len, &local);
if (success) {
- /* Write the path value to the keyfile */
- nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, new_path);
+ /* Write the path value to the keyfile.
+ * We know, that basename(new_path) starts with a UUID, hence no conflict with "data:;base64," */
+ nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, strrchr (new_path, '/') + 1);
} else {
nm_log_warn (LOGD_SETTINGS, "keyfile: %s.%s: failed to write certificate to file %s: %s",
setting_name, cert_data->property_name, new_path, local->message);