From fa5a6caf2b70ac0071a09646d7ddc5f8e6df5e6a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 26 Feb 2015 01:48:50 +0100 Subject: [PATCH] libnm: ensure valid blob for nm_setting_802_1x_set_*_cert() A valid blob cannot start with "file://", otherwise it would break the implementation of the certificate properties in NMSetting8021x. Simply reject every blob in nm_setting_802_1x_set_ca_cert() et al. that is not valid according to get_cert_scheme(). (cherry picked from commit cda7b158e2b87fc4a397334c50448ecb9d2457c2) --- libnm-core/nm-setting-8021x.c | 41 +++++++++++++++++++++++++++++++---- libnm-util/nm-setting-8021x.c | 36 ++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c index a83c24c30c..259eea7cfc 100644 --- a/libnm-core/nm-setting-8021x.c +++ b/libnm-core/nm-setting-8021x.c @@ -32,6 +32,7 @@ #include "nm-setting-private.h" #include "nm-core-enum-types.h" #include "nm-macros-internal.h" +#include "gsystem-local-alloc.h" /** * SECTION:nm-setting-8021x @@ -463,6 +464,38 @@ get_cert_scheme (GBytes *bytes, GError **error) 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) { + /* the array is empty or the format is already 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. */ + GBytes *bytes = g_bytes_new_static (array->data, array->len); + + if (get_cert_scheme (bytes, NULL) != NM_SETTING_802_1X_CK_SCHEME_BLOB) + format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + g_bytes_unref (bytes); + } + + if (out_file_format) + *out_file_format = format; + return array; +} + /** * nm_setting_802_1x_get_ca_cert_scheme: * @setting: the #NMSetting8021x @@ -602,7 +635,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) { @@ -916,7 +949,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; @@ -1181,7 +1214,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) { @@ -1499,7 +1532,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; diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c index f5ab1bf9c1..ea141c65d7 100644 --- a/libnm-util/nm-setting-8021x.c +++ b/libnm-util/nm-setting-8021x.c @@ -449,6 +449,34 @@ get_cert_scheme (GByteArray *array) 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 @@ -590,7 +618,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) { @@ -906,7 +934,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; @@ -1171,7 +1199,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) { @@ -1491,7 +1519,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;