summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-09-04 07:39:52 +0200
committerThomas Haller <thaller@redhat.com>2018-09-04 07:39:52 +0200
commit4b5680898f41947d26bccb2023010d7b05d1a240 (patch)
tree0cdd78512da4d61ef4ac9efe2b507ce85944b67a
parent5ef81dc0fbbe41b85abe7929563d41b03eaf6989 (diff)
parente3ac45c026104e05c6fda802131c92457720c119 (diff)
downloadNetworkManager-4b5680898f41947d26bccb2023010d7b05d1a240.tar.gz
crypto: merge branch 'th/crypto-secrets'
https://github.com/NetworkManager/NetworkManager/pull/191
-rw-r--r--.travis.yml13
-rw-r--r--Makefile.am82
-rw-r--r--config.h.meson12
-rw-r--r--configure.ac41
-rw-r--r--docs/libnm/Makefile.am3
-rw-r--r--docs/libnm/meson.build3
-rw-r--r--libnm-core/crypto.c826
-rw-r--r--libnm-core/crypto.h137
-rw-r--r--libnm-core/meson.build31
-rw-r--r--libnm-core/nm-core-internal.h22
-rw-r--r--libnm-core/nm-crypto-gnutls.c (renamed from libnm-core/crypto_gnutls.c)317
-rw-r--r--libnm-core/nm-crypto-impl.h74
-rw-r--r--libnm-core/nm-crypto-nss.c (renamed from libnm-core/crypto_nss.c)368
-rw-r--r--libnm-core/nm-crypto.c1035
-rw-r--r--libnm-core/nm-crypto.h125
-rw-r--r--libnm-core/nm-keyfile.c74
-rw-r--r--libnm-core/nm-setting-8021x.c2740
-rw-r--r--libnm-core/nm-setting-vpn.c2
-rw-r--r--libnm-core/nm-utils.c156
-rw-r--r--libnm-core/tests/test-crypto.c109
-rw-r--r--libnm-core/tests/test-setting.c4
-rw-r--r--libnm-util/crypto_nss.c15
-rw-r--r--libnm/nm-vpn-service-plugin.c1
-rw-r--r--meson.build13
-rw-r--r--po/POTFILES.in6
-rw-r--r--shared/meson.build2
-rw-r--r--shared/nm-utils/nm-io-utils.c430
-rw-r--r--shared/nm-utils/nm-io-utils.h63
-rw-r--r--shared/nm-utils/nm-macros-internal.h41
-rw-r--r--shared/nm-utils/nm-secret-utils.c134
-rw-r--r--shared/nm-utils/nm-secret-utils.h151
-rw-r--r--shared/nm-utils/nm-shared-utils.h46
-rw-r--r--src/nm-core-utils.c362
-rw-r--r--src/nm-core-utils.h20
-rw-r--r--src/platform/nm-linux-platform.c13
-rw-r--r--src/platform/tests/test-link.c15
-rw-r--r--src/settings/plugins/ifcfg-rh/meson.build1
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c687
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c1
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c6
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.c2
42 files changed, 4274 insertions, 3911 deletions
diff --git a/.travis.yml b/.travis.yml
index bba6844210..c5108aee11 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -79,6 +79,11 @@ before_install:
script:
- |
if test "$BUILD_TYPE" == 'meson'; then
+ if [ "$CC" == gcc ]; then
+ CRYPTO=nss
+ else
+ CRYPTO=gnutls
+ fi &&
meson build \
\
-D ld_gc=false \
@@ -91,6 +96,7 @@ script:
-D vapi=false \
-D introspection=false \
-D qt=false \
+ -D crypto=$CRYPTO \
\
-D docs=true \
\
@@ -103,11 +109,16 @@ script:
fi
- |
if test "$BUILD_TYPE" == 'autotools'; then
+ if [ "$CC" == gcc ]; then
+ CRYPTO=gnutls
+ else
+ CRYPTO=nss
+ fi &&
git clean -fdx &&
NOCONFIGURE=1 ./autogen.sh &&
mkdir ./build &&
pushd ./build &&
- ../configure --prefix="$PWD/INST" --with-systemd-logind=no --enable-more-warnings=no --enable-ifcfg-rh --enable-config-plugin-ibft --enable-ifupdown --enable-tests &&
+ ../configure --prefix="$PWD/INST" --with-systemd-logind=no --enable-more-warnings=no --enable-ifcfg-rh --enable-config-plugin-ibft --enable-ifupdown --enable-tests --with-crypto=$CRYPTO &&
make -j4 &&
if [ "$CC" == gcc ]; then
sudo locale-gen pl_PL.UTF-8 &&
diff --git a/Makefile.am b/Makefile.am
index 8176019594..c1615108a1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -501,12 +501,15 @@ libnm_core_lib_h_priv = \
shared/nm-utils/nm-dedup-multi.h \
shared/nm-utils/nm-enum-utils.h \
shared/nm-utils/nm-hash-utils.h \
+ shared/nm-utils/nm-io-utils.h \
+ shared/nm-utils/nm-secret-utils.h \
shared/nm-utils/nm-shared-utils.h \
shared/nm-utils/nm-random-utils.h \
shared/nm-utils/nm-udev-utils.h \
shared/nm-ethtool-utils.h \
shared/nm-meta-setting.h \
- libnm-core/crypto.h \
+ libnm-core/nm-crypto.h \
+ libnm-core/nm-crypto-impl.h \
libnm-core/nm-connection-private.h \
libnm-core/nm-core-internal.h \
libnm-core/nm-core-types-internal.h \
@@ -567,12 +570,14 @@ libnm_core_lib_c_real = \
shared/nm-utils/nm-dedup-multi.c \
shared/nm-utils/nm-enum-utils.c \
shared/nm-utils/nm-hash-utils.c \
+ shared/nm-utils/nm-io-utils.c \
+ shared/nm-utils/nm-secret-utils.c \
shared/nm-utils/nm-shared-utils.c \
shared/nm-utils/nm-random-utils.c \
shared/nm-utils/nm-udev-utils.c \
shared/nm-ethtool-utils.c \
shared/nm-meta-setting.c \
- libnm-core/crypto.c \
+ libnm-core/nm-crypto.c \
libnm-core/nm-connection.c \
libnm-core/nm-dbus-utils.c \
libnm-core/nm-errors.c \
@@ -615,14 +620,6 @@ dflt_cppflags_libnm_core = \
$(SANITIZER_LIB_CFLAGS) \
$(NULL)
-if WITH_GNUTLS
-dflt_cppflags_libnm_core += $(GNUTLS_CFLAGS)
-endif
-
-if WITH_NSS
-dflt_cppflags_libnm_core += $(NSS_CFLAGS)
-endif
-
noinst_LTLIBRARIES += libnm-core/libnm-core.la
GLIB_GENERATED += \
@@ -668,7 +665,6 @@ nodist_libnm_core_libnm_core_la_SOURCES = \
$(libnm_core_lib_c_mkenums)
libnm_core_libnm_core_la_LIBADD = \
- shared/libcsiphash.la \
$(GLIB_LIBS) \
$(UUID_LIBS) \
$(LIBUDEV_LIBS) \
@@ -678,19 +674,9 @@ libnm_core_libnm_core_la_LDFLAGS = \
$(CODE_COVERAGE_LDFLAGS) \
$(SANITIZER_LIB_LDFLAGS)
-if WITH_GNUTLS
-libnm_core_lib_c_real += libnm-core/crypto_gnutls.c
-libnm_core_libnm_core_la_LIBADD += $(GNUTLS_LIBS)
-endif
-
-if WITH_NSS
-libnm_core_lib_c_real += libnm-core/crypto_nss.c
-libnm_core_libnm_core_la_LIBADD += $(NSS_LIBS)
-endif
-
EXTRA_DIST += \
- libnm-core/crypto_gnutls.c \
- libnm-core/crypto_nss.c \
+ libnm-core/nm-crypto-gnutls.c \
+ libnm-core/nm-crypto-nss.c \
libnm-core/nm-core-enum-types.c.template \
libnm-core/nm-core-enum-types.h.template \
libnm-core/meson.build
@@ -713,6 +699,46 @@ dist_dependencies += \
###############################################################################
+if HAVE_CRYPTO_GNUTLS
+if WITH_GNUTLS
+libnm_crypto_lib = libnm-core/libnm-crypto-gnutls.la
+else
+check_ltlibraries += libnm-core/libnm-crypto-gnutls.la
+endif
+
+libnm_core_libnm_crypto_gnutls_la_SOURCES = libnm-core/nm-crypto-gnutls.c
+libnm_core_libnm_crypto_gnutls_la_CPPFLAGS = \
+ $(libnm_core_libnm_core_la_CPPFLAGS) \
+ $(GNUTLS_CFLAGS)
+libnm_core_libnm_crypto_gnutls_la_LDFLAGS = \
+ $(libnm_core_libnm_core_la_LDFLAGS)
+libnm_core_libnm_crypto_gnutls_la_LIBADD = \
+ $(libnm_core_libnm_core_la_LIBADD) \
+ $(GNUTLS_LIBS)
+endif
+
+if HAVE_CRYPTO_NSS
+if WITH_NSS
+libnm_crypto_lib = libnm-core/libnm-crypto-nss.la
+else
+check_ltlibraries += libnm-core/libnm-crypto-nss.la
+endif
+
+libnm_core_libnm_crypto_nss_la_SOURCES = libnm-core/nm-crypto-nss.c
+libnm_core_libnm_crypto_nss_la_CPPFLAGS = \
+ $(libnm_core_libnm_core_la_CPPFLAGS) \
+ $(NSS_CFLAGS)
+libnm_core_libnm_crypto_nss_la_LDFLAGS = \
+ $(libnm_core_libnm_core_la_LDFLAGS)
+libnm_core_libnm_crypto_nss_la_LIBADD = \
+ $(libnm_core_libnm_core_la_LIBADD) \
+ $(NSS_LIBS)
+endif
+
+noinst_LTLIBRARIES += $(libnm_crypto_lib)
+
+###############################################################################
+
check_programs += \
libnm-core/tests/test-compare \
libnm-core/tests/test-crypto \
@@ -759,6 +785,8 @@ nodist_libnm_core_tests_test_general_SOURCES = \
libnm_core_tests_ldadd = \
libnm-core/libnm-core.la \
+ shared/libcsiphash.la \
+ $(libnm_crypto_lib) \
$(GLIB_LIBS)
libnm_core_tests_ldflags = \
@@ -963,6 +991,8 @@ libnm_libnm_utils_la_SOURCES = \
libnm_libnm_utils_la_LIBADD = \
libnm-core/libnm-core.la \
+ shared/libcsiphash.la \
+ $(libnm_crypto_lib) \
introspection/libnmdbus.la \
$(GLIB_LIBS)
@@ -1588,6 +1618,8 @@ endif
src_libNetworkManagerBase_la_LIBADD = \
libnm-core/libnm-core.la \
+ shared/libcsiphash.la \
+ $(libnm_crypto_lib) \
$(GLIB_LIBS) \
$(SYSTEMD_JOURNAL_LIBS) \
$(LIBUDEV_LIBS) \
@@ -4733,9 +4765,13 @@ EXTRA_DIST += \
shared/nm-utils/nm-compat.c \
shared/nm-utils/nm-compat.h \
shared/nm-utils/nm-glib.h \
+ shared/nm-utils/nm-io-utils.c \
+ shared/nm-utils/nm-io-utils.h \
shared/nm-utils/nm-jansson.h \
shared/nm-utils/nm-obj.h \
shared/nm-utils/nm-macros-internal.h \
+ shared/nm-utils/nm-secret-utils.c \
+ shared/nm-utils/nm-secret-utils.h \
shared/nm-utils/nm-shared-utils.c \
shared/nm-utils/nm-shared-utils.h \
shared/nm-utils/nm-test-utils.h \
diff --git a/config.h.meson b/config.h.meson
index c5fbf5fab3..ce77952bec 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -226,18 +226,6 @@
/* Define if you have iwd support */
#mesondefine WITH_IWD
-/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
- significant byte first (like Motorola and SPARC, unlike Intel). */
-#if defined AC_APPLE_UNIVERSAL_BUILD
-# if defined __BIG_ENDIAN__
-# define WORDS_BIGENDIAN 1
-# endif
-#else
-# ifndef WORDS_BIGENDIAN
-/* # undef WORDS_BIGENDIAN */
-# endif
-#endif
-
/* Define to 1 if on MINIX. */
#mesondefine _MINIX
diff --git a/configure.ac b/configure.ac
index ea1c43f12f..c104c9b930 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,11 +109,6 @@ GETTEXT_PACKAGE=NetworkManager
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
-dnl
-dnl Make sha1.c happy on big endian systems
-dnl
-AC_C_BIGENDIAN
-
# Add runstatedir if not specified manually in autoconf < 2.70
AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run")
AC_SUBST(runstatedir)
@@ -668,21 +663,41 @@ else
fi
AC_SUBST(NM_MODIFY_SYSTEM_POLICY)
+PKG_CHECK_MODULES(GNUTLS, [gnutls >= 2.12], [have_crypto_gnutls=yes], [have_crypto_gnutls=no])
+PKG_CHECK_MODULES(NSS, [nss], [have_crypto_nss=yes], [have_crypto_nss=yes])
+if test "${have_crypto_nss}" = "yes"; then
+ # Work around a pkg-config bug (fdo #29801) where exists != usable
+ FOO=`$PKG_CONFIG --cflags --libs nss`
+ if test x"$?" != "x0"; then
+ have_crypto_nss=no
+ fi
+fi
+AM_CONDITIONAL(HAVE_CRYPTO_GNUTLS, test "${have_crypto_gnutls}" = 'yes')
+AM_CONDITIONAL(HAVE_CRYPTO_NSS, test "${have_crypto_nss}" = 'yes')
+if test "${have_crypto_gnutls}" = 'yes'; then
+ AC_DEFINE(HAVE_CRYPTO_GNUTLS, 1, [Define if you have gnutls support])
+else
+ AC_DEFINE(HAVE_CRYPTO_GNUTLS, 0, [Define if you have gnutls support])
+fi
+if test "${have_crypto_nss}" = 'yes'; then
+ AC_DEFINE(HAVE_CRYPTO_NSS, 1, [Define if you have nss support])
+else
+ AC_DEFINE(HAVE_CRYPTO_NSS, 0, [Define if you have nss support])
+fi
+
AC_ARG_WITH(crypto,
AS_HELP_STRING([--with-crypto=nss|gnutls],
[Cryptography library to use for certificate and key operations]),
with_crypto=$withval,
with_crypto=nss)
if test "$with_crypto" = 'nss'; then
- PKG_CHECK_MODULES(NSS, [nss])
-
- # Work around a pkg-config bug (fdo #29801) where exists != usable
- FOO=`$PKG_CONFIG --cflags --libs nss`
- if test x"$?" != "x0"; then
- AC_MSG_ERROR([No usable NSS found])
+ if test "${have_crypto_nss}" != "yes"; then
+ AC_MSG_ERROR([No usable NSS found for --with-crypto=nss])
fi
elif test "$with_crypto" = 'gnutls'; then
- PKG_CHECK_MODULES(GNUTLS, [gnutls >= 2.12])
+ if test "${have_crypto_gnutls}" != "yes"; then
+ AC_MSG_ERROR([No usable gnutls found for --with-crypto=gnutls])
+ fi
else
AC_MSG_ERROR([Please choose either 'nss' or 'gnutls' for certificate and crypto operations])
fi
@@ -1385,7 +1400,7 @@ echo " code coverage: $enable_code_coverage"
echo " LTO: $enable_lto"
echo " linker garbage collection: $enable_ld_gc"
echo " JSON validation for libnm: $enable_json_validation"
-echo " crypto: $with_crypto"
+echo " crypto: $with_crypto (have-gnutls: $have_crypto_gnutls, have-nss: $have_crypto_nss)"
echo " sanitizers: $sanitizers"
echo " Mozilla Public Suffix List: $with_libpsl"
echo
diff --git a/docs/libnm/Makefile.am b/docs/libnm/Makefile.am
index c2bcff1be5..c5f2b836ba 100644
--- a/docs/libnm/Makefile.am
+++ b/docs/libnm/Makefile.am
@@ -32,7 +32,8 @@ CFILE_GLOB=$(top_srcdir)/libnm-core/*.c $(top_srcdir)/libnm/*.c
# Header files to ignore when scanning.
IGNORE_HFILES= \
common.h \
- crypto.h \
+ nm-crypto.h \
+ nm-crypto-impl.h \
nm-dbus-helpers.h \
nm-core-internal.h \
nm-core-types-internal.h \
diff --git a/docs/libnm/meson.build b/docs/libnm/meson.build
index 7baf09f823..77f7ed0f94 100644
--- a/docs/libnm/meson.build
+++ b/docs/libnm/meson.build
@@ -2,7 +2,8 @@ doc_module = libnm_name
private_headers = [
'common.h',
- 'crypto.h',
+ 'nm-crypto.h',
+ 'nm-crypto-impl.h',
'nm-dbus-helpers.h',
'nm-core-internal.h',
'nm-core-types-internal.h',
diff --git a/libnm-core/crypto.c b/libnm-core/crypto.c
deleted file mode 100644
index 319f8055fe..0000000000
--- a/libnm-core/crypto.c
+++ /dev/null
@@ -1,826 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-
-/*
- * Dan Williams <dcbw@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * Copyright 2007 - 2011 Red Hat, Inc.
- */
-
-#include "nm-default.h"
-
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "crypto.h"
-#include "nm-errors.h"
-
-#define PEM_RSA_KEY_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
-#define PEM_RSA_KEY_END "-----END RSA PRIVATE KEY-----"
-
-#define PEM_DSA_KEY_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
-#define PEM_DSA_KEY_END "-----END DSA PRIVATE KEY-----"
-
-#define PEM_CERT_BEGIN "-----BEGIN CERTIFICATE-----"
-#define PEM_CERT_END "-----END CERTIFICATE-----"
-
-#define PEM_PKCS8_ENC_KEY_BEGIN "-----BEGIN ENCRYPTED PRIVATE KEY-----"
-#define PEM_PKCS8_ENC_KEY_END "-----END ENCRYPTED PRIVATE KEY-----"
-
-#define PEM_PKCS8_DEC_KEY_BEGIN "-----BEGIN PRIVATE KEY-----"
-#define PEM_PKCS8_DEC_KEY_END "-----END PRIVATE KEY-----"
-
-static gboolean
-find_tag (const char *tag,
- const guint8 *data,
- gsize data_len,
- gsize start_at,
- gsize *out_pos)
-{
- gsize i, taglen;
- gsize len = data_len - start_at;
-
- g_return_val_if_fail (out_pos != NULL, FALSE);
-
- taglen = strlen (tag);
- if (len >= taglen) {
- for (i = 0; i < len - taglen + 1; i++) {
- if (memcmp (data + start_at + i, tag, taglen) == 0) {
- *out_pos = start_at + i;
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-#define DEK_INFO_TAG "DEK-Info: "
-#define PROC_TYPE_TAG "Proc-Type: "
-
-static GByteArray *
-parse_old_openssl_key_file (const guint8 *data,
- gsize data_len,
- NMCryptoKeyType *out_key_type,
- char **out_cipher,
- char **out_iv,
- GError **error)
-{
- GByteArray *bindata = NULL;
- char **lines = NULL;
- char **ln = NULL;
- gsize start = 0, end = 0;
- GString *str = NULL;
- int enc_tags = 0;
- NMCryptoKeyType key_type;
- char *iv = NULL;
- char *cipher = NULL;
- unsigned char *tmp = NULL;
- gsize tmp_len = 0;
- const char *start_tag;
- const char *end_tag;
- guint8 save_end = 0;
-
- *out_key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
- *out_iv = NULL;
- *out_cipher = NULL;
-
- if (find_tag (PEM_RSA_KEY_BEGIN, data, data_len, 0, &start)) {
- key_type = NM_CRYPTO_KEY_TYPE_RSA;
- start_tag = PEM_RSA_KEY_BEGIN;
- end_tag = PEM_RSA_KEY_END;
- } else if (find_tag (PEM_DSA_KEY_BEGIN, data, data_len, 0, &start)) {
- key_type = NM_CRYPTO_KEY_TYPE_DSA;
- start_tag = PEM_DSA_KEY_BEGIN;
- end_tag = PEM_DSA_KEY_END;
- } else
- goto parse_error;
-
- start += strlen (start_tag);
- if (!find_tag (end_tag, data, data_len, start, &end)) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("PEM key file had no end tag '%s'."),
- end_tag);
- goto parse_error;
- }
-
- save_end = data[end];
- ((guint8 *)data)[end] = '\0';
- lines = g_strsplit ((const char *) (data + start), "\n", 0);
- ((guint8 *)data)[end] = save_end;
-
- if (!lines || g_strv_length (lines) <= 1) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Doesn't look like a PEM private key file."));
- goto parse_error;
- }
-
- str = g_string_new_len (NULL, end - start);
- for (ln = lines; *ln; ln++) {
- char *p = *ln;
-
- /* Chug leading spaces */
- p = g_strstrip (p);
- if (!*p)
- continue;
-
- if (!strncmp (p, PROC_TYPE_TAG, strlen (PROC_TYPE_TAG))) {
- if (enc_tags++ != 0 || str->len != 0) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Malformed PEM file: Proc-Type was not first tag."));
- goto parse_error;
- }
-
- p += strlen (PROC_TYPE_TAG);
- if (strcmp (p, "4,ENCRYPTED")) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Malformed PEM file: unknown Proc-Type tag '%s'."),
- p);
- goto parse_error;
- }
- } else if (!strncmp (p, DEK_INFO_TAG, strlen (DEK_INFO_TAG))) {
- static const char *const known_ciphers[] = { CIPHER_DES_EDE3_CBC,
- CIPHER_DES_CBC,
- CIPHER_AES_128_CBC,
- CIPHER_AES_192_CBC,
- CIPHER_AES_256_CBC };
- char *comma;
- guint i;
-
- if (enc_tags++ != 1 || str->len != 0) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Malformed PEM file: DEK-Info was not the second tag."));
- goto parse_error;
- }
-
- p += strlen (DEK_INFO_TAG);
-
- /* Grab the IV first */
- comma = strchr (p, ',');
- if (!comma || (*(comma + 1) == '\0')) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Malformed PEM file: no IV found in DEK-Info tag."));
- goto parse_error;
- }
- *comma++ = '\0';
- if (!g_ascii_isxdigit (*comma)) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Malformed PEM file: invalid format of IV in DEK-Info tag."));
- goto parse_error;
- }
- iv = g_strdup (comma);
-
- /* Get the private key cipher */
- for (i = 0; i < G_N_ELEMENTS (known_ciphers); i++) {
- if (!g_ascii_strcasecmp (p, known_ciphers[i])) {
- cipher = g_strdup (known_ciphers[i]);
- break;
- }
- }
- if (i == G_N_ELEMENTS (known_ciphers)) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Malformed PEM file: unknown private key cipher '%s'."),
- p);
- goto parse_error;
- }
- } else {
- if (enc_tags == 1) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- "Malformed PEM file: both Proc-Type and DEK-Info tags are required.");
- goto parse_error;
- }
- g_string_append (str, p);
- }
- }
-
- tmp = g_base64_decode (str->str, &tmp_len);
- if (tmp == NULL || !tmp_len) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Could not decode private key."));
- goto parse_error;
- }
- g_string_free (str, TRUE);
-
- if (lines)
- g_strfreev (lines);
-
- bindata = g_byte_array_sized_new (tmp_len);
- g_byte_array_append (bindata, tmp, tmp_len);
- g_free (tmp);
-
- *out_key_type = key_type;
- *out_iv = iv;
- *out_cipher = cipher;
- return bindata;
-
-parse_error:
- g_free (tmp);
- g_free (cipher);
- g_free (iv);
- if (str)
- g_string_free (str, TRUE);
- if (lines)
- g_strfreev (lines);
- return NULL;
-}
-
-static GByteArray *
-parse_pkcs8_key_file (const guint8 *data,
- gsize data_len,
- gboolean *out_encrypted,
- GError **error)
-{
- GByteArray *key = NULL;
- gsize start = 0, end = 0;
- unsigned char *der = NULL;
- guint8 save_end;
- gsize length = 0;
- const char *start_tag = NULL, *end_tag = NULL;
- gboolean encrypted = FALSE;
-
- /* Try encrypted first, decrypted next */
- if (find_tag (PEM_PKCS8_ENC_KEY_BEGIN, data, data_len, 0, &start)) {
- start_tag = PEM_PKCS8_ENC_KEY_BEGIN;
- end_tag = PEM_PKCS8_ENC_KEY_END;
- encrypted = TRUE;
- } else if (find_tag (PEM_PKCS8_DEC_KEY_BEGIN, data, data_len, 0, &start)) {
- start_tag = PEM_PKCS8_DEC_KEY_BEGIN;
- end_tag = PEM_PKCS8_DEC_KEY_END;
- encrypted = FALSE;
- } else {
- g_set_error_literal (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Failed to find expected PKCS#8 start tag."));
- return NULL;
- }
-
- start += strlen (start_tag);
- if (!find_tag (end_tag, data, data_len, start, &end)) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Failed to find expected PKCS#8 end tag '%s'."),
- end_tag);
- return NULL;
- }
-
- /* g_base64_decode() wants a NULL-terminated string */
- save_end = data[end];
- ((guint8 *)data)[end] = '\0';
- der = g_base64_decode ((const char *) (data + start), &length);
- ((guint8 *)data)[end] = save_end;
-
- if (der && length) {
- key = g_byte_array_sized_new (length);
- g_byte_array_append (key, der, length);
- g_assert (key->len == length);
- *out_encrypted = encrypted;
- } else {
- g_set_error_literal (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Failed to decode PKCS#8 private key."));
- }
-
- g_free (der);
- return key;
-}
-
-static GByteArray *
-file_to_g_byte_array (const char *filename, GError **error)
-{
- char *contents;
- GByteArray *array = NULL;
- gsize length = 0;
-
- if (g_file_get_contents (filename, &contents, &length, error)) {
- array = g_byte_array_sized_new (length);
- g_byte_array_append (array, (guint8 *) contents, length);
- g_assert (array->len == length);
- g_free (contents);
- }
- return array;
-}
-
-/*
- * Convert a hex string into bytes.
- */
-static char *
-convert_iv (const char *src,
- gsize *out_len,
- GError **error)
-{
- int num;
- int i;
- char conv[3];
- char *c;
-
- g_return_val_if_fail (src != NULL, NULL);
-
- num = strlen (src);
- if (num % 2) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("IV must be an even number of bytes in length."));
- return NULL;
- }
-
- num /= 2;
- c = g_malloc0 (num + 1);
-
- conv[2] = '\0';
- for (i = 0; i < num; i++) {
- conv[0] = src[(i * 2)];
- conv[1] = src[(i * 2) + 1];
- if (!g_ascii_isxdigit (conv[0]) || !g_ascii_isxdigit (conv[1])) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("IV contains non-hexadecimal digits."));
- goto error;
- }
-
- c[i] = strtol(conv, NULL, 16);
- }
- *out_len = num;
- return c;
-
-error:
- g_free (c);
- return NULL;
-}
-
-char *
-crypto_make_des_aes_key (const char *cipher,
- const char *salt,
- const gsize salt_len,
- const char *password,
- gsize *out_len,
- GError **error)
-{
- char *key;
- guint32 digest_len;
-
- g_return_val_if_fail (cipher != NULL, NULL);
- g_return_val_if_fail (salt != NULL, NULL);
- g_return_val_if_fail (salt_len >= 8, NULL);
- g_return_val_if_fail (password != NULL, NULL);
- g_return_val_if_fail (out_len != NULL, NULL);
-
- if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
- digest_len = 24;
- else if (!strcmp (cipher, CIPHER_DES_CBC))
- digest_len = 8;
- else if (!strcmp (cipher, CIPHER_AES_128_CBC))
- digest_len = 16;
- else if (!strcmp (cipher, CIPHER_AES_192_CBC))
- digest_len = 24;
- else if (!strcmp (cipher, CIPHER_AES_256_CBC))
- digest_len = 32;
- else {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
- _("Private key cipher '%s' was unknown."),
- cipher);
- return NULL;
- }
-
- if (password[0] == '\0')
- return NULL;
-
- key = g_malloc0 (digest_len + 1);
-
- crypto_md5_hash (salt,
- 8,
- password,
- strlen (password),
- key,
- digest_len);
-
- *out_len = digest_len;
- return key;
-}
-
-static GByteArray *
-decrypt_key (const char *cipher,
- int key_type,
- const guint8 *data,
- gsize data_len,
- const char *iv,
- const char *password,
- GError **error)
-{
- char *bin_iv = NULL;
- gsize bin_iv_len = 0;
- char *key = NULL;
- gsize key_len = 0;
- char *output = NULL;
- gsize decrypted_len = 0;
- GByteArray *decrypted = NULL;
-
- g_return_val_if_fail (password != NULL, NULL);
-
- bin_iv = convert_iv (iv, &bin_iv_len, error);
- if (!bin_iv)
- return NULL;
-
- /* Convert the password and IV into a DES or AES key */
- key = crypto_make_des_aes_key (cipher, bin_iv, bin_iv_len, password, &key_len, error);
- if (!key || !key_len)
- goto out;
-
- output = crypto_decrypt (cipher, key_type,
- data, data_len,
- bin_iv, bin_iv_len,
- key, key_len,
- &decrypted_len,
- error);
- if (output && decrypted_len) {
- decrypted = g_byte_array_sized_new (decrypted_len);
- g_byte_array_append (decrypted, (guint8 *) output, decrypted_len);
- }
-
-out:
- /* Don't leak stale key material */
- if (key)
- memset (key, 0, key_len);
- g_free (output);
- g_free (key);
- g_free (bin_iv);
-
- return decrypted;
-}
-
-GByteArray *
-crypto_decrypt_openssl_private_key_data (const guint8 *data,
- gsize data_len,
- const char *password,
- NMCryptoKeyType *out_key_type,
- GError **error)
-{
- GByteArray *decrypted = NULL;
- NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
- GByteArray *parsed;
- char *iv = NULL;
- char *cipher = NULL;
-
- g_return_val_if_fail (data != NULL, NULL);
- if (out_key_type)
- g_return_val_if_fail (*out_key_type == NM_CRYPTO_KEY_TYPE_UNKNOWN, NULL);
-
- if (!crypto_init (error))
- return NULL;
-
- parsed = parse_old_openssl_key_file (data, data_len, &key_type, &cipher, &iv, NULL);
- /* return the key type even if decryption failed */
- if (out_key_type)
- *out_key_type = key_type;
-
- if (!parsed) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Unable to determine private key type."));
- return NULL;
- }
-
- if (password) {
- if (!cipher || !iv) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_PASSWORD,
- _("Password provided, but key was not encrypted."));
- } else {
- decrypted = decrypt_key (cipher,
- key_type,
- parsed->data,
- parsed->len,
- iv,
- password,
- error);
- }
- } else if (!cipher && !iv)
- decrypted = g_byte_array_ref (parsed);
-
- g_byte_array_unref (parsed);
- g_free (cipher);
- g_free (iv);
-
- return decrypted;
-}
-
-GByteArray *
-crypto_decrypt_openssl_private_key (const char *file,
- const char *password,
- NMCryptoKeyType *out_key_type,
- GError **error)
-{
- GByteArray *contents;
- GByteArray *key = NULL;
-
- if (!crypto_init (error))
- return NULL;
-
- contents = file_to_g_byte_array (file, error);
- if (contents) {
- key = crypto_decrypt_openssl_private_key_data (contents->data, contents->len,
- password, out_key_type, error);
- g_byte_array_free (contents, TRUE);
- }
- return key;
-}
-
-static GByteArray *
-extract_pem_cert_data (GByteArray *contents, GError **error)
-{
- GByteArray *cert = NULL;
- gsize start = 0, end = 0;
- unsigned char *der = NULL;
- guint8 save_end;
- gsize length = 0;
-
- if (!find_tag (PEM_CERT_BEGIN, contents->data, contents->len, 0, &start)) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("PEM certificate had no start tag '%s'."),
- PEM_CERT_BEGIN);
- goto done;
- }
-
- start += strlen (PEM_CERT_BEGIN);
- if (!find_tag (PEM_CERT_END, contents->data, contents->len, start, &end)) {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("PEM certificate had no end tag '%s'."),
- PEM_CERT_END);
- goto done;
- }
-
- /* g_base64_decode() wants a NULL-terminated string */
- save_end = contents->data[end];
- contents->data[end] = '\0';
- der = g_base64_decode ((const char *) (contents->data + start), &length);
- contents->data[end] = save_end;
-
- if (der && length) {
- cert = g_byte_array_sized_new (length);
- g_byte_array_append (cert, der, length);
- g_assert (cert->len == length);
- } else {
- g_set_error (error, NM_CRYPTO_ERROR,
- NM_CRYPTO_ERROR_INVALID_DATA,
- _("Failed to decode certificate."));
- }
-
-done:
- g_free (der);
- return cert;
-}
-
-GByteArray *
-crypto_load_and_verify_certificate (const char *file,
- NMCryptoFileFormat *out_file_format,
- GError **error)
-{
- GByteArray *array, *contents;
-
- g_return_val_if_fail (file != NULL, NULL);
- g_return_val_if_fail (out_file_format != NULL, NULL);
- g_return_val_if_fail (*out_file_format == NM_CRYPTO_FILE_FORMAT_UNKNOWN, NULL);
-
- if (!crypto_init (error))
- return NULL;
-
- contents = file_to_g_byte_array (file, error);
- if (!contents)
- return NULL;
-
- /* Check for PKCS#12 */
- if (crypto_is_pkcs12_data (contents->data, contents->len, NULL)) {
- *out_file_format = NM_CRYPTO_FILE_FORMAT_PKCS12;
- return contents;
- }
-
- /* Check for plain DER format */
- if (contents->len > 2 && contents->data[0] == 0x30 && contents->data[1] == 0x82) {
- *out_file_format = crypto_verify_cert (contents->data, contents->len, error);
- } else {
- array = extract_pem_cert_data (contents, error);
- if (!array) {
- g_byte_array_free (contents, TRUE);
- return NULL;
- }
-
- *out_file_format = crypto_verify_cert (array->data, array->len, error);
- g_byte_array_free (array, TRUE);
- }
-
- if (*out_file_format != NM_CRYPTO_FILE_FORMAT_X509) {
- g_byte_array_free (contents, TRUE);
- contents = NULL;
- }
-
- return contents;
-}
-
-gboolean
-crypto_is_pkcs12_data (const guint8 *data,
- gsize data_len,
- GError **error)
-{
- GError *local = NULL;
- gboolean success;
-
- if (!data_len)
- return FALSE;
-
- g_return_val_if_fail (data != NULL, FALSE);
-
- if (!crypto_init (error))
- return FALSE;
-
- success = crypto_verify_pkcs12 (data, data_len, NULL, &local);
- if (success == FALSE) {
- /* If the error was just a decryption error, then it's pkcs#12 */
- if (local) {
- if (g_error_matches (local, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED)) {
- success = TRUE;
- g_error_free (local);
- } else
- g_propagate_error (error, local);
- }
- }
- return success;
-}
-
-gboolean
-crypto_is_pkcs12_file (const char *file, GError **error)
-{
- GByteArray *contents;
- gboolean success = FALSE;
-
- g_return_val_if_fail (file != NULL, FALSE);
-
- if (!crypto_init (error))
- return FALSE;
-
- contents = file_to_g_byte_array (file, error);
- if (contents) {
- success = crypto_is_pkcs12_data (contents->data, contents->len, error);
- g_byte_array_free (contents, TRUE);
- }
- return success;
-}
-
-/* Verifies that a private key can be read, and if a password is given, that
- * the private key can be decrypted with that password.
- */
-NMCryptoFileFormat
-crypto_verify_private_key_data (const guint8 *data,
- gsize data_len,
- const char *password,
- gboolean *out_is_encrypted,
- GError **error)
-{
- GByteArray *tmp;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- NMCryptoKeyType ktype = NM_CRYPTO_KEY_TYPE_UNKNOWN;
- gboolean is_encrypted = FALSE;
-
- g_return_val_if_fail (data != NULL, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
- g_return_val_if_fail (out_is_encrypted == NULL || *out_is_encrypted == FALSE, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
-
- if (!crypto_init (error))
- return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
-
- /* Check for PKCS#12 first */
- if (crypto_is_pkcs12_data (data, data_len, NULL)) {
- is_encrypted = TRUE;
- if (!password || crypto_verify_pkcs12 (data, data_len, password, error))
- format = NM_CRYPTO_FILE_FORMAT_PKCS12;
- } else {
- /* Maybe it's PKCS#8 */
- tmp = parse_pkcs8_key_file (data, data_len, &is_encrypted, NULL);
- if (tmp) {
- if (!password || crypto_verify_pkcs8 (tmp->data, tmp->len, is_encrypted, password, error))
- format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
- } else {
- char *cipher, *iv;
-
- /* Or it's old-style OpenSSL */
- tmp = parse_old_openssl_key_file (data, data_len, &ktype,
- &cipher, &iv, NULL);
- if (tmp) {
- format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
- is_encrypted = (cipher && iv);
- g_free (cipher);
- g_free (iv);
- }
- }
-
- if (tmp) {
- /* Don't leave key data around */
- memset (tmp->data, 0, tmp->len);
- g_byte_array_free (tmp, TRUE);
- }
- }
-
- if (out_is_encrypted)
- *out_is_encrypted = is_encrypted;
- return format;
-}
-
-NMCryptoFileFormat
-crypto_verify_private_key (const char *filename,
- const char *password,
- gboolean *out_is_encrypted,
- GError **error)
-{
- GByteArray *contents;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
-
- g_return_val_if_fail (filename != NULL, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
-
- if (!crypto_init (error))
- return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
-
- contents = file_to_g_byte_array (filename, error);
- if (contents) {
- format = crypto_verify_private_key_data (contents->data, contents->len, password, out_is_encrypted, error);
- g_byte_array_free (contents, TRUE);
- }
- return format;
-}
-
-void
-crypto_md5_hash (const char *salt,
- gssize salt_len,
- const char *password,
- gssize password_len,
- char *buffer,
- gsize buflen)
-{
- GChecksum *ctx;
- gsize digest_len;
- char digest[16];
- gsize bufidx = 0;
- int i;
-
- nm_assert (g_checksum_type_get_length (G_CHECKSUM_MD5) == sizeof (digest));
-
- g_return_if_fail (password_len == 0 || password);
- g_return_if_fail (buffer != NULL);
- g_return_if_fail (buflen > 0);
- g_return_if_fail (salt_len == 0 || salt);
-
- ctx = g_checksum_new (G_CHECKSUM_MD5);
-
- if (salt_len < 0)
- salt_len = strlen (salt);
- if (password_len < 0)
- password_len = strlen (password);
-
- for (;;) {
- if (password_len > 0)
- g_checksum_update (ctx, (const guchar *) password, password_len);
- if (salt_len > 0)
- g_checksum_update (ctx, (const guchar *) salt, salt_len);
-
- digest_len = sizeof (digest);
- g_checksum_get_digest (ctx, (guchar *) digest, &digest_len);
- nm_assert (digest_len == sizeof (digest));
-
- for (i = 0; i < sizeof (digest); i++) {
- if (bufidx >= buflen)
- goto done;
- buffer[bufidx++] = digest[i];
- }
-
- g_checksum_reset (ctx);
- g_checksum_update (ctx, (const guchar *) digest, sizeof (digest));
- }
-
-done:
- memset (digest, 0, sizeof (digest));
- g_checksum_free (ctx);
-}
diff --git a/libnm-core/crypto.h b/libnm-core/crypto.h
deleted file mode 100644
index d20d6f3100..0000000000
--- a/libnm-core/crypto.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-
-/*
- * Dan Williams <dcbw@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * Copyright 2007 - 2014 Red Hat, Inc.
- */
-
-#ifndef __CRYPTO_H__
-#define __CRYPTO_H__
-
-#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE)
-#error Cannot use this header.
-#endif
-
-#define MD5_HASH_LEN 20
-#define CIPHER_DES_EDE3_CBC "DES-EDE3-CBC"
-#define CIPHER_DES_CBC "DES-CBC"
-#define CIPHER_AES_128_CBC "AES-128-CBC"
-#define CIPHER_AES_192_CBC "AES-192-CBC"
-#define CIPHER_AES_256_CBC "AES-256-CBC"
-
-typedef enum {
- NM_CRYPTO_KEY_TYPE_UNKNOWN = 0,
- NM_CRYPTO_KEY_TYPE_RSA,
- NM_CRYPTO_KEY_TYPE_DSA
-} NMCryptoKeyType;
-
-typedef enum {
- NM_CRYPTO_FILE_FORMAT_UNKNOWN = 0,
- NM_CRYPTO_FILE_FORMAT_X509,
- NM_CRYPTO_FILE_FORMAT_RAW_KEY,
- NM_CRYPTO_FILE_FORMAT_PKCS12
-} NMCryptoFileFormat;
-
-gboolean crypto_init (GError **error);
-
-GByteArray *crypto_decrypt_openssl_private_key_data (const guint8 *data,
- gsize data_len,
- const char *password,
- NMCryptoKeyType *out_key_type,
- GError **error);
-
-GByteArray *crypto_decrypt_openssl_private_key (const char *file,
- const char *password,
- NMCryptoKeyType *out_key_type,
- GError **error);
-
-GByteArray *crypto_load_and_verify_certificate (const char *file,
- NMCryptoFileFormat *out_file_format,
- GError **error);
-
-gboolean crypto_is_pkcs12_file (const char *file, GError **error);
-
-gboolean crypto_is_pkcs12_data (const guint8 *data, gsize len, GError **error);
-
-NMCryptoFileFormat crypto_verify_private_key_data (const guint8 *data,
- gsize data_len,
- const char *password,
- gboolean *out_is_encrypted,
- GError **error);
-
-NMCryptoFileFormat crypto_verify_private_key (const char *file,
- const char *password,
- gboolean *out_is_encrypted,
- GError **error);
-
-/* Internal utils API bits for crypto providers */
-
-void crypto_md5_hash (const char *salt,
- gssize salt_len,
- const char *password,
- gssize password_len,
- char *buffer,
- gsize buflen);
-
-char *crypto_make_des_aes_key (const char *cipher,
- const char *salt,
- const gsize salt_len,
- const char *password,
- gsize *out_len,
- GError **error);
-
-char * crypto_decrypt (const char *cipher,
- int key_type,
- const guint8 *data,
- gsize data_len,
- const char *iv,
- const gsize iv_len,
- const char *key,
- const gsize key_len,
- gsize *out_len,
- GError **error);
-
-char * crypto_encrypt (const char *cipher,
- const guint8 *data,
- gsize data_len,
- const char *iv,
- gsize iv_len,
- const char *key,
- gsize key_len,
- gsize *out_len,
- GError **error);
-
-gboolean crypto_randomize (void *buffer, gsize buffer_len, GError **error);
-
-NMCryptoFileFormat crypto_verify_cert (const guint8 *data,
- gsize len,
- GError **error);
-
-gboolean crypto_verify_pkcs12 (const guint8 *data,
- gsize data_len,
- const char *password,
- GError **error);
-
-gboolean crypto_verify_pkcs8 (const guint8 *data,
- gsize data_len,
- gboolean is_encrypted,
- const char *password,
- GError **error);
-
-#endif /* __CRYPTO_H__ */
diff --git a/libnm-core/meson.build b/libnm-core/meson.build
index ab570b6b47..eb6fcce94b 100644
--- a/libnm-core/meson.build
+++ b/libnm-core/meson.build
@@ -107,8 +107,7 @@ libnm_core_settings_sources = files(
)
libnm_core_sources = libnm_core_settings_sources + files(
- 'crypto.c',
- 'crypto_' + crypto + '.c',
+ 'nm-crypto.c',
'nm-connection.c',
'nm-dbus-utils.c',
'nm-errors.c',
@@ -136,7 +135,6 @@ libnm_core_enum = gnome.mkenums(
)
deps = [
- crypto_dep,
dl_dep,
libudev_dep,
shared_dep,
@@ -154,6 +152,32 @@ if enable_json_validation
deps += jansson_dep
endif
+if (crypto_gnutls_dep.found())
+ libnm_crypto_gnutls = static_library(
+ 'nm-crypto-gnutls',
+ sources: [ 'nm-crypto-gnutls.c' ],
+ dependencies: deps + [ crypto_gnutls_dep ],
+ c_args: cflags
+ )
+endif
+
+if (crypto_nss_dep.found())
+ libnm_crypto_nss = static_library(
+ 'nm-crypto-nss',
+ sources: [ 'nm-crypto-nss.c' ],
+ dependencies: deps + [ crypto_nss_dep ],
+ c_args: cflags
+ )
+endif
+
+if crypto == 'gnutls'
+ libnm_crypto = libnm_crypto_gnutls
+elif crypto == 'nss'
+ libnm_crypto = libnm_crypto_nss
+else
+ error('bug')
+endif
+
libnm_core_sources_all = libnm_core_sources
libnm_core_sources_all += libnm_core_enum
libnm_core_sources_all += shared_nm_meta_setting_c
@@ -165,6 +189,7 @@ libnm_core = static_library(
'nm-core',
sources: libnm_core_sources_all,
dependencies: deps,
+ link_with: libnm_crypto,
c_args: cflags
)
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 3dbbb7aa64..f0d4e40f93 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -215,6 +215,13 @@ const char *nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboole
char *_nm_utils_bin2str (gconstpointer addr, gsize length, gboolean upper_case);
void _nm_utils_bin2str_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out);
+guint8 *_nm_utils_str2bin_full (const char *asc,
+ gboolean delimiter_required,
+ const char *delimiter_candidates,
+ guint8 *buffer,
+ gsize buffer_length,
+ gsize *out_len);
+
GSList * _nm_utils_hash_values_to_slist (GHashTable *hash);
GHashTable *_nm_utils_copy_strdict (GHashTable *strdict);
@@ -287,12 +294,6 @@ void _nm_dbus_errors_init (void);
extern gboolean _nm_utils_is_manager_process;
-GByteArray *nm_utils_rsa_key_encrypt (const guint8 *data,
- gsize len,
- const char *in_password,
- char **out_password,
- GError **error);
-
gulong _nm_dbus_signal_connect_data (GDBusProxy *proxy,
const char *signal_name,
const GVariantType *signature,
@@ -587,4 +588,13 @@ const NMSettInfoProperty *_nm_sett_info_property_get (NMSettingClass *setting_cl
/*****************************************************************************/
+NMSetting8021xCKScheme _nm_setting_802_1x_cert_get_scheme (GBytes *bytes, GError **error);
+
+GBytes *_nm_setting_802_1x_cert_value_to_bytes (NMSetting8021xCKScheme scheme,
+ const guint8 *val_bin,
+ gssize val_len,
+ GError **error);
+
+/*****************************************************************************/
+
#endif
diff --git a/libnm-core/crypto_gnutls.c b/libnm-core/nm-crypto-gnutls.c
index 49181ee722..6c897e6dd3 100644
--- a/libnm-core/crypto_gnutls.c
+++ b/libnm-core/nm-crypto-gnutls.c
@@ -23,26 +23,53 @@
#include "nm-default.h"
+#include "nm-crypto-impl.h"
+
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <gnutls/x509.h>
#include <gnutls/pkcs12.h>
-#include "crypto.h"
+#include "nm-utils/nm-secret-utils.h"
#include "nm-errors.h"
-#define SALT_LEN 8
+/*****************************************************************************/
+
+static gboolean
+_get_cipher_info (NMCryptoCipherType cipher,
+ int *out_cipher_mech,
+ guint8 *out_real_iv_len)
+{
+ static const int cipher_mechs[] = {
+ [NM_CRYPTO_CIPHER_DES_EDE3_CBC] = GNUTLS_CIPHER_3DES_CBC,
+ [NM_CRYPTO_CIPHER_DES_CBC] = GNUTLS_CIPHER_DES_CBC,
+ [NM_CRYPTO_CIPHER_AES_128_CBC] = GNUTLS_CIPHER_AES_128_CBC,
+ [NM_CRYPTO_CIPHER_AES_192_CBC] = GNUTLS_CIPHER_AES_192_CBC,
+ [NM_CRYPTO_CIPHER_AES_256_CBC] = GNUTLS_CIPHER_AES_256_CBC,
+ };
+
+ g_return_val_if_fail (_NM_INT_NOT_NEGATIVE (cipher) && (gsize) cipher < G_N_ELEMENTS (cipher_mechs), FALSE);
+
+ if (cipher_mechs[cipher] == 0)
+ return FALSE;
-static gboolean initialized = FALSE;
+ NM_SET_OUT (out_cipher_mech, cipher_mechs[cipher]);
+ NM_SET_OUT (out_real_iv_len, nm_crypto_cipher_get_info (cipher)->real_iv_len);
+ return TRUE;
+}
+
+/*****************************************************************************/
gboolean
-crypto_init (GError **error)
+_nm_crypto_init (GError **error)
{
+ static gboolean initialized = FALSE;
+
if (initialized)
return TRUE;
- if (gnutls_global_init() != 0) {
- gnutls_global_deinit();
+ if (gnutls_global_init () != 0) {
+ gnutls_global_deinit ();
g_set_error_literal (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_FAILED,
_("Failed to initialize the crypto engine."));
@@ -53,61 +80,47 @@ crypto_init (GError **error)
return TRUE;
}
-char *
-crypto_decrypt (const char *cipher,
- int key_type,
- const guint8 *data,
- gsize data_len,
- const char *iv,
- const gsize iv_len,
- const char *key,
- const gsize key_len,
- gsize *out_len,
- GError **error)
+/*****************************************************************************/
+
+guint8 *
+_nmtst_crypto_decrypt (NMCryptoCipherType cipher,
+ const guint8 *data,
+ gsize data_len,
+ const guint8 *iv,
+ gsize iv_len,
+ const guint8 *key,
+ gsize key_len,
+ gsize *out_len,
+ GError **error)
{
gnutls_cipher_hd_t ctx;
gnutls_datum_t key_dt, iv_dt;
int err;
- int cipher_mech, i;
- char *output = NULL;
- gboolean success = FALSE;
- gsize pad_len, real_iv_len;
-
- if (!crypto_init (error))
- return NULL;
+ int cipher_mech;
+ nm_auto_clear_secret_ptr NMSecretPtr output = { 0 };
+ guint8 pad_i, pad_len;
+ guint8 real_iv_len;
- if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
- cipher_mech = GNUTLS_CIPHER_3DES_CBC;
- real_iv_len = SALT_LEN;
- } else if (!strcmp (cipher, CIPHER_DES_CBC)) {
- cipher_mech = GNUTLS_CIPHER_DES_CBC;
- real_iv_len = SALT_LEN;
- } else if (!strcmp (cipher, CIPHER_AES_128_CBC)) {
- cipher_mech = GNUTLS_CIPHER_AES_128_CBC;
- real_iv_len = 16;
- } else if (!strcmp (cipher, CIPHER_AES_192_CBC)) {
- cipher_mech = GNUTLS_CIPHER_AES_192_CBC;
- real_iv_len = 16;
- } else if (!strcmp (cipher, CIPHER_AES_256_CBC)) {
- cipher_mech = GNUTLS_CIPHER_AES_256_CBC;
- real_iv_len = 16;
- } else {
+ if (!_get_cipher_info (cipher, &cipher_mech, &real_iv_len)) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
- _("Private key cipher '%s' was unknown."),
- cipher);
+ _("Unsupported key cipher for decryption"));
return NULL;
}
+ if (!_nm_crypto_init (error))
+ return NULL;
+
if (iv_len < real_iv_len) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_DATA,
- _("Invalid IV length (must be at least %zd)."),
- real_iv_len);
+ _("Invalid IV length (must be at least %u)."),
+ (guint) real_iv_len);
return NULL;
}
- output = g_malloc0 (data_len);
+ output.len = data_len;
+ output.bin = g_malloc (data_len);
key_dt.data = (unsigned char *) key;
key_dt.size = key_len;
@@ -120,107 +133,81 @@ crypto_decrypt (const char *cipher,
NM_CRYPTO_ERROR_DECRYPTION_FAILED,
_("Failed to initialize the decryption cipher context: %s (%s)"),
gnutls_strerror_name (err), gnutls_strerror (err));
- goto out;
+ return NULL;
}
- err = gnutls_cipher_decrypt2 (ctx, data, data_len, output, data_len);
+ err = gnutls_cipher_decrypt2 (ctx, data, data_len, output.bin, output.len);
+
+ gnutls_cipher_deinit (ctx);
+
if (err < 0) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_DECRYPTION_FAILED,
_("Failed to decrypt the private key: %s (%s)"),
gnutls_strerror_name (err), gnutls_strerror (err));
- goto out;
+ return NULL;
}
- pad_len = output[data_len - 1];
+
+ pad_len = output.len > 0
+ ? output.bin[output.len - 1]
+ : 0;
/* Check if the padding at the end of the decrypted data is valid */
- if (pad_len == 0 || pad_len > real_iv_len) {
+ if ( pad_len == 0
+ || pad_len > real_iv_len) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_DECRYPTION_FAILED,
_("Failed to decrypt the private key: unexpected padding length."));
- goto out;
+ return NULL;
}
/* Validate tail padding; last byte is the padding size, and all pad bytes
* should contain the padding size.
*/
- for (i = 1; i <= pad_len; ++i) {
- if (output[data_len - i] != pad_len) {
+ for (pad_i = 1; pad_i <= pad_len; ++pad_i) {
+ if (output.bin[data_len - pad_i] != pad_len) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_DECRYPTION_FAILED,
_("Failed to decrypt the private key."));
- goto out;
+ return NULL;
}
}
- *out_len = data_len - pad_len;
- success = TRUE;
-
-out:
- if (!success) {
- if (output) {
- /* Don't expose key material */
- memset (output, 0, data_len);
- g_free (output);
- output = NULL;
- }
- }
- gnutls_cipher_deinit (ctx);
- return output;
+ *out_len = output.len - pad_len;
+ return g_steal_pointer (&output.bin);
}
-char *
-crypto_encrypt (const char *cipher,
- const guint8 *data,
- gsize data_len,
- const char *iv,
- const gsize iv_len,
- const char *key,
- gsize key_len,
- gsize *out_len,
- GError **error)
+guint8 *
+_nmtst_crypto_encrypt (NMCryptoCipherType cipher,
+ const guint8 *data,
+ gsize data_len,
+ const guint8 *iv,
+ gsize iv_len,
+ const guint8 *key,
+ gsize key_len,
+ gsize *out_len,
+ GError **error)
{
gnutls_cipher_hd_t ctx;
gnutls_datum_t key_dt, iv_dt;
int err;
int cipher_mech;
- char *output = NULL;
- gboolean success = FALSE;
- gsize padded_buf_len, pad_len, output_len;
- char *padded_buf = NULL;
- guint32 i;
+ nm_auto_clear_secret_ptr NMSecretPtr output = { 0 };
+ nm_auto_clear_secret_ptr NMSecretPtr padded_buf = { 0 };
+ gsize i, pad_len;
- if (!crypto_init (error))
- return NULL;
+ nm_assert (iv_len);
- if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
- cipher_mech = GNUTLS_CIPHER_3DES_CBC;
- else if (!strcmp (cipher, CIPHER_AES_128_CBC))
- cipher_mech = GNUTLS_CIPHER_AES_128_CBC;
- else if (!strcmp (cipher, CIPHER_AES_192_CBC))
- cipher_mech = GNUTLS_CIPHER_AES_192_CBC;
- else if (!strcmp (cipher, CIPHER_AES_256_CBC))
- cipher_mech = GNUTLS_CIPHER_AES_256_CBC;
- else {
+ if ( cipher == NM_CRYPTO_CIPHER_DES_CBC
+ || !_get_cipher_info (cipher, &cipher_mech, NULL)) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
- _("Private key cipher '%s' was unknown."),
- cipher);
+ _("Unsupported key cipher for encryption"));
return NULL;
}
- /* If data_len % ivlen == 0, then we add another complete block
- * onto the end so that the decrypter knows there's padding.
- */
- pad_len = iv_len - (data_len % iv_len);
- output_len = padded_buf_len = data_len + pad_len;
- padded_buf = g_malloc0 (padded_buf_len);
-
- memcpy (padded_buf, data, data_len);
- for (i = 0; i < pad_len; i++)
- padded_buf[data_len + i] = (guint8) (pad_len & 0xFF);
-
- output = g_malloc0 (output_len);
+ if (!_nm_crypto_init (error))
+ return NULL;
key_dt.data = (unsigned char *) key;
key_dt.size = key_len;
@@ -233,51 +220,50 @@ crypto_encrypt (const char *cipher,
NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
_("Failed to initialize the encryption cipher context: %s (%s)"),
gnutls_strerror_name (err), gnutls_strerror (err));
- goto out;
+ return NULL;
}
- err = gnutls_cipher_encrypt2 (ctx, padded_buf, padded_buf_len, output, output_len);
+ /* If data_len % ivlen == 0, then we add another complete block
+ * onto the end so that the decrypter knows there's padding.
+ */
+ pad_len = iv_len - (data_len % iv_len);
+
+ padded_buf.len = data_len + pad_len;
+ padded_buf.bin = g_malloc (padded_buf.len);
+ memcpy (padded_buf.bin, data, data_len);
+ for (i = 0; i < pad_len; i++)
+ padded_buf.bin[data_len + i] = (guint8) (pad_len & 0xFF);
+
+ output.len = padded_buf.len;
+ output.bin = g_malloc (output.len);
+
+ err = gnutls_cipher_encrypt2 (ctx, padded_buf.bin, padded_buf.len, output.bin, output.len);
+
+ gnutls_cipher_deinit (ctx);
+
if (err < 0) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
_("Failed to encrypt the data: %s (%s)"),
gnutls_strerror_name (err), gnutls_strerror (err));
- goto out;
- }
-
- *out_len = output_len;
- success = TRUE;
-
-out:
- if (padded_buf) {
- memset (padded_buf, 0, padded_buf_len);
- g_free (padded_buf);
- padded_buf = NULL;
+ return NULL;
}
- if (!success) {
- if (output) {
- /* Don't expose key material */
- memset (output, 0, output_len);
- g_free (output);
- output = NULL;
- }
- }
- gnutls_cipher_deinit (ctx);
- return output;
+ *out_len = output.len;
+ return g_steal_pointer (&output.bin);
}
-NMCryptoFileFormat
-crypto_verify_cert (const unsigned char *data,
- gsize len,
- GError **error)
+gboolean
+_nm_crypto_verify_x509 (const guint8 *data,
+ gsize len,
+ GError **error)
{
gnutls_x509_crt_t der;
gnutls_datum_t dt;
int err;
- if (!crypto_init (error))
- return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ if (!_nm_crypto_init (error))
+ return FALSE;
err = gnutls_x509_crt_init (&der);
if (err < 0) {
@@ -285,7 +271,7 @@ crypto_verify_cert (const unsigned char *data,
NM_CRYPTO_ERROR_INVALID_DATA,
_("Error initializing certificate data: %s"),
gnutls_strerror (err));
- return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ return FALSE;
}
/* Try DER first */
@@ -294,36 +280,35 @@ crypto_verify_cert (const unsigned char *data,
err = gnutls_x509_crt_import (der, &dt, GNUTLS_X509_FMT_DER);
if (err == GNUTLS_E_SUCCESS) {
gnutls_x509_crt_deinit (der);
- return NM_CRYPTO_FILE_FORMAT_X509;
+ return TRUE;
}
/* And PEM next */
err = gnutls_x509_crt_import (der, &dt, GNUTLS_X509_FMT_PEM);
gnutls_x509_crt_deinit (der);
if (err == GNUTLS_E_SUCCESS)
- return NM_CRYPTO_FILE_FORMAT_X509;
+ return TRUE;
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_DATA,
_("Couldn't decode certificate: %s"),
gnutls_strerror (err));
- return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ return FALSE;
}
gboolean
-crypto_verify_pkcs12 (const guint8 *data,
- gsize data_len,
- const char *password,
- GError **error)
+_nm_crypto_verify_pkcs12 (const guint8 *data,
+ gsize data_len,
+ const char *password,
+ GError **error)
{
gnutls_pkcs12_t p12;
gnutls_datum_t dt;
- gboolean success = FALSE;
int err;
g_return_val_if_fail (data != NULL, FALSE);
- if (!crypto_init (error))
+ if (!_nm_crypto_init (error))
return FALSE;
dt.data = (unsigned char *) data;
@@ -348,31 +333,32 @@ crypto_verify_pkcs12 (const guint8 *data,
NM_CRYPTO_ERROR_INVALID_DATA,
_("Couldn't decode PKCS#12 file: %s"),
gnutls_strerror (err));
- goto out;
+ gnutls_pkcs12_deinit (p12);
+ return FALSE;
}
}
err = gnutls_pkcs12_verify_mac (p12, password);
- if (err == GNUTLS_E_SUCCESS)
- success = TRUE;
- else {
+
+ gnutls_pkcs12_deinit (p12);
+
+ if (err != GNUTLS_E_SUCCESS) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_DECRYPTION_FAILED,
_("Couldn't verify PKCS#12 file: %s"),
gnutls_strerror (err));
+ return FALSE;
}
-out:
- gnutls_pkcs12_deinit (p12);
- return success;
+ return TRUE;
}
gboolean
-crypto_verify_pkcs8 (const guint8 *data,
- gsize data_len,
- gboolean is_encrypted,
- const char *password,
- GError **error)
+_nm_crypto_verify_pkcs8 (const guint8 *data,
+ gsize data_len,
+ gboolean is_encrypted,
+ const char *password,
+ GError **error)
{
gnutls_x509_privkey_t p8;
gnutls_datum_t dt;
@@ -380,12 +366,9 @@ crypto_verify_pkcs8 (const guint8 *data,
g_return_val_if_fail (data != NULL, FALSE);
- if (!crypto_init (error))
+ if (!_nm_crypto_init (error))
return FALSE;
- dt.data = (unsigned char *) data;
- dt.size = data_len;
-
err = gnutls_x509_privkey_init (&p8);
if (err < 0) {
g_set_error (error, NM_CRYPTO_ERROR,
@@ -395,11 +378,15 @@ crypto_verify_pkcs8 (const guint8 *data,
return FALSE;
}
+ dt.data = (unsigned char *) data;
+ dt.size = data_len;
+
err = gnutls_x509_privkey_import_pkcs8 (p8,
&dt,
GNUTLS_X509_FMT_DER,
is_encrypted ? password : NULL,
is_encrypted ? 0 : GNUTLS_PKCS_PLAIN);
+
gnutls_x509_privkey_deinit (p8);
if (err < 0) {
@@ -423,9 +410,9 @@ crypto_verify_pkcs8 (const guint8 *data,
}
gboolean
-crypto_randomize (void *buffer, gsize buffer_len, GError **error)
+_nm_crypto_randomize (void *buffer, gsize buffer_len, GError **error)
{
- if (!crypto_init (error))
+ if (!_nm_crypto_init (error))
return FALSE;
gnutls_rnd (GNUTLS_RND_RANDOM, buffer, buffer_len);
diff --git a/libnm-core/nm-crypto-impl.h b/libnm-core/nm-crypto-impl.h
new file mode 100644
index 0000000000..918651525b
--- /dev/null
+++ b/libnm-core/nm-crypto-impl.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * Dan Williams <dcbw@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_CRYPTO_IMPL_H__
+#define __NM_CRYPTO_IMPL_H__
+
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE)
+#error Cannot use this header.
+#endif
+
+#include "nm-crypto.h"
+
+gboolean _nm_crypto_init (GError **error);
+
+gboolean _nm_crypto_randomize (void *buffer, gsize buffer_len, GError **error);
+
+gboolean _nm_crypto_verify_x509 (const guint8 *data,
+ gsize len,
+ GError **error);
+
+gboolean _nm_crypto_verify_pkcs12 (const guint8 *data,
+ gsize data_len,
+ const char *password,
+ GError **error);
+
+gboolean _nm_crypto_verify_pkcs8 (const guint8 *data,
+ gsize data_len,
+ gboolean is_encrypted,
+ const char *password,
+ GError **error);
+
+/*****************************************************************************/
+
+guint8 *_nmtst_crypto_encrypt (NMCryptoCipherType cipher,
+ const guint8 *data,
+ gsize data_len,
+ const guint8 *iv,
+ gsize iv_len,
+ const guint8 *key,
+ gsize key_len,
+ gsize *out_len,
+ GError **error);
+
+guint8 *_nmtst_crypto_decrypt (NMCryptoCipherType cipher,
+ const guint8 *data,
+ gsize data_len,
+ const guint8 *iv,
+ gsize iv_len,
+ const guint8 *key,
+ gsize key_len,
+ gsize *out_len,
+ GError **error);
+
+#endif /* __NM_CRYPTO_IMPL_H__ */
diff --git a/libnm-core/crypto_nss.c b/libnm-core/nm-crypto-nss.c
index 3b457fbb30..711dde4baf 100644
--- a/libnm-core/crypto_nss.c
+++ b/libnm-core/nm-crypto-nss.c
@@ -23,6 +23,8 @@
#include "nm-default.h"
+#include "nm-crypto-impl.h"
+
#include <prinit.h>
#include <nss.h>
#include <pk11pub.h>
@@ -33,20 +35,46 @@
#include <ciferfam.h>
#include <p12plcy.h>
-#include "crypto.h"
+#include "nm-utils/nm-secret-utils.h"
#include "nm-errors.h"
-static gboolean initialized = FALSE;
+/*****************************************************************************/
+
+static gboolean
+_get_cipher_info (NMCryptoCipherType cipher,
+ CK_MECHANISM_TYPE *out_cipher_mech,
+ guint8 *out_real_iv_len)
+{
+ static const CK_MECHANISM_TYPE cipher_mechs[] = {
+ [NM_CRYPTO_CIPHER_DES_EDE3_CBC] = CKM_DES3_CBC_PAD,
+ [NM_CRYPTO_CIPHER_DES_CBC] = CKM_DES_CBC_PAD,
+ [NM_CRYPTO_CIPHER_AES_128_CBC] = CKM_AES_CBC_PAD,
+ [NM_CRYPTO_CIPHER_AES_192_CBC] = CKM_AES_CBC_PAD,
+ [NM_CRYPTO_CIPHER_AES_256_CBC] = CKM_AES_CBC_PAD,
+ };
+
+ g_return_val_if_fail (_NM_INT_NOT_NEGATIVE (cipher) && (gsize) cipher < G_N_ELEMENTS (cipher_mechs), FALSE);
+
+ if (!cipher_mechs[cipher])
+ return FALSE;
+
+ NM_SET_OUT (out_cipher_mech, cipher_mechs[cipher]);
+ NM_SET_OUT (out_real_iv_len, nm_crypto_cipher_get_info (cipher)->real_iv_len);
+ return TRUE;
+}
+
+/*****************************************************************************/
gboolean
-crypto_init (GError **error)
+_nm_crypto_init (GError **error)
{
+ static gboolean initialized = FALSE;
SECStatus ret;
if (initialized)
return TRUE;
- PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1);
+ PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 1);
ret = NSS_NoDB_Init (NULL);
if (ret != SECSuccess) {
g_set_error (error, NM_CRYPTO_ERROR,
@@ -57,74 +85,61 @@ crypto_init (GError **error)
return FALSE;
}
- SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
- SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
- SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
- SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
- SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
- SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
- SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC4_40, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC4_128, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_40, 1);
+ SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_128, 1);
+ SEC_PKCS12EnableCipher (PKCS12_DES_56, 1);
+ SEC_PKCS12EnableCipher (PKCS12_DES_EDE3_168, 1);
+ SEC_PKCS12SetPreferredCipher (PKCS12_DES_EDE3_168, 1);
initialized = TRUE;
return TRUE;
}
-char *
-crypto_decrypt (const char *cipher,
- int key_type,
- const guint8 *data,
- gsize data_len,
- const char *iv,
- const gsize iv_len,
- const char *key,
- const gsize key_len,
- gsize *out_len,
- GError **error)
+guint8 *
+_nmtst_crypto_decrypt (NMCryptoCipherType cipher,
+ const guint8 *data,
+ gsize data_len,
+ const guint8 *iv,
+ gsize iv_len,
+ const guint8 *key,
+ gsize key_len,
+ gsize *out_len,
+ GError **error)
{
- char *output = NULL;
- int decrypted_len = 0;
CK_MECHANISM_TYPE cipher_mech;
PK11SlotInfo *slot = NULL;
SECItem key_item;
PK11SymKey *sym_key = NULL;
SECItem *sec_param = NULL;
PK11Context *ctx = NULL;
+ nm_auto_clear_secret_ptr NMSecretPtr output = { 0 };
SECStatus s;
gboolean success = FALSE;
- unsigned pad_len = 0, extra = 0;
- guint32 i, real_iv_len = 0;
-
- if (!crypto_init (error))
- return NULL;
+ int decrypted_len = 0;
+ unsigned extra = 0;
+ unsigned pad_len = 0;
+ guint32 i;
+ guint8 real_iv_len;
- if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
- cipher_mech = CKM_DES3_CBC_PAD;
- real_iv_len = 8;
- } else if (!strcmp (cipher, CIPHER_DES_CBC)) {
- cipher_mech = CKM_DES_CBC_PAD;
- real_iv_len = 8;
- } else if (NM_IN_STRSET (cipher, CIPHER_AES_128_CBC,
- CIPHER_AES_192_CBC,
- CIPHER_AES_256_CBC)) {
- cipher_mech = CKM_AES_CBC_PAD;
- real_iv_len = 16;
- } else {
+ if (!_get_cipher_info (cipher, &cipher_mech, &real_iv_len)) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
- _("Private key cipher '%s' was unknown."),
- cipher);
+ _("Unsupported key cipher for decryption"));
return NULL;
}
if (iv_len < real_iv_len) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_DATA,
- _("Invalid IV length (must be at least %d)."),
- real_iv_len);
+ _("Invalid IV length (must be at least %u)."),
+ (guint) real_iv_len);
return NULL;
}
- output = g_malloc0 (data_len);
+ if (!_nm_crypto_init (error))
+ return NULL;
slot = PK11_GetBestSlot (cipher_mech, NULL);
if (!slot) {
@@ -162,10 +177,13 @@ crypto_decrypt (const char *cipher,
goto out;
}
+ output.len = data_len;
+ output.bin = g_malloc (data_len);
+
s = PK11_CipherOp (ctx,
- (unsigned char *) output,
+ (unsigned char *) output.bin,
&decrypted_len,
- data_len,
+ output.len,
data,
data_len);
if (s != SECSuccess) {
@@ -184,7 +202,7 @@ crypto_decrypt (const char *cipher,
}
s = PK11_DigestFinal (ctx,
- (unsigned char *) (output + decrypted_len),
+ (unsigned char *) &output.bin[decrypted_len],
&extra,
data_len - decrypted_len);
if (s != SECSuccess) {
@@ -194,6 +212,7 @@ crypto_decrypt (const char *cipher,
PORT_GetError ());
goto out;
}
+
decrypted_len += extra;
pad_len = data_len - decrypted_len;
@@ -209,7 +228,7 @@ crypto_decrypt (const char *cipher,
* should contain the padding size.
*/
for (i = pad_len; i > 0; i--) {
- if (output[data_len - i] != pad_len) {
+ if (output.bin[data_len - i] != pad_len) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_DECRYPTION_FAILED,
_("Failed to decrypt the private key."));
@@ -217,7 +236,6 @@ crypto_decrypt (const char *cipher,
}
}
- *out_len = decrypted_len;
success = TRUE;
out:
@@ -230,27 +248,25 @@ out:
if (slot)
PK11_FreeSlot (slot);
- if (!success) {
- if (output) {
- /* Don't expose key material */
- memset (output, 0, data_len);
- g_free (output);
- output = NULL;
- }
- }
- return output;
+ if (!success)
+ return NULL;
+
+ if (decrypted_len < output.len)
+ nm_explicit_bzero (&output.bin[decrypted_len], output.len - decrypted_len);
+ *out_len = decrypted_len;
+ return g_steal_pointer (&output.bin);
}
-char *
-crypto_encrypt (const char *cipher,
- const guint8 *data,
- gsize data_len,
- const char *iv,
- gsize iv_len,
- const char *key,
- gsize key_len,
- gsize *out_len,
- GError **error)
+guint8 *
+_nmtst_crypto_encrypt (NMCryptoCipherType cipher,
+ const guint8 *data,
+ gsize data_len,
+ const guint8 *iv,
+ gsize iv_len,
+ const guint8 *key,
+ gsize key_len,
+ gsize *out_len,
+ GError **error)
{
SECStatus ret;
CK_MECHANISM_TYPE cipher_mech = CKM_DES3_CBC_PAD;
@@ -260,49 +276,29 @@ crypto_encrypt (const char *cipher,
PK11SymKey *sym_key = NULL;
SECItem *sec_param = NULL;
PK11Context *ctx = NULL;
- unsigned char *output, *padded_buf;
- gsize output_len;
+ nm_auto_clear_secret_ptr NMSecretPtr padded_buf = { 0 };
+ nm_auto_clear_secret_ptr NMSecretPtr output = { 0 };
int encrypted_len = 0, i;
gboolean success = FALSE;
- gsize padded_buf_len, pad_len;
-
- if (!crypto_init (error))
- return NULL;
+ gsize pad_len;
- if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
- cipher_mech = CKM_DES3_CBC_PAD;
- else if (NM_IN_STRSET (cipher,
- CIPHER_AES_128_CBC,
- CIPHER_AES_192_CBC,
- CIPHER_AES_256_CBC))
- cipher_mech = CKM_AES_CBC_PAD;
- else {
+ if ( cipher == NM_CRYPTO_CIPHER_DES_CBC
+ || !_get_cipher_info (cipher, &cipher_mech, NULL)) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_UNKNOWN_CIPHER,
- _("Private key cipher '%s' was unknown."),
- cipher);
+ _("Unsupported key cipher for encryption"));
return NULL;
}
- /* If data->len % ivlen == 0, then we add another complete block
- * onto the end so that the decrypter knows there's padding.
- */
- pad_len = iv_len - (data_len % iv_len);
- output_len = padded_buf_len = data_len + pad_len;
- padded_buf = g_malloc0 (padded_buf_len);
-
- memcpy (padded_buf, data, data_len);
- for (i = 0; i < pad_len; i++)
- padded_buf[data_len + i] = (guint8) (pad_len & 0xFF);
-
- output = g_malloc0 (output_len);
+ if (!_nm_crypto_init (error))
+ return NULL;
slot = PK11_GetBestSlot (cipher_mech, NULL);
if (!slot) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_FAILED,
_("Failed to initialize the encryption cipher slot."));
- goto out;
+ return NULL;
}
sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
@@ -329,7 +325,22 @@ crypto_encrypt (const char *cipher,
goto out;
}
- ret = PK11_CipherOp (ctx, output, &encrypted_len, output_len, padded_buf, padded_buf_len);
+ /* If data->len % ivlen == 0, then we add another complete block
+ * onto the end so that the decrypter knows there's padding.
+ */
+ pad_len = iv_len - (data_len % iv_len);
+
+ padded_buf.len = data_len + pad_len;
+ padded_buf.bin = g_malloc (padded_buf.len);
+
+ memcpy (padded_buf.bin, data, data_len);
+ for (i = 0; i < pad_len; i++)
+ padded_buf.bin[data_len + i] = (guint8) (pad_len & 0xFF);
+
+ output.len = padded_buf.len;
+ output.bin = g_malloc (output.len);
+
+ ret = PK11_CipherOp (ctx, output.bin, &encrypted_len, output.len, padded_buf.bin, padded_buf.len);
if (ret != SECSuccess) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
@@ -338,46 +349,41 @@ crypto_encrypt (const char *cipher,
goto out;
}
- if (encrypted_len != output_len) {
+ if (encrypted_len != output.len) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_ENCRYPTION_FAILED,
_("Unexpected amount of data after encrypting."));
goto out;
}
- *out_len = encrypted_len;
success = TRUE;
out:
if (ctx)
PK11_DestroyContext (ctx, PR_TRUE);
- if (sym_key)
- PK11_FreeSymKey (sym_key);
if (sec_param)
SECITEM_FreeItem (sec_param, PR_TRUE);
+ if (sym_key)
+ PK11_FreeSymKey (sym_key);
if (slot)
PK11_FreeSlot (slot);
- memset (padded_buf, 0, padded_buf_len);
- g_free (padded_buf);
+ if (!success)
+ return NULL;
- if (!success) {
- memset (output, 0, output_len);
- g_free (output);
- output = NULL;
- }
- return (char *) output;
+ *out_len = output.len;
+ return g_steal_pointer (&output.bin);
}
-NMCryptoFileFormat
-crypto_verify_cert (const unsigned char *data,
- gsize len,
- GError **error)
+gboolean
+_nm_crypto_verify_x509 (const guint8 *data,
+ gsize len,
+ GError **error)
{
CERTCertificate *cert;
- if (!crypto_init (error))
- return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ if (!_nm_crypto_init (error))
+ return FALSE;
/* Try DER/PEM first */
cert = CERT_DecodeCertFromPackage ((char *) data, len);
@@ -385,76 +391,85 @@ crypto_verify_cert (const unsigned char *data,
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_DATA,
_("Couldn't decode certificate: %d"),
- PORT_GetError());
- return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ PORT_GetError ());
+ return FALSE;
}
CERT_DestroyCertificate (cert);
- return NM_CRYPTO_FILE_FORMAT_X509;
+ return TRUE;
}
gboolean
-crypto_verify_pkcs12 (const guint8 *data,
- gsize data_len,
- const char *password,
- GError **error)
+_nm_crypto_verify_pkcs12 (const guint8 *data,
+ gsize data_len,
+ const char *password,
+ GError **error)
{
SEC_PKCS12DecoderContext *p12ctx = NULL;
SECItem pw = { 0 };
PK11SlotInfo *slot = NULL;
SECStatus s;
- gunichar2 *ucs2_password;
- long ucs2_chars = 0;
-#ifndef WORDS_BIGENDIAN
- guint16 *p;
-#endif /* WORDS_BIGENDIAN */
+ gboolean success = FALSE;
- if (error)
- g_return_val_if_fail (*error == NULL, FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
- if (!crypto_init (error))
+ if (!_nm_crypto_init (error))
return FALSE;
/* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do
* any conversions for us.
*/
if (password && *password) {
- if (!g_utf8_validate (password, -1, NULL)) {
+ nm_auto_clear_secret_ptr NMSecretPtr ucs2_password = { 0 };
+
+ if (g_utf8_validate (password, -1, NULL)) {
+ long ucs2_chars;
+
+ ucs2_password.bin = (guint8 *) g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL);
+
+ /* cannot fail, because password is valid UTF-8*/
+ nm_assert (ucs2_password.bin && ucs2_chars > 0);
+
+ ucs2_password.len = ucs2_chars * 2;
+ }
+
+ if (!ucs2_password.bin || ucs2_password.len == 0) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_PASSWORD,
_("Password must be UTF-8"));
return FALSE;
}
- ucs2_password = g_utf8_to_utf16 (password, strlen (password), NULL, &ucs2_chars, NULL);
- /* Can't fail if g_utf8_validate() succeeded */
- g_return_val_if_fail (ucs2_password != NULL && ucs2_chars != 0, FALSE);
-
- ucs2_chars *= 2; /* convert # UCS2 characters -> bytes */
- pw.data = PORT_ZAlloc(ucs2_chars + 2);
- memcpy (pw.data, ucs2_password, ucs2_chars);
- pw.len = ucs2_chars + 2; /* include terminating NULL */
-
- memset (ucs2_password, 0, ucs2_chars);
- g_free (ucs2_password);
-
-#ifndef WORDS_BIGENDIAN
- for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++)
- *p = GUINT16_SWAP_LE_BE (*p);
-#endif /* WORDS_BIGENDIAN */
- } else {
- /* NULL password */
- pw.data = NULL;
- pw.len = 0;
+
+ pw.data = PORT_ZAlloc (ucs2_password.len + 2);
+ memcpy (pw.data, ucs2_password.bin, ucs2_password.len);
+ pw.len = ucs2_password.len + 2;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ {
+ guint16 *p, *p_end;
+
+ p_end = (guint16 *) &(((guint8 *) pw.data)[ucs2_password.len]);
+ for (p = (guint16 *) pw.data; p < p_end; p++)
+ *p = GUINT16_SWAP_LE_BE (*p);
+ }
+#endif
+ }
+
+ slot = PK11_GetInternalKeySlot ();
+ if (!slot) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_FAILED,
+ _("Couldn't initialize slot"));
+ goto out;
}
- slot = PK11_GetInternalKeySlot();
p12ctx = SEC_PKCS12DecoderStart (&pw, slot, NULL, NULL, NULL, NULL, NULL, NULL);
if (!p12ctx) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_FAILED,
_("Couldn't initialize PKCS#12 decoder: %d"),
- PORT_GetError());
- goto error;
+ PORT_GetError ());
+ goto out;
}
s = SEC_PKCS12DecoderUpdate (p12ctx, (guint8 *)data, data_len);
@@ -462,8 +477,8 @@ crypto_verify_pkcs12 (const guint8 *data,
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_INVALID_DATA,
_("Couldn't decode PKCS#12 file: %d"),
- PORT_GetError());
- goto error;
+ PORT_GetError ());
+ goto out;
}
s = SEC_PKCS12DecoderVerify (p12ctx);
@@ -471,35 +486,34 @@ crypto_verify_pkcs12 (const guint8 *data,
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERROR_DECRYPTION_FAILED,
_("Couldn't verify PKCS#12 file: %d"),
- PORT_GetError());
- goto error;
+ PORT_GetError ());
+ goto out;
}
- SEC_PKCS12DecoderFinish (p12ctx);
- SECITEM_ZfreeItem (&pw, PR_FALSE);
- return TRUE;
+ success = TRUE;
-error:
+out:
if (p12ctx)
SEC_PKCS12DecoderFinish (p12ctx);
-
if (slot)
- PK11_FreeSlot(slot);
+ PK11_FreeSlot (slot);
+
+ if (pw.data)
+ SECITEM_ZfreeItem (&pw, PR_FALSE);
- SECITEM_ZfreeItem (&pw, PR_FALSE);
- return FALSE;
+ return success;
}
gboolean
-crypto_verify_pkcs8 (const guint8 *data,
- gsize data_len,
- gboolean is_encrypted,
- const char *password,
- GError **error)
+_nm_crypto_verify_pkcs8 (const guint8 *data,
+ gsize data_len,
+ gboolean is_encrypted,
+ const char *password,
+ GError **error)
{
g_return_val_if_fail (data != NULL, FALSE);
- if (!crypto_init (error))
+ if (!_nm_crypto_init (error))
return FALSE;
/* NSS apparently doesn't do PKCS#8 natively, but you have to put the
@@ -510,11 +524,11 @@ crypto_verify_pkcs8 (const guint8 *data,
}
gboolean
-crypto_randomize (void *buffer, gsize buffer_len, GError **error)
+_nm_crypto_randomize (void *buffer, gsize buffer_len, GError **error)
{
SECStatus s;
- if (!crypto_init (error))
+ if (!_nm_crypto_init (error))
return FALSE;
s = PK11_GenerateRandom (buffer, buffer_len);
diff --git a/libnm-core/nm-crypto.c b/libnm-core/nm-crypto.c
new file mode 100644
index 0000000000..7a6e8d18ce
--- /dev/null
+++ b/libnm-core/nm-crypto.c
@@ -0,0 +1,1035 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * Dan Williams <dcbw@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-crypto.h"
+
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "nm-utils/nm-secret-utils.h"
+#include "nm-utils/nm-io-utils.h"
+
+#include "nm-crypto-impl.h"
+#include "nm-utils.h"
+#include "nm-errors.h"
+
+#define PEM_RSA_KEY_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
+#define PEM_RSA_KEY_END "-----END RSA PRIVATE KEY-----"
+
+#define PEM_DSA_KEY_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
+#define PEM_DSA_KEY_END "-----END DSA PRIVATE KEY-----"
+
+#define PEM_CERT_BEGIN "-----BEGIN CERTIFICATE-----"
+#define PEM_CERT_END "-----END CERTIFICATE-----"
+
+#define PEM_PKCS8_ENC_KEY_BEGIN "-----BEGIN ENCRYPTED PRIVATE KEY-----"
+#define PEM_PKCS8_ENC_KEY_END "-----END ENCRYPTED PRIVATE KEY-----"
+
+#define PEM_PKCS8_DEC_KEY_BEGIN "-----BEGIN PRIVATE KEY-----"
+#define PEM_PKCS8_DEC_KEY_END "-----END PRIVATE KEY-----"
+
+/*****************************************************************************/
+
+static const NMCryptoCipherInfo cipher_infos[] = {
+#define _CI(_cipher, _name, _digest_len, _real_iv_len) \
+ [(_cipher) - 1] = { .cipher = _cipher, .name = ""_name"", .digest_len = _digest_len, .real_iv_len = _real_iv_len }
+ _CI (NM_CRYPTO_CIPHER_DES_EDE3_CBC, "DES-EDE3-CBC", 24, 8),
+ _CI (NM_CRYPTO_CIPHER_DES_CBC, "DES-CBC", 8, 8),
+ _CI (NM_CRYPTO_CIPHER_AES_128_CBC, "AES-128-CBC", 16, 16),
+ _CI (NM_CRYPTO_CIPHER_AES_192_CBC, "AES-192-CBC", 24, 16),
+ _CI (NM_CRYPTO_CIPHER_AES_256_CBC, "AES-256-CBC", 32, 16),
+};
+
+const NMCryptoCipherInfo *
+nm_crypto_cipher_get_info (NMCryptoCipherType cipher)
+{
+ g_return_val_if_fail (cipher > NM_CRYPTO_CIPHER_UNKNOWN && (gsize) cipher < G_N_ELEMENTS (cipher_infos) + 1, NULL);
+
+#if NM_MORE_ASSERTS > 10
+ {
+ int i, j;
+
+ for (i = 0; i < (int) G_N_ELEMENTS (cipher_infos); i++) {
+ const NMCryptoCipherInfo *info = &cipher_infos[i];
+
+ nm_assert (info->cipher == (NMCryptoCipherType) (i + 1));
+ nm_assert (info->name && info->name[0]);
+ for (j = 0; j < i; j++)
+ nm_assert (g_ascii_strcasecmp (info->name, cipher_infos[j].name) != 0);
+ }
+ }
+#endif
+
+ return &cipher_infos[cipher - 1];
+}
+
+const NMCryptoCipherInfo *
+nm_crypto_cipher_get_info_by_name (const char *cipher_name, gssize p_len)
+{
+ int i;
+
+ nm_assert (nm_crypto_cipher_get_info (NM_CRYPTO_CIPHER_DES_CBC)->cipher == NM_CRYPTO_CIPHER_DES_CBC);
+
+ if (p_len < 0) {
+ if (!cipher_name)
+ return FALSE;
+ p_len = strlen (cipher_name);
+ }
+
+ for (i = 0; i < (int) G_N_ELEMENTS (cipher_infos); i++) {
+ const NMCryptoCipherInfo *info = &cipher_infos[i];
+
+ if ( (gsize) p_len == strlen (info->name)
+ && g_ascii_strncasecmp (info->name, cipher_name, p_len) == 0)
+ return info;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static gboolean
+find_tag (const char *tag,
+ const guint8 *data,
+ gsize data_len,
+ gsize start_at,
+ gsize *out_pos)
+{
+ gsize i, taglen;
+ gsize len = data_len - start_at;
+
+ g_return_val_if_fail (out_pos != NULL, FALSE);
+
+ taglen = strlen (tag);
+ if (len >= taglen) {
+ for (i = 0; i < len - taglen + 1; i++) {
+ if (memcmp (data + start_at + i, tag, taglen) == 0) {
+ *out_pos = start_at + i;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+#define DEK_INFO_TAG "DEK-Info: "
+#define PROC_TYPE_TAG "Proc-Type: "
+
+static char *
+_extract_line (const guint8 **p, const guint8 *p_end)
+{
+ const guint8 *x, *x0;
+
+ nm_assert (p);
+ nm_assert (p_end);
+ nm_assert (*p);
+ nm_assert (*p < p_end);
+
+ x = x0 = *p;
+ while (TRUE) {
+ if (x == p_end) {
+ *p = p_end;
+ break;
+ }
+ if (*x == '\0') {
+ /* the data contains embedded NUL. This is the end. */
+ *p = p_end;
+ break;
+ }
+ if (*x == '\n') {
+ *p = x + 1;
+ break;
+ }
+ x++;
+ }
+
+ if (x == x0)
+ return NULL;
+ return g_strndup ((char *) x0, x - x0);
+}
+
+static gboolean
+parse_old_openssl_key_file (const guint8 *data,
+ gsize data_len,
+ NMSecretPtr *out_parsed,
+ NMCryptoKeyType *out_key_type,
+ NMCryptoCipherType *out_cipher,
+ char **out_iv,
+ GError **error)
+{
+ gsize start = 0, end = 0;
+ nm_auto_free_secret char *str = NULL;
+ char *str_p;
+ gsize str_len;
+ int enc_tags = 0;
+ NMCryptoKeyType key_type;
+ nm_auto_clear_secret_ptr NMSecretPtr parsed = { 0 };
+ nm_auto_clear_secret_ptr NMSecretPtr data_content = { 0 };
+ nm_auto_free_secret char *iv = NULL;
+ NMCryptoCipherType cipher = NM_CRYPTO_CIPHER_UNKNOWN;
+ const char *start_tag;
+ const char *end_tag;
+ const guint8 *data_start, *data_end;
+
+ nm_assert (!out_parsed || (out_parsed->len == 0 && !out_parsed->bin));
+ nm_assert (!out_iv || !*out_iv);
+
+ NM_SET_OUT (out_key_type, NM_CRYPTO_KEY_TYPE_UNKNOWN);
+ NM_SET_OUT (out_cipher, NM_CRYPTO_CIPHER_UNKNOWN);
+
+ if (find_tag (PEM_RSA_KEY_BEGIN, data, data_len, 0, &start)) {
+ key_type = NM_CRYPTO_KEY_TYPE_RSA;
+ start_tag = PEM_RSA_KEY_BEGIN;
+ end_tag = PEM_RSA_KEY_END;
+ } else if (find_tag (PEM_DSA_KEY_BEGIN, data, data_len, 0, &start)) {
+ key_type = NM_CRYPTO_KEY_TYPE_DSA;
+ start_tag = PEM_DSA_KEY_BEGIN;
+ end_tag = PEM_DSA_KEY_END;
+ } else {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("PEM key file had no start tag"));
+ return FALSE;
+ }
+
+ start += strlen (start_tag);
+ if (!find_tag (end_tag, data, data_len, start, &end)) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("PEM key file had no end tag '%s'."),
+ end_tag);
+ return FALSE;
+ }
+
+ str_len = end - start + 1;
+ str = g_new (char, str_len);
+ str[0] = '\0';
+ str_p = str;
+
+ data_start = &data[start];
+ data_end = &data[end];
+
+ while (data_start < data_end) {
+ nm_auto_free_secret char *line = NULL;
+ char *p;
+
+ line = _extract_line (&data_start, data_end);
+ if (!line)
+ continue;
+
+ p = nm_secret_strchomp (nm_str_skip_leading_spaces (line));
+
+ if (!strncmp (p, PROC_TYPE_TAG, strlen (PROC_TYPE_TAG))) {
+ if (enc_tags++ != 0 || str_p != str) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Malformed PEM file: Proc-Type was not first tag."));
+ return FALSE;
+ }
+
+ p += strlen (PROC_TYPE_TAG);
+ if (strcmp (p, "4,ENCRYPTED")) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Malformed PEM file: unknown Proc-Type tag '%s'."),
+ p);
+ return FALSE;
+ }
+ } else if (!strncmp (p, DEK_INFO_TAG, strlen (DEK_INFO_TAG))) {
+ const NMCryptoCipherInfo *cipher_info;
+ char *comma;
+ gsize p_len;
+
+ if (enc_tags++ != 1 || str_p != str) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Malformed PEM file: DEK-Info was not the second tag."));
+ return FALSE;
+ }
+
+ p += strlen (DEK_INFO_TAG);
+
+ /* Grab the IV first */
+ comma = strchr (p, ',');
+ if (!comma || (*(comma + 1) == '\0')) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Malformed PEM file: no IV found in DEK-Info tag."));
+ return FALSE;
+ }
+ p_len = comma - p;
+ comma++;
+ if (!g_ascii_isxdigit (*comma)) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Malformed PEM file: invalid format of IV in DEK-Info tag."));
+ return FALSE;
+ }
+ nm_free_secret (iv);
+ iv = g_strdup (comma);
+
+ /* Get the private key cipher */
+ cipher_info = nm_crypto_cipher_get_info_by_name (p, p_len);
+ if (!cipher_info) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Malformed PEM file: unknown private key cipher '%s'."),
+ p);
+ return FALSE;
+ }
+ cipher = cipher_info->cipher;
+ } else {
+ if (enc_tags == 1) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ "Malformed PEM file: both Proc-Type and DEK-Info tags are required.");
+ return FALSE;
+ }
+ nm_utils_strbuf_append_str (&str_p, &str_len, p);
+ nm_assert (str_len > 0);
+ }
+ }
+
+ parsed.bin = (guint8 *) g_base64_decode (str, &parsed.len);
+ if (!parsed.bin || parsed.len == 0) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Could not decode private key."));
+ nm_secret_ptr_clear (&parsed);
+ return FALSE;
+ }
+
+ NM_SET_OUT (out_key_type, key_type);
+ NM_SET_OUT (out_iv, g_steal_pointer (&iv));
+ NM_SET_OUT (out_cipher, cipher);
+ nm_secret_ptr_move (out_parsed, &parsed);
+ return TRUE;
+}
+
+static gboolean
+parse_pkcs8_key_file (const guint8 *data,
+ gsize data_len,
+ NMSecretPtr *parsed,
+ gboolean *out_encrypted,
+ GError **error)
+{
+ gsize start = 0, end = 0;
+ gs_free guchar *der = NULL;
+ const char *start_tag = NULL, *end_tag = NULL;
+ gboolean encrypted = FALSE;
+ nm_auto_free_secret char *der_base64 = NULL;
+
+ nm_assert (parsed);
+ nm_assert (!parsed->bin);
+ nm_assert (parsed->len == 0);
+ nm_assert (out_encrypted);
+
+ /* Try encrypted first, decrypted next */
+ if (find_tag (PEM_PKCS8_ENC_KEY_BEGIN, data, data_len, 0, &start)) {
+ start_tag = PEM_PKCS8_ENC_KEY_BEGIN;
+ end_tag = PEM_PKCS8_ENC_KEY_END;
+ encrypted = TRUE;
+ } else if (find_tag (PEM_PKCS8_DEC_KEY_BEGIN, data, data_len, 0, &start)) {
+ start_tag = PEM_PKCS8_DEC_KEY_BEGIN;
+ end_tag = PEM_PKCS8_DEC_KEY_END;
+ encrypted = FALSE;
+ } else {
+ g_set_error_literal (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Failed to find expected PKCS#8 start tag."));
+ return FALSE;
+ }
+
+ start += strlen (start_tag);
+ if (!find_tag (end_tag, data, data_len, start, &end)) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Failed to find expected PKCS#8 end tag '%s'."),
+ end_tag);
+ return FALSE;
+ }
+
+ /* g_base64_decode() wants a NULL-terminated string */
+ der_base64 = g_strndup ((char *) &data[start], end - start);
+
+ parsed->bin = (guint8 *) g_base64_decode (der_base64, &parsed->len);
+ if (!parsed->bin || parsed->len == 0) {
+ g_set_error_literal (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Failed to decode PKCS#8 private key."));
+ nm_secret_ptr_clear (parsed);
+ return FALSE;
+ }
+
+ *out_encrypted = encrypted;
+ return TRUE;
+}
+
+static gboolean
+file_read_contents (const char *filename,
+ NMSecretPtr *out_contents,
+ GError **error)
+{
+ nm_assert (out_contents);
+ nm_assert (out_contents->len == 0);
+ nm_assert (!out_contents->str);
+
+ return nm_utils_file_get_contents (-1,
+ filename,
+ 100*1024*1024,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET,
+ &out_contents->str,
+ &out_contents->len,
+ error) >= 0;
+}
+
+GBytes *
+nm_crypto_read_file (const char *filename,
+ GError **error)
+{
+ nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
+
+ g_return_val_if_fail (filename, NULL);
+
+ if (!file_read_contents (filename, &contents, error))
+ return NULL;
+ return nm_secret_copy_to_gbytes (contents.bin, contents.len);
+}
+
+/*
+ * Convert a hex string into bytes.
+ */
+static guint8 *
+_nmtst_convert_iv (const char *src,
+ gsize *out_len,
+ GError **error)
+{
+ gsize i, num;
+ gs_free guint8 *c = NULL;
+ int c0, c1;
+
+ nm_assert (src);
+
+ num = strlen (src);
+ if ( num == 0
+ || (num % 2) != 0) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("IV must be an even number of bytes in length."));
+ return NULL;
+ }
+
+ num /= 2;
+ c = g_malloc (num + 1);
+
+ /* defensively add trailing NUL. This function returns binary data,
+ * do not assume it's NUL terminated. */
+ c[num] = '\0';
+
+ for (i = 0; i < num; i++) {
+ if ( ((c0 = nm_utils_hexchar_to_int (*(src++))) < 0)
+ || ((c1 = nm_utils_hexchar_to_int (*(src++))) < 0)) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("IV contains non-hexadecimal digits."));
+ nm_explicit_bzero (c, i);
+ return FALSE;
+ }
+
+ c[i] = (c0 << 4) + c1;
+ }
+ *out_len = num;
+ return g_steal_pointer (&c);
+}
+
+guint8 *
+nmtst_crypto_make_des_aes_key (NMCryptoCipherType cipher,
+ const guint8 *salt,
+ gsize salt_len,
+ const char *password,
+ gsize *out_len,
+ GError **error)
+{
+ guint8 *key;
+ const NMCryptoCipherInfo *cipher_info;
+
+ g_return_val_if_fail (salt != NULL, NULL);
+ g_return_val_if_fail (salt_len >= 8, NULL);
+ g_return_val_if_fail (password != NULL, NULL);
+ g_return_val_if_fail (out_len != NULL, NULL);
+
+ *out_len = 0;
+
+ cipher_info = nm_crypto_cipher_get_info (cipher);
+
+ g_return_val_if_fail (cipher_info, NULL);
+
+ if (password[0] == '\0')
+ return NULL;
+
+ key = g_malloc (cipher_info->digest_len);
+
+ nm_crypto_md5_hash (salt,
+ 8,
+ (guint8 *) password,
+ strlen (password),
+ key,
+ cipher_info->digest_len);
+
+ *out_len = cipher_info->digest_len;
+ return key;
+}
+
+static gboolean
+_nmtst_decrypt_key (NMCryptoCipherType cipher,
+ const guint8 *data,
+ gsize data_len,
+ const char *iv,
+ const char *password,
+ NMSecretPtr *parsed,
+ GError **error)
+{
+ nm_auto_clear_secret_ptr NMSecretPtr bin_iv = { 0 };
+ nm_auto_clear_secret_ptr NMSecretPtr key = { 0 };
+ gs_free char *output = NULL;
+
+ nm_assert (password);
+ nm_assert (cipher != NM_CRYPTO_CIPHER_UNKNOWN);
+ nm_assert (iv);
+ nm_assert (parsed);
+ nm_assert (!parsed->bin);
+ nm_assert (parsed->len == 0);
+
+ bin_iv.bin = _nmtst_convert_iv (iv, &bin_iv.len, error);
+ if (!bin_iv.bin)
+ return FALSE;
+
+ if (bin_iv.len < 8) {
+ g_set_error (error,
+ NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("IV must contain at least 8 characters"));
+ return FALSE;
+ }
+
+ /* Convert the password and IV into a DES or AES key */
+ key.bin = nmtst_crypto_make_des_aes_key (cipher, bin_iv.bin, bin_iv.len, password, &key.len, error);
+ if (!key.bin || !key.len)
+ return FALSE;
+
+ parsed->bin = _nmtst_crypto_decrypt (cipher,
+ data,
+ data_len,
+ bin_iv.bin,
+ bin_iv.len,
+ key.bin,
+ key.len,
+ &parsed->len,
+ error);
+ if (!parsed->bin || parsed->len == 0) {
+ nm_secret_ptr_clear (parsed);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GBytes *
+nmtst_crypto_decrypt_openssl_private_key_data (const guint8 *data,
+ gsize data_len,
+ const char *password,
+ NMCryptoKeyType *out_key_type,
+ GError **error)
+{
+ NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
+ nm_auto_clear_secret_ptr NMSecretPtr parsed = { 0 };
+ nm_auto_free_secret char *iv = NULL;
+ NMCryptoCipherType cipher = NM_CRYPTO_CIPHER_UNKNOWN;
+
+ g_return_val_if_fail (data != NULL, NULL);
+
+ NM_SET_OUT (out_key_type, NM_CRYPTO_KEY_TYPE_UNKNOWN);
+
+ if (!_nm_crypto_init (error))
+ return NULL;
+
+ if (!parse_old_openssl_key_file (data, data_len, &parsed, &key_type, &cipher, &iv, NULL)) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Unable to determine private key type."));
+ return NULL;
+ }
+
+ NM_SET_OUT (out_key_type, key_type);
+
+ if (password) {
+ nm_auto_clear_secret_ptr NMSecretPtr parsed2 = { 0 };
+
+ if (cipher == NM_CRYPTO_CIPHER_UNKNOWN || !iv) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_PASSWORD,
+ _("Password provided, but key was not encrypted."));
+ return NULL;
+ }
+
+ if (!_nmtst_decrypt_key (cipher,
+ parsed.bin,
+ parsed.len,
+ iv,
+ password,
+ &parsed2,
+ error))
+ return NULL;
+
+ return nm_secret_copy_to_gbytes (parsed2.bin, parsed2.len);
+ }
+
+ if (cipher != NM_CRYPTO_CIPHER_UNKNOWN || iv)
+ return NULL;
+
+ return nm_secret_copy_to_gbytes (parsed.bin, parsed.len);
+}
+
+GBytes *
+nmtst_crypto_decrypt_openssl_private_key (const char *file,
+ const char *password,
+ NMCryptoKeyType *out_key_type,
+ GError **error)
+{
+ nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
+
+ if (!_nm_crypto_init (error))
+ return NULL;
+
+ if (!file_read_contents (file, &contents, error))
+ return NULL;
+
+ return nmtst_crypto_decrypt_openssl_private_key_data (contents.bin,
+ contents.len,
+ password,
+ out_key_type,
+ error);
+}
+
+static gboolean
+extract_pem_cert_data (const guint8 *contents,
+ gsize contents_len,
+ NMSecretPtr *out_cert,
+ GError **error)
+{
+ gsize start = 0;
+ gsize end = 0;
+ nm_auto_free_secret char *der_base64 = NULL;
+
+ nm_assert (contents);
+ nm_assert (out_cert);
+ nm_assert (out_cert->len == 0);
+ nm_assert (!out_cert->ptr);
+
+ if (!find_tag (PEM_CERT_BEGIN, contents, contents_len, 0, &start)) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("PEM certificate had no start tag '%s'."),
+ PEM_CERT_BEGIN);
+ return FALSE;
+ }
+
+ start += strlen (PEM_CERT_BEGIN);
+ if (!find_tag (PEM_CERT_END, contents, contents_len, start, &end)) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("PEM certificate had no end tag '%s'."),
+ PEM_CERT_END);
+ return FALSE;
+ }
+
+ /* g_base64_decode() wants a NULL-terminated string */
+ der_base64 = g_strndup ((const char *) &contents[start], end - start);
+
+ out_cert->bin = (guint8 *) g_base64_decode (der_base64, &out_cert->len);
+ if (!out_cert->bin || !out_cert->len) {
+ g_set_error (error, NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Failed to decode certificate."));
+ nm_secret_ptr_clear (out_cert);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+nm_crypto_load_and_verify_certificate (const char *file,
+ NMCryptoFileFormat *out_file_format,
+ GBytes **out_certificate,
+ GError **error)
+{
+ nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
+
+ g_return_val_if_fail (file, FALSE);
+ nm_assert (!error || !*error);
+
+ if (!_nm_crypto_init (error))
+ goto out;
+
+ if (!file_read_contents (file, &contents, error))
+ goto out;
+
+ if (contents.len == 0) {
+ g_set_error (error,
+ NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Certificate file is empty"));
+ goto out;
+ }
+
+ /* Check for PKCS#12 */
+ if (nm_crypto_is_pkcs12_data (contents.bin, contents.len, NULL)) {
+ NM_SET_OUT (out_file_format, NM_CRYPTO_FILE_FORMAT_PKCS12);
+ NM_SET_OUT (out_certificate, nm_secret_copy_to_gbytes (contents.bin, contents.len));
+ return TRUE;
+ }
+
+ /* Check for plain DER format */
+ if (contents.len > 2 && contents.bin[0] == 0x30 && contents.bin[1] == 0x82) {
+ if (_nm_crypto_verify_x509 (contents.bin, contents.len, NULL)) {
+ NM_SET_OUT (out_file_format, NM_CRYPTO_FILE_FORMAT_X509);
+ NM_SET_OUT (out_certificate, nm_secret_copy_to_gbytes (contents.bin, contents.len));
+ return TRUE;
+ }
+ } else {
+ nm_auto_clear_secret_ptr NMSecretPtr pem_cert = { 0 };
+
+ if (extract_pem_cert_data (contents.bin, contents.len, &pem_cert, NULL)) {
+ if (_nm_crypto_verify_x509 (pem_cert.bin, pem_cert.len, NULL)) {
+ NM_SET_OUT (out_file_format, NM_CRYPTO_FILE_FORMAT_X509);
+ NM_SET_OUT (out_certificate, nm_secret_copy_to_gbytes (contents.bin, contents.len));
+ return TRUE;
+ }
+ }
+ }
+
+ g_set_error (error,
+ NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Failed to recognize certificate"));
+
+out:
+ NM_SET_OUT (out_file_format, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
+ NM_SET_OUT (out_certificate, NULL);
+ return FALSE;
+}
+
+gboolean
+nm_crypto_is_pkcs12_data (const guint8 *data,
+ gsize data_len,
+ GError **error)
+{
+ GError *local = NULL;
+ gboolean success;
+
+ if (!data_len) {
+ g_set_error (error,
+ NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("Certificate file is empty"));
+ return FALSE;
+ }
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ if (!_nm_crypto_init (error))
+ return FALSE;
+
+ success = _nm_crypto_verify_pkcs12 (data, data_len, NULL, &local);
+ if (success == FALSE) {
+ /* If the error was just a decryption error, then it's pkcs#12 */
+ if (local) {
+ if (g_error_matches (local, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED)) {
+ success = TRUE;
+ g_error_free (local);
+ } else
+ g_propagate_error (error, local);
+ }
+ }
+ return success;
+}
+
+gboolean
+nm_crypto_is_pkcs12_file (const char *file, GError **error)
+{
+ nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
+
+ g_return_val_if_fail (file != NULL, FALSE);
+
+ if (!_nm_crypto_init (error))
+ return FALSE;
+
+ if (!file_read_contents (file, &contents, error))
+ return FALSE;
+
+ return nm_crypto_is_pkcs12_data (contents.bin, contents.len, error);
+}
+
+/* Verifies that a private key can be read, and if a password is given, that
+ * the private key can be decrypted with that password.
+ */
+NMCryptoFileFormat
+nm_crypto_verify_private_key_data (const guint8 *data,
+ gsize data_len,
+ const char *password,
+ gboolean *out_is_encrypted,
+ GError **error)
+{
+ NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ gboolean is_encrypted = FALSE;
+
+ g_return_val_if_fail (data != NULL, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
+ g_return_val_if_fail (out_is_encrypted == NULL || *out_is_encrypted == FALSE, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
+
+ if (!_nm_crypto_init (error))
+ return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+
+ /* Check for PKCS#12 first */
+ if (nm_crypto_is_pkcs12_data (data, data_len, NULL)) {
+ is_encrypted = TRUE;
+ if ( !password
+ || _nm_crypto_verify_pkcs12 (data, data_len, password, error))
+ format = NM_CRYPTO_FILE_FORMAT_PKCS12;
+ } else {
+ nm_auto_clear_secret_ptr NMSecretPtr parsed = { 0 };
+
+ /* Maybe it's PKCS#8 */
+ if (parse_pkcs8_key_file (data, data_len, &parsed, &is_encrypted, NULL)) {
+ if ( !password
+ || _nm_crypto_verify_pkcs8 (parsed.bin, parsed.len, is_encrypted, password, error))
+ format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
+ } else {
+ NMCryptoCipherType cipher;
+ nm_auto_free_secret char *iv = NULL;
+
+ /* Or it's old-style OpenSSL */
+ if (parse_old_openssl_key_file (data, data_len, NULL, NULL, &cipher, &iv, NULL)) {
+ format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
+ is_encrypted = (cipher != NM_CRYPTO_CIPHER_UNKNOWN && iv);
+ }
+ }
+ }
+
+ if ( format == NM_CRYPTO_FILE_FORMAT_UNKNOWN
+ && error
+ && !*error) {
+ g_set_error (error,
+ NM_CRYPTO_ERROR,
+ NM_CRYPTO_ERROR_INVALID_DATA,
+ _("not a valid private key"));
+ }
+
+ if (out_is_encrypted)
+ *out_is_encrypted = is_encrypted;
+ return format;
+}
+
+NMCryptoFileFormat
+nm_crypto_verify_private_key (const char *filename,
+ const char *password,
+ gboolean *out_is_encrypted,
+ GError **error)
+{
+ nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
+
+ g_return_val_if_fail (filename != NULL, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
+
+ if (!_nm_crypto_init (error))
+ return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+
+ if (!file_read_contents (filename, &contents, error))
+ return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+
+ return nm_crypto_verify_private_key_data (contents.bin, contents.len, password, out_is_encrypted, error);
+}
+
+void
+nm_crypto_md5_hash (const guint8 *salt,
+ gsize salt_len,
+ const guint8 *password,
+ gsize password_len,
+ guint8 *buffer,
+ gsize buflen)
+{
+ nm_auto_free_checksum GChecksum *ctx = NULL;
+#define MD5_DIGEST_LEN 16
+ nm_auto_clear_static_secret_ptr const NMSecretPtr digest = NM_SECRET_PTR_STATIC (MD5_DIGEST_LEN);
+ gsize bufidx = 0;
+ int i;
+
+ nm_assert (g_checksum_type_get_length (G_CHECKSUM_MD5) == MD5_DIGEST_LEN);
+
+ g_return_if_fail (password_len == 0 || password);
+ g_return_if_fail (buffer);
+ g_return_if_fail (buflen > 0);
+ g_return_if_fail (salt_len == 0 || salt);
+
+ ctx = g_checksum_new (G_CHECKSUM_MD5);
+
+ for (;;) {
+ gsize digest_len;
+
+ if (password_len > 0)
+ g_checksum_update (ctx, (const guchar *) password, password_len);
+ if (salt_len > 0)
+ g_checksum_update (ctx, (const guchar *) salt, salt_len);
+
+ digest_len = MD5_DIGEST_LEN;
+ g_checksum_get_digest (ctx, digest.bin, &digest_len);
+ nm_assert (digest_len == MD5_DIGEST_LEN);
+
+ for (i = 0; i < MD5_DIGEST_LEN; i++) {
+ if (bufidx >= buflen)
+ return;
+ buffer[bufidx++] = digest.bin[i];
+ }
+
+ g_checksum_reset (ctx);
+ g_checksum_update (ctx, digest.ptr, MD5_DIGEST_LEN);
+ }
+}
+
+gboolean
+nm_crypto_randomize (void *buffer, gsize buffer_len, GError **error)
+{
+ return _nm_crypto_randomize (buffer, buffer_len, error);
+}
+
+
+/**
+ * nmtst_crypto_rsa_key_encrypt:
+ * @data: (array length=len): RSA private key data to be encrypted
+ * @len: length of @data
+ * @in_password: (allow-none): existing password to use, if any
+ * @out_password: (out) (allow-none): if @in_password was %NULL, a random
+ * password will be generated and returned in this argument
+ * @error: detailed error information on return, if an error occurred
+ *
+ * Encrypts the given RSA private key data with the given password (or generates
+ * a password if no password was given) and converts the data to PEM format
+ * suitable for writing to a file. It uses Triple DES cipher for the encryption.
+ *
+ * Returns: (transfer full): on success, PEM-formatted data suitable for writing
+ * to a PEM-formatted certificate/private key file.
+ **/
+GBytes *
+nmtst_crypto_rsa_key_encrypt (const guint8 *data,
+ gsize len,
+ const char *in_password,
+ char **out_password,
+ GError **error)
+{
+ guint8 salt[8];
+ nm_auto_clear_secret_ptr NMSecretPtr key = { 0 };
+ nm_auto_clear_secret_ptr NMSecretPtr enc = { 0 };
+ gs_unref_ptrarray GPtrArray *pem = NULL;
+ nm_auto_free_secret char *tmp_password = NULL;
+ nm_auto_free_secret char *enc_base64 = NULL;
+ gsize enc_base64_len;
+ const char *p;
+ gsize ret_len, ret_idx;
+ guint i;
+ NMSecretBuf *ret;
+
+ g_return_val_if_fail (data, NULL);
+ g_return_val_if_fail (len > 0, NULL);
+ g_return_val_if_fail (!out_password || !*out_password, NULL);
+
+ /* Make the password if needed */
+ if (!in_password) {
+ nm_auto_clear_static_secret_ptr NMSecretPtr pw_buf = NM_SECRET_PTR_STATIC (32);
+
+ if (!nm_crypto_randomize (pw_buf.bin, pw_buf.len, error))
+ return NULL;
+ tmp_password = nm_utils_bin2hexstr (pw_buf.bin, pw_buf.len, -1);
+ in_password = tmp_password;
+ }
+
+ if (!nm_crypto_randomize (salt, sizeof (salt), error))
+ return NULL;
+
+ key.bin = nmtst_crypto_make_des_aes_key (NM_CRYPTO_CIPHER_DES_EDE3_CBC, salt, sizeof (salt), in_password, &key.len, NULL);
+ if (!key.bin)
+ g_return_val_if_reached (NULL);
+
+ enc.bin = _nmtst_crypto_encrypt (NM_CRYPTO_CIPHER_DES_EDE3_CBC, data, len, salt, sizeof (salt), key.bin, key.len, &enc.len, error);
+ if (!enc.bin)
+ return NULL;
+
+ /* What follows is not the most efficient way to construct the pem
+ * file line-by-line. At least, it makes sure, that the data will be cleared
+ * again and not left around in memory.
+ *
+ * If this would not be test code, we should improve the implementation
+ * to avoid some of the copying. */
+ pem = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_free_secret);
+
+ g_ptr_array_add (pem, g_strdup ("-----BEGIN RSA PRIVATE KEY-----\n"));
+ g_ptr_array_add (pem, g_strdup ("Proc-Type: 4,ENCRYPTED\n"));
+
+ /* Convert the salt to a hex string */
+ g_ptr_array_add (pem, g_strdup_printf ("DEK-Info: %s,",
+ nm_crypto_cipher_get_info (NM_CRYPTO_CIPHER_DES_EDE3_CBC)->name));
+ g_ptr_array_add (pem, nm_utils_bin2hexstr (salt, sizeof (salt), sizeof (salt) * 2));
+ g_ptr_array_add (pem, g_strdup ("\n\n"));
+
+ /* Convert the encrypted key to a base64 string */
+ enc_base64 = g_base64_encode ((const guchar *) enc.bin, enc.len);
+ enc_base64_len = strlen (enc_base64);
+ for (p = enc_base64; (p - enc_base64) < (ptrdiff_t) enc_base64_len; p += 64) {
+ g_ptr_array_add (pem, g_strndup (p, 64));
+ g_ptr_array_add (pem, g_strdup ("\n"));
+ }
+
+ g_ptr_array_add (pem, g_strdup ("-----END RSA PRIVATE KEY-----\n"));
+
+ ret_len = 0;
+ for (i = 0; i < pem->len; i++)
+ ret_len += strlen (pem->pdata[i]);
+
+ ret = nm_secret_buf_new (ret_len + 1);
+ ret_idx = 0;
+ for (i = 0; i < pem->len; i++) {
+ const char *line = pem->pdata[i];
+ gsize line_l = strlen (line);
+
+ memcpy (&ret->bin[ret_idx], line, line_l);
+ ret_idx += line_l;
+ nm_assert (ret_idx <= ret_len);
+ }
+ nm_assert (ret_idx == ret_len);
+ ret->bin[ret_len] = '\0';
+
+ NM_SET_OUT (out_password, g_strdup (tmp_password));
+ return nm_secret_buf_to_gbytes_take (ret, ret_len);
+}
diff --git a/libnm-core/nm-crypto.h b/libnm-core/nm-crypto.h
new file mode 100644
index 0000000000..54fbbc5f57
--- /dev/null
+++ b/libnm-core/nm-crypto.h
@@ -0,0 +1,125 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * Dan Williams <dcbw@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2014 Red Hat, Inc.
+ */
+
+#ifndef __NM_CRYPTO_H__
+#define __NM_CRYPTO_H__
+
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE)
+#error Cannot use this header.
+#endif
+
+typedef enum {
+ NM_CRYPTO_CIPHER_UNKNOWN,
+ NM_CRYPTO_CIPHER_DES_EDE3_CBC,
+ NM_CRYPTO_CIPHER_DES_CBC,
+ NM_CRYPTO_CIPHER_AES_128_CBC,
+ NM_CRYPTO_CIPHER_AES_192_CBC,
+ NM_CRYPTO_CIPHER_AES_256_CBC,
+} NMCryptoCipherType;
+
+typedef struct {
+ const char *name;
+ NMCryptoCipherType cipher;
+ guint8 digest_len;
+ guint8 real_iv_len;
+} NMCryptoCipherInfo;
+
+const NMCryptoCipherInfo *nm_crypto_cipher_get_info (NMCryptoCipherType cipher);
+const NMCryptoCipherInfo *nm_crypto_cipher_get_info_by_name (const char *cipher_name, gssize p_len);
+
+typedef enum {
+ NM_CRYPTO_KEY_TYPE_UNKNOWN = 0,
+ NM_CRYPTO_KEY_TYPE_RSA,
+ NM_CRYPTO_KEY_TYPE_DSA
+} NMCryptoKeyType;
+
+typedef enum {
+ NM_CRYPTO_FILE_FORMAT_UNKNOWN = 0,
+ NM_CRYPTO_FILE_FORMAT_X509,
+ NM_CRYPTO_FILE_FORMAT_RAW_KEY,
+ NM_CRYPTO_FILE_FORMAT_PKCS12
+} NMCryptoFileFormat;
+
+/*****************************************************************************/
+
+GBytes *nm_crypto_read_file (const char *filename,
+ GError **error);
+
+gboolean nm_crypto_load_and_verify_certificate (const char *file,
+ NMCryptoFileFormat *out_file_format,
+ GBytes **out_certificat,
+ GError **error);
+
+gboolean nm_crypto_is_pkcs12_file (const char *file, GError **error);
+
+gboolean nm_crypto_is_pkcs12_data (const guint8 *data, gsize len, GError **error);
+
+NMCryptoFileFormat nm_crypto_verify_private_key_data (const guint8 *data,
+ gsize data_len,
+ const char *password,
+ gboolean *out_is_encrypted,
+ GError **error);
+
+NMCryptoFileFormat nm_crypto_verify_private_key (const char *file,
+ const char *password,
+ gboolean *out_is_encrypted,
+ GError **error);
+
+void nm_crypto_md5_hash (const guint8 *salt,
+ gsize salt_len,
+ const guint8 *password,
+ gsize password_len,
+ guint8 *buffer,
+ gsize buflen);
+
+gboolean nm_crypto_randomize (void *buffer, gsize buffer_len, GError **error);
+
+/*****************************************************************************/
+
+GBytes *nmtst_crypto_decrypt_openssl_private_key_data (const guint8 *data,
+ gsize data_len,
+ const char *password,
+ NMCryptoKeyType *out_key_type,
+ GError **error);
+
+GBytes *nmtst_crypto_decrypt_openssl_private_key (const char *file,
+ const char *password,
+ NMCryptoKeyType *out_key_type,
+ GError **error);
+
+GBytes *nmtst_crypto_rsa_key_encrypt (const guint8 *data,
+ gsize len,
+ const char *in_password,
+ char **out_password,
+ GError **error);
+
+guint8 *nmtst_crypto_make_des_aes_key (NMCryptoCipherType cipher,
+ const guint8 *salt,
+ gsize salt_len,
+ const char *password,
+ gsize *out_len,
+ GError **error);
+
+/*****************************************************************************/
+
+#endif /* __NM_CRYPTO_H__ */
diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c
index 3f9d60bbb7..c7d878691b 100644
--- a/libnm-core/nm-keyfile.c
+++ b/libnm-core/nm-keyfile.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <linux/pkt_sched.h>
+#include "nm-utils/nm-secret-utils.h"
#include "nm-common-macros.h"
#include "nm-core-internal.h"
#include "nm-keyfile-utils.h"
@@ -939,7 +940,7 @@ unescape_semicolons (char *str)
i++;
str[j++] = str[i++];;
}
- str[j] = '\0';
+ nm_explicit_bzero (&str[j], i - j);
return j;
}
@@ -950,9 +951,10 @@ get_bytes (KeyfileReaderInfo *info,
gboolean zero_terminate,
gboolean unescape_semicolon)
{
- gs_free char *tmp_string = NULL;
+ nm_auto_free_secret char *tmp_string = NULL;
gboolean may_be_int_list = TRUE;
gsize length;
+ GBytes *result;
/* New format: just a string
* Old format: integer list; e.g. 11;25;38;
@@ -969,7 +971,7 @@ get_bytes (KeyfileReaderInfo *info,
* byte-array. The reason is that zero_terminate is there to terminate
* *valid* strings. It's not there to terminated invalid (empty) strings.
*/
- return g_bytes_new_take (tmp_string, 0);
+ return g_bytes_new_static ("", 0);
}
for (length = 0; tmp_string[length]; length++) {
@@ -986,12 +988,11 @@ get_bytes (KeyfileReaderInfo *info,
/* Try to parse the string as a integer list. */
if (may_be_int_list && length > 0) {
- gs_free guint8 *bin_data = NULL;
+ nm_auto_free_secret_buf NMSecretBuf *bin = NULL;
const char *const s = tmp_string;
gsize i, d;
- const gsize BIN_DATA_LEN = (length / 2 + 3);
- bin_data = g_malloc (BIN_DATA_LEN);
+ bin = nm_secret_buf_new (length / 2 + 3);
#define DIGIT(c) ((c) - '0')
i = 0;
@@ -1024,8 +1025,8 @@ get_bytes (KeyfileReaderInfo *info,
break;
}
- bin_data[d++] = n;
- nm_assert (d < BIN_DATA_LEN);
+ nm_assert (d < bin->len);
+ bin->bin[d++] = n;
/* allow whitespace after the digit. */
while (g_ascii_isspace (s[i]))
@@ -1043,16 +1044,23 @@ get_bytes (KeyfileReaderInfo *info,
* string format before. We expect that this conversion cannot fail. */
if (d > 0) {
/* note that @zero_terminate does not add a terminating '\0' to
- * binary data as an integer list.
- *
- * But we add a '\0' to the bin_data pointer, just to avoid somebody
- * (erronously!) reading the binary data as C-string.
+ * binary data as an integer list. If the bytes are expressed as
+ * an integer list, all potential NUL characters are supposed to
+ * be included there explicitly.
*
- * @d itself does not entail the '\0'. */
- nm_assert (d + 1 <= BIN_DATA_LEN);
- bin_data = g_realloc (bin_data, d + 1);
- bin_data[d] = '\0';
- return g_bytes_new_take (g_steal_pointer (&bin_data), d);
+ * However, in the spirit of defensive programming, we do append a
+ * NUL character to the buffer, although this character is hidden
+ * and only a mitigation for bugs. */
+
+ if (d + 10 < bin->len) {
+ /* hm, too much unused memory. Copy the memory to a suitable
+ * sized buffer. */
+ return nm_secret_copy_to_gbytes (bin->bin, d);
+ }
+
+ nm_assert (d < bin->len);
+ bin->bin[d] = '\0';
+ return nm_secret_buf_to_gbytes_take (g_steal_pointer (&bin), d);
}
}
@@ -1063,8 +1071,13 @@ get_bytes (KeyfileReaderInfo *info,
length++;
if (length == 0)
return NULL;
- tmp_string = g_realloc (tmp_string, length + (zero_terminate ? 0 : 1));
- return g_bytes_new_take (g_steal_pointer (&tmp_string), length);
+
+ result = g_bytes_new_with_free_func (tmp_string,
+ length,
+ (GDestroyNotify) nm_free_secret,
+ tmp_string);
+ tmp_string = NULL;
+ return result;
}
static void
@@ -1108,12 +1121,12 @@ get_cert_path (const char *base_dir, const guint8 *cert_path, gsize cert_path_le
g_return_val_if_fail (base_dir != NULL, NULL);
g_return_val_if_fail (cert_path != NULL, NULL);
- base = path = g_malloc0 (cert_path_len + 1);
- memcpy (path, cert_path, cert_path_len);
+ path = g_strndup ((char *) cert_path, cert_path_len);
if (path[0] == '/')
return path;
+ base = path;
p = strrchr (path, '/');
if (p)
base = p + 1;
@@ -1147,8 +1160,9 @@ nm_keyfile_detect_unqualified_path_scheme (const char *base_dir,
const char *data = pdata;
gboolean exists = FALSE;
gsize validate_len;
+ gsize path_len, pathuri_len;
gs_free char *path = NULL;
- GByteArray *tmp;
+ gs_free char *pathuri = NULL;
g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL);
@@ -1191,18 +1205,16 @@ nm_keyfile_detect_unqualified_path_scheme (const char *base_dir,
* 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. */
- 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_byte_array_unref (tmp);
+ path_len = strlen (path);
+ pathuri_len = (NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + 1) + path_len;
+ pathuri = g_new (char, pathuri_len);
+ memcpy (pathuri, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH));
+ memcpy (&pathuri[NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)], path, path_len + 1);
+ if (nm_setting_802_1x_check_cert_scheme (pathuri, pathuri_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_PATH)
return NULL;
- }
- g_free (path);
- path = (char *) g_byte_array_free (tmp, FALSE);
NM_SET_OUT (out_exists, exists);
- return g_steal_pointer (&path);
+ return g_steal_pointer (&pathuri);
}
#define HAS_SCHEME_PREFIX(bin, bin_len, scheme) \
diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c
index 0d61f91c5d..529029de83 100644
--- a/libnm-core/nm-setting-8021x.c
+++ b/libnm-core/nm-setting-8021x.c
@@ -26,8 +26,9 @@
#include <string.h>
+#include "nm-utils/nm-secret-utils.h"
#include "nm-utils.h"
-#include "crypto.h"
+#include "nm-crypto.h"
#include "nm-utils-private.h"
#include "nm-setting-private.h"
#include "nm-core-enum-types.h"
@@ -60,14 +61,89 @@
* ISBN: 978-1587051548
**/
-G_DEFINE_TYPE (NMSetting8021x, nm_setting_802_1x, NM_TYPE_SETTING)
+/*****************************************************************************/
-#define NM_SETTING_802_1X_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_802_1X, NMSetting8021xPrivate))
+static NMSetting8021xCKFormat
+_crypto_format_to_ck (NMCryptoFileFormat format)
+{
+ G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_UNKNOWN == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_UNKNOWN) );
+ G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_X509 == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_X509) );
+ G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_RAW_KEY == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_RAW_KEY) );
+ G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_PKCS12 == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_PKCS12) );
+
+ nm_assert (NM_IN_SET (format, NM_CRYPTO_FILE_FORMAT_UNKNOWN,
+ NM_CRYPTO_FILE_FORMAT_X509,
+ NM_CRYPTO_FILE_FORMAT_RAW_KEY,
+ NM_CRYPTO_FILE_FORMAT_PKCS12));
+ return (NMSetting8021xCKFormat) format;
+}
-G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_UNKNOWN == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_UNKNOWN) );
-G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_X509 == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_X509) );
-G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_RAW_KEY == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_RAW_KEY) );
-G_STATIC_ASSERT ( (NM_SETTING_802_1X_CK_FORMAT_PKCS12 == (NMSetting8021xCKFormat) NM_CRYPTO_FILE_FORMAT_PKCS12) );
+/*****************************************************************************/
+
+typedef void (*EAPMethodNeedSecretsFunc) (NMSetting8021x *self,
+ GPtrArray *secrets,
+ gboolean phase2);
+
+typedef gboolean (*EAPMethodValidateFunc)(NMSetting8021x *self,
+ gboolean phase2,
+ GError **error);
+
+typedef struct {
+ const char *method;
+ EAPMethodNeedSecretsFunc ns_func;
+ EAPMethodValidateFunc v_func;
+} EAPMethodsTable;
+
+static EAPMethodsTable eap_methods_table[];
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE (NMSetting8021x,
+ PROP_EAP,
+ PROP_IDENTITY,
+ PROP_ANONYMOUS_IDENTITY,
+ PROP_PAC_FILE,
+ PROP_CA_CERT,
+ PROP_CA_CERT_PASSWORD,
+ PROP_CA_CERT_PASSWORD_FLAGS,
+ PROP_CA_PATH,
+ PROP_SUBJECT_MATCH,
+ PROP_ALTSUBJECT_MATCHES,
+ PROP_DOMAIN_SUFFIX_MATCH,
+ PROP_CLIENT_CERT,
+ PROP_CLIENT_CERT_PASSWORD,
+ PROP_CLIENT_CERT_PASSWORD_FLAGS,
+ PROP_PHASE1_PEAPVER,
+ PROP_PHASE1_PEAPLABEL,
+ PROP_PHASE1_FAST_PROVISIONING,
+ PROP_PHASE1_AUTH_FLAGS,
+ PROP_PHASE2_AUTH,
+ PROP_PHASE2_AUTHEAP,
+ PROP_PHASE2_CA_CERT,
+ PROP_PHASE2_CA_CERT_PASSWORD,
+ PROP_PHASE2_CA_CERT_PASSWORD_FLAGS,
+ PROP_PHASE2_CA_PATH,
+ PROP_PHASE2_SUBJECT_MATCH,
+ PROP_PHASE2_ALTSUBJECT_MATCHES,
+ PROP_PHASE2_DOMAIN_SUFFIX_MATCH,
+ PROP_PHASE2_CLIENT_CERT,
+ PROP_PHASE2_CLIENT_CERT_PASSWORD,
+ PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS,
+ PROP_PASSWORD,
+ PROP_PASSWORD_FLAGS,
+ PROP_PASSWORD_RAW,
+ PROP_PASSWORD_RAW_FLAGS,
+ PROP_PRIVATE_KEY,
+ PROP_PRIVATE_KEY_PASSWORD,
+ PROP_PRIVATE_KEY_PASSWORD_FLAGS,
+ PROP_PHASE2_PRIVATE_KEY,
+ PROP_PHASE2_PRIVATE_KEY_PASSWORD,
+ PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS,
+ PROP_PIN,
+ PROP_PIN_FLAGS,
+ PROP_SYSTEM_CA_CERTS,
+ PROP_AUTH_TIMEOUT,
+);
typedef struct {
GSList *eap; /* GSList of strings */
@@ -116,67 +192,509 @@ typedef struct {
int auth_timeout;
} NMSetting8021xPrivate;
-enum {
- PROP_0,
- PROP_EAP,
- PROP_IDENTITY,
- PROP_ANONYMOUS_IDENTITY,
- PROP_PAC_FILE,
- PROP_CA_CERT,
- PROP_CA_CERT_PASSWORD,
- PROP_CA_CERT_PASSWORD_FLAGS,
- PROP_CA_PATH,
- PROP_SUBJECT_MATCH,
- PROP_ALTSUBJECT_MATCHES,
- PROP_DOMAIN_SUFFIX_MATCH,
- PROP_CLIENT_CERT,
- PROP_CLIENT_CERT_PASSWORD,
- PROP_CLIENT_CERT_PASSWORD_FLAGS,
- PROP_PHASE1_PEAPVER,
- PROP_PHASE1_PEAPLABEL,
- PROP_PHASE1_FAST_PROVISIONING,
- PROP_PHASE1_AUTH_FLAGS,
- PROP_PHASE2_AUTH,
- PROP_PHASE2_AUTHEAP,
- PROP_PHASE2_CA_CERT,
- PROP_PHASE2_CA_CERT_PASSWORD,
- PROP_PHASE2_CA_CERT_PASSWORD_FLAGS,
- PROP_PHASE2_CA_PATH,
- PROP_PHASE2_SUBJECT_MATCH,
- PROP_PHASE2_ALTSUBJECT_MATCHES,
- PROP_PHASE2_DOMAIN_SUFFIX_MATCH,
- PROP_PHASE2_CLIENT_CERT,
- PROP_PHASE2_CLIENT_CERT_PASSWORD,
- PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS,
- PROP_PASSWORD,
- PROP_PASSWORD_FLAGS,
- PROP_PASSWORD_RAW,
- PROP_PASSWORD_RAW_FLAGS,
- PROP_PRIVATE_KEY,
- PROP_PRIVATE_KEY_PASSWORD,
- PROP_PRIVATE_KEY_PASSWORD_FLAGS,
- PROP_PHASE2_PRIVATE_KEY,
- PROP_PHASE2_PRIVATE_KEY_PASSWORD,
- PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS,
- PROP_PIN,
- PROP_PIN_FLAGS,
- PROP_SYSTEM_CA_CERTS,
- PROP_AUTH_TIMEOUT,
+G_DEFINE_TYPE (NMSetting8021x, nm_setting_802_1x, NM_TYPE_SETTING)
- LAST_PROP
-};
+#define NM_SETTING_802_1X_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_802_1X, NMSetting8021xPrivate))
+
+/*****************************************************************************/
/**
- * nm_setting_802_1x_new:
+ * nm_setting_802_1x_check_cert_scheme:
+ * @pdata: (allow-none): the data pointer
+ * @length: the length of the data
+ * @error: (allow-none): (out): validation reason
*
- * Creates a new #NMSetting8021x object with default values.
+ * Determines and verifies the blob type.
+ * When setting certificate properties of NMSetting8021x
+ * the blob must be not UNKNOWN (or NULL).
*
- * Returns: the new empty #NMSetting8021x object
+ * Returns: the scheme of the blob or %NM_SETTING_802_1X_CK_SCHEME_UNKNOWN.
+ * For NULL it also returns NM_SETTING_802_1X_CK_SCHEME_UNKNOWN.
+ *
+ * Since: 1.2
**/
-NMSetting *
-nm_setting_802_1x_new (void)
+NMSetting8021xCKScheme
+nm_setting_802_1x_check_cert_scheme (gconstpointer pdata, gsize length, GError **error)
{
- return (NMSetting *) g_object_new (NM_TYPE_SETTING_802_1X, NULL);
+ const char *data = pdata;
+ NMSetting8021xCKScheme scheme;
+ gsize prefix_length;
+
+ g_return_val_if_fail (!length || data, NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
+
+ if (!length || !data) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("binary data missing"));
+ return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+ }
+
+ if ( length >= NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)
+ && !memcmp (data, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH))) {
+ scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
+ prefix_length = NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
+ } else if ( length >= NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)
+ && !memcmp (data, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11))) {
+ scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11;
+ prefix_length = NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11);
+ } else {
+ scheme = NM_SETTING_802_1X_CK_SCHEME_BLOB;
+ prefix_length = 0;
+ }
+
+ if (scheme != NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+ /* An actual URI must 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 (data[length - 1] != '\0') {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("URI not NUL terminated"));
+ return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+ }
+ length--;
+
+ if (length <= prefix_length) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("URI is empty"));
+ return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+ }
+
+ if (!g_utf8_validate (data + prefix_length, length - prefix_length, NULL)) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("URI is not valid UTF-8"));
+ return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+ }
+ }
+
+ return scheme;
+}
+
+NMSetting8021xCKScheme
+_nm_setting_802_1x_cert_get_scheme (GBytes *bytes, GError **error)
+{
+ const char *data;
+ gsize length;
+
+ if (!bytes) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("data missing"));
+ return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+ }
+
+ data = g_bytes_get_data (bytes, &length);
+ return nm_setting_802_1x_check_cert_scheme (data, length, error);
+}
+
+static gboolean
+_cert_verify_scheme (NMSetting8021xCKScheme scheme,
+ GBytes *bytes,
+ GError **error)
+{
+ GError *local = NULL;
+ NMSetting8021xCKScheme scheme_detected;
+
+ nm_assert (bytes);
+
+ scheme_detected = _nm_setting_802_1x_cert_get_scheme (bytes, &local);
+ if (scheme_detected == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("certificate is invalid: %s"), local->message);
+ return FALSE;
+ }
+
+ if (scheme_detected != scheme) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("certificate detected as invalid scheme"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GBytes *
+_nm_setting_802_1x_cert_value_to_bytes (NMSetting8021xCKScheme scheme,
+ const guint8 *val_bin,
+ gssize val_len,
+ GError **error)
+{
+ gs_unref_bytes GBytes *bytes = NULL;
+ guint8 *mem;
+ gsize total_len;
+
+ nm_assert (val_bin);
+
+ switch (scheme) {
+ case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
+ if (val_len < 0)
+ val_len = strlen ((char *) val_bin) + 1;
+
+ bytes = g_bytes_new (val_bin, val_len);
+ break;
+ case NM_SETTING_802_1X_CK_SCHEME_PATH:
+ if (val_len < 0)
+ val_len = strlen ((char *) val_bin) + 1;
+
+ total_len = NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH) + ((gsize) val_len);
+
+ mem = g_new (guint8, total_len);
+ memcpy (mem, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH));
+ memcpy (&mem[NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)], val_bin, val_len);
+ bytes = g_bytes_new_take (mem, total_len);
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ if (!_cert_verify_scheme (scheme, bytes, error))
+ return NULL;
+
+ return g_steal_pointer (&bytes);
+}
+
+static const char *
+_cert_get_path (GBytes *bytes)
+{
+ const guint8 *bin;
+
+ nm_assert (bytes);
+ nm_assert (g_bytes_get_size (bytes) >= NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH));
+
+ bin = g_bytes_get_data (bytes, NULL);
+
+ nm_assert (bin);
+ nm_assert (bin[g_bytes_get_size (bytes) - 1] == '\0');
+ nm_assert (g_str_has_prefix ((const char *) bin, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH));
+
+ return (const char *) &bin[NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)];
+}
+
+#define _cert_assert_scheme(cert, check_scheme, ret_val) \
+ G_STMT_START { \
+ NMSetting8021xCKScheme scheme; \
+ \
+ scheme = _nm_setting_802_1x_cert_get_scheme ((cert), NULL); \
+ if (scheme != check_scheme) { \
+ g_return_val_if_fail (scheme == check_scheme, ret_val); \
+ return ret_val; \
+ } \
+ } G_STMT_END
+
+#define _cert_impl_get_scheme(setting, cert_field) \
+ G_STMT_START { \
+ NMSetting8021x *const _setting = (setting); \
+ GBytes *_cert; \
+ \
+ g_return_val_if_fail (NM_IS_SETTING_802_1X (_setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); \
+ \
+ _cert = NM_SETTING_802_1X_GET_PRIVATE (_setting)->cert_field; \
+ \
+ return _nm_setting_802_1x_cert_get_scheme (_cert, NULL); \
+ } G_STMT_END
+
+#define _cert_impl_get_blob(setting, cert_field) \
+ G_STMT_START { \
+ NMSetting8021x *const _setting = (setting); \
+ GBytes *_cert; \
+ \
+ g_return_val_if_fail (NM_IS_SETTING_802_1X (_setting), NULL); \
+ \
+ _cert = NM_SETTING_802_1X_GET_PRIVATE (_setting)->cert_field; \
+ \
+ _cert_assert_scheme (_cert, NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL); \
+ \
+ return _cert; \
+ } G_STMT_END
+
+#define _cert_impl_get_path(setting, cert_field) \
+ G_STMT_START { \
+ NMSetting8021x *const _setting = (setting); \
+ GBytes *_cert; \
+ \
+ g_return_val_if_fail (NM_IS_SETTING_802_1X (_setting), NULL); \
+ \
+ _cert = NM_SETTING_802_1X_GET_PRIVATE (_setting)->cert_field; \
+ \
+ _cert_assert_scheme (_cert, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL); \
+ \
+ return _cert_get_path (_cert); \
+ } G_STMT_END
+
+#define _cert_impl_get_uri(setting, cert_field) \
+ G_STMT_START { \
+ NMSetting8021x *const _setting = (setting); \
+ GBytes *_cert; \
+ \
+ g_return_val_if_fail (NM_IS_SETTING_802_1X (_setting), NULL); \
+ \
+ _cert = NM_SETTING_802_1X_GET_PRIVATE (_setting)->cert_field; \
+ \
+ _cert_assert_scheme (_cert, NM_SETTING_802_1X_CK_SCHEME_PKCS11, NULL); \
+ \
+ return g_bytes_get_data (_cert, NULL); \
+ } G_STMT_END
+
+static gboolean
+_cert_impl_set (NMSetting8021x *setting,
+ _PropertyEnums property,
+ const char *value,
+ const char *password,
+ NMSetting8021xCKScheme scheme,
+ NMSetting8021xCKFormat *out_format,
+ GError **error)
+{
+ NMSetting8021xPrivate *priv;
+ NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ gs_unref_bytes GBytes *cert = NULL;
+ GBytes **p_cert = NULL;
+ GBytes **p_client_cert = NULL;
+ char **p_password = NULL;
+ _PropertyEnums notify_cert = property;
+ _PropertyEnums notify_password = PROP_0;
+ _PropertyEnums notify_client_cert = PROP_0;
+
+ g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+ if (value) {
+ g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+ g_return_val_if_fail (NM_IN_SET (scheme, NM_SETTING_802_1X_CK_SCHEME_BLOB,
+ NM_SETTING_802_1X_CK_SCHEME_PATH,
+ NM_SETTING_802_1X_CK_SCHEME_PKCS11), FALSE);
+ }
+
+ if (!value) {
+ /* coerce password to %NULL. It should be already. */
+ password = NULL;
+ }
+
+ priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
+
+ if (!value) {
+ /* pass. */
+ } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
+ cert = _nm_setting_802_1x_cert_value_to_bytes (scheme, (guint8 *) value, -1, error);
+ if (!cert)
+ goto err;
+ } else {
+ gs_unref_bytes GBytes *file = NULL;
+
+ if (NM_IN_SET (property, PROP_PRIVATE_KEY,
+ PROP_PHASE2_PRIVATE_KEY)) {
+ file = nm_crypto_read_file (value, error);
+ if (!file)
+ goto err;
+ format = nm_crypto_verify_private_key_data (g_bytes_get_data (file, NULL),
+ g_bytes_get_size (file),
+ password,
+ NULL,
+ error);
+ if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN)
+ goto err;
+ } else {
+ if (!nm_crypto_load_and_verify_certificate (value, &format, &file, error))
+ goto err;
+ }
+
+ nm_assert (format != NM_CRYPTO_FILE_FORMAT_UNKNOWN);
+ nm_assert (file);
+
+ if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
+ cert = g_steal_pointer (&file);
+ if (!_cert_verify_scheme (scheme, cert, error))
+ goto err;
+ } else {
+ cert = _nm_setting_802_1x_cert_value_to_bytes (scheme, (guint8 *) value, -1, error);
+ if (!cert)
+ goto err;
+ }
+ }
+
+ switch (property) {
+ case PROP_CA_CERT:
+ case PROP_PHASE2_CA_CERT:
+ if ( value
+ && scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11
+ && format != NM_CRYPTO_FILE_FORMAT_X509) {
+ /* wpa_supplicant can only use raw x509 CA certs */
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("CA certificate must be in X.509 format"));
+ goto err;
+ }
+ p_cert = (property == PROP_CA_CERT)
+ ? &priv->ca_cert
+ : &priv->phase2_ca_cert;
+ break;
+ case PROP_CLIENT_CERT:
+ case PROP_PHASE2_CLIENT_CERT:
+ if ( value
+ && scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11
+ && !NM_IN_SET (format, NM_CRYPTO_FILE_FORMAT_X509,
+ NM_CRYPTO_FILE_FORMAT_PKCS12)) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("invalid certificate format"));
+ goto err;
+ }
+ p_cert = (property == PROP_CLIENT_CERT)
+ ? &priv->client_cert
+ : &priv->phase2_client_cert;
+ break;
+ case PROP_PRIVATE_KEY:
+ p_cert = &priv->private_key;
+ p_password = &priv->private_key_password;
+ p_client_cert = &priv->client_cert;
+ notify_password = PROP_PRIVATE_KEY_PASSWORD;
+ notify_client_cert = PROP_CLIENT_CERT;
+ break;
+ case PROP_PHASE2_PRIVATE_KEY:
+ p_cert = &priv->phase2_private_key;
+ p_password = &priv->phase2_private_key_password;
+ p_client_cert = &priv->phase2_client_cert;
+ notify_password = PROP_PHASE2_PRIVATE_KEY_PASSWORD;
+ notify_client_cert = PROP_PHASE2_CLIENT_CERT;
+ break;
+ default:
+ nm_assert_not_reached ();
+ break;
+ }
+
+ /* As required by NM and wpa_supplicant, set the client-cert
+ * property to the same PKCS#12 data.
+ */
+ if ( cert
+ && p_client_cert
+ && format == NM_CRYPTO_FILE_FORMAT_PKCS12
+ && !nm_gbytes_equal0 (cert, *p_client_cert)) {
+ g_bytes_unref (*p_client_cert);
+ *p_client_cert = g_bytes_ref (cert);
+ } else
+ notify_client_cert = PROP_0;
+
+ if ( p_cert
+ && !nm_gbytes_equal0 (cert, *p_cert)) {
+ g_bytes_unref (*p_cert);
+ *p_cert = g_steal_pointer (&cert);
+ } else
+ notify_cert = PROP_0;
+
+ if ( p_password
+ && !nm_streq0 (password, *p_password)) {
+ nm_free_secret (*p_password);
+ *p_password = g_strdup (password);
+ } else
+ notify_password = PROP_0;
+
+ nm_gobject_notify_together (setting, notify_cert,
+ notify_password,
+ notify_client_cert);
+
+ NM_SET_OUT (out_format, _crypto_format_to_ck (format));
+ return TRUE;
+
+err:
+ g_prefix_error (error,
+ "%s.%s: ",
+ NM_SETTING_802_1X_SETTING_NAME,
+ obj_properties[property]->name);
+ NM_SET_OUT (out_format, NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
+ return FALSE;
+}
+
+static NMSetting8021xCKFormat
+_cert_impl_get_key_format_from_bytes (GBytes *private_key)
+{
+ const char *path;
+ GError *error = NULL;
+
+ if (!private_key)
+ return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+
+ switch (_nm_setting_802_1x_cert_get_scheme (private_key, NULL)) {
+ case NM_SETTING_802_1X_CK_SCHEME_BLOB:
+ if (nm_crypto_is_pkcs12_data (g_bytes_get_data (private_key, NULL),
+ g_bytes_get_size (private_key),
+ NULL))
+ return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
+ return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
+ case NM_SETTING_802_1X_CK_SCHEME_PATH:
+ path = _cert_get_path (private_key);
+ if (nm_crypto_is_pkcs12_file (path, &error))
+ return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
+ if (error && error->domain == G_FILE_ERROR) {
+ g_error_free (error);
+ return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+ }
+ g_error_free (error);
+ return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
+ default:
+ break;
+ }
+
+ return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+}
+#define _cert_impl_get_key_format(setting, private_key_field) \
+ ({ \
+ NMSetting8021x *_setting = (setting); \
+ NMSetting8021xPrivate *_priv; \
+ \
+ g_return_val_if_fail (NM_IS_SETTING_802_1X (_setting), NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); \
+ \
+ _priv = NM_SETTING_802_1X_GET_PRIVATE (_setting); \
+ _cert_impl_get_key_format_from_bytes (_priv->private_key_field); \
+ })
+
+static gboolean
+_cert_verify_property (GBytes *bytes,
+ const char *prop_name,
+ const char *password,
+ const char *password_prop_name,
+ GError **error)
+{
+ GError *local = NULL;
+ NMSetting8021xCKScheme scheme;
+
+ if (!bytes)
+ return TRUE;
+
+ scheme = _nm_setting_802_1x_cert_get_scheme (bytes, &local);
+ if (scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("certificate is invalid: %s"), local->message);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, prop_name);
+ g_error_free (local);
+ return FALSE;
+ }
+
+ if (password && (scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("password is not supported when certificate is not on a PKCS#11 token"));
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, password_prop_name);
+ return FALSE;
+ }
+
+ return TRUE;
}
/*****************************************************************************/
@@ -251,7 +769,7 @@ nm_setting_802_1x_add_eap_method (NMSetting8021x *setting, const char *eap)
}
priv->eap = g_slist_append (priv->eap, g_ascii_strdown (eap, -1));
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP);
+ _notify (setting, PROP_EAP);
return TRUE;
}
@@ -276,7 +794,7 @@ nm_setting_802_1x_remove_eap_method (NMSetting8021x *setting, guint32 i)
g_free (elt->data);
priv->eap = g_slist_delete_link (priv->eap, elt);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP);
+ _notify (setting, PROP_EAP);
}
/**
@@ -302,7 +820,7 @@ nm_setting_802_1x_remove_eap_method_by_value (NMSetting8021x *setting,
for (iter = priv->eap; iter; iter = g_slist_next (iter)) {
if (!strcmp (eap, (char *) iter->data)) {
priv->eap = g_slist_delete_link (priv->eap, iter);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP);
+ _notify (setting, PROP_EAP);
return TRUE;
}
}
@@ -325,7 +843,7 @@ nm_setting_802_1x_clear_eap_methods (NMSetting8021x *setting)
priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
g_slist_free_full (priv->eap, g_free);
priv->eap = NULL;
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_EAP);
+ _notify (setting, PROP_EAP);
}
/**
@@ -421,134 +939,6 @@ nm_setting_802_1x_get_system_ca_certs (NMSetting8021x *setting)
return NM_SETTING_802_1X_GET_PRIVATE (setting)->system_ca_certs;
}
-static NMSetting8021xCKScheme
-get_cert_scheme (GBytes *bytes, GError **error)
-{
- const char *data;
- gsize length;
-
- if (!bytes) {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("data missing"));
- return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
- }
-
- data = g_bytes_get_data (bytes, &length);
- return nm_setting_802_1x_check_cert_scheme (data, length, error);
-}
-
-/**
- * nm_setting_802_1x_check_cert_scheme:
- * @pdata: (allow-none): the data pointer
- * @length: the length of the data
- * @error: (allow-none): (out): validation reason
- *
- * Determines and verifies the blob type.
- * When setting certificate properties of NMSetting8021x
- * the blob must be not UNKNOWN (or NULL).
- *
- * Returns: the scheme of the blob or %NM_SETTING_802_1X_CK_SCHEME_UNKNOWN.
- * For NULL it also returns NM_SETTING_802_1X_CK_SCHEME_UNKNOWN.
- *
- * Since: 1.2
- **/
-NMSetting8021xCKScheme
-nm_setting_802_1x_check_cert_scheme (gconstpointer pdata, gsize length, GError **error)
-{
- const char *data = pdata;
- NMSetting8021xCKScheme scheme;
- gsize prefix_length;
-
- g_return_val_if_fail (!length || data, NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
-
- if (!length || !data) {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("binary data missing"));
- return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
- }
-
- if ( length >= NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)
- && !memcmp (data, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH))) {
- scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
- prefix_length = NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
- } else if ( length >= NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)
- && !memcmp (data, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11))) {
- scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11;
- prefix_length = NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11);
- } else {
- scheme = NM_SETTING_802_1X_CK_SCHEME_BLOB;
- prefix_length = 0;
- }
-
- if (scheme != NM_SETTING_802_1X_CK_SCHEME_BLOB) {
- /* An actual URI must 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 (data[length - 1] != '\0') {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("URI not NUL terminated"));
- return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
- }
- length--;
-
- if (length <= prefix_length) {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("URI is empty"));
- return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
- }
-
- if (!g_utf8_validate (data + prefix_length, length - prefix_length, NULL)) {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("URI is not valid UTF-8"));
- return NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
- }
- }
-
- return scheme;
-}
-
-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. */
- if (nm_setting_802_1x_check_cert_scheme (array->data, array->len, NULL) != 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
@@ -563,9 +953,7 @@ load_and_verify_certificate (const char *cert_path,
NMSetting8021xCKScheme
nm_setting_802_1x_get_ca_cert_scheme (NMSetting8021x *setting)
{
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
-
- return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert, NULL);
+ _cert_impl_get_scheme (setting, ca_cert);
}
/**
@@ -584,14 +972,7 @@ nm_setting_802_1x_get_ca_cert_scheme (NMSetting8021x *setting)
GBytes *
nm_setting_802_1x_get_ca_cert_blob (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_ca_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL);
-
- return NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert;
+ _cert_impl_get_blob (setting, ca_cert);
}
/**
@@ -610,16 +991,7 @@ nm_setting_802_1x_get_ca_cert_blob (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_ca_cert_path (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_ca_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert, NULL);
- return (const char *)data + strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
+ _cert_impl_get_path (setting, ca_cert);
}
/**
@@ -641,35 +1013,7 @@ nm_setting_802_1x_get_ca_cert_path (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_ca_cert_uri (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_ca_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert, NULL);
- return (const char *)data;
-}
-
-static GBytes *
-path_to_scheme_value (const char *path)
-{
- GByteArray *array;
- gsize len;
-
- g_return_val_if_fail (path != NULL && path[0], NULL);
-
- len = strlen (path);
-
- /* Add the path scheme tag to the front, then the filename */
- array = g_byte_array_sized_new (len + strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH) + 1);
- g_byte_array_append (array, (const guint8 *) NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH));
- g_byte_array_append (array, (const guint8 *) path, len);
- g_byte_array_append (array, (const guint8 *) "\0", 1);
-
- return g_byte_array_free_to_bytes (array);
+ _cert_impl_get_uri (setting, ca_cert);
}
/**
@@ -698,65 +1042,7 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *setting,
NMSetting8021xCKFormat *out_format,
GError **error)
{
- NMSetting8021xPrivate *priv;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- GByteArray *data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
-
- if (value) {
- g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
- g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11,
- FALSE);
- }
-
- if (out_format)
- g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE);
-
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- g_clear_pointer (&priv->ca_cert, g_bytes_unref);
-
- if (!value) {
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CA_CERT);
- return TRUE;
- }
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- priv->ca_cert = g_bytes_new (value, strlen (value) + 1);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CA_CERT);
- return TRUE;
- }
-
- data = load_and_verify_certificate (value, scheme, &format, error);
- if (data) {
- /* wpa_supplicant can only use raw x509 CA certs */
- if (format == NM_CRYPTO_FILE_FORMAT_X509) {
- if (out_format)
- *out_format = NM_SETTING_802_1X_CK_FORMAT_X509;
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
- priv->ca_cert = g_byte_array_free_to_bytes (data);
- data = NULL;
- } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
- priv->ca_cert = path_to_scheme_value (value);
- else
- g_assert_not_reached ();
- } else {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("CA certificate must be in X.509 format"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT);
- }
- if (data)
- g_byte_array_unref (data);
- }
-
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CA_CERT);
- return priv->ca_cert != NULL;
+ return _cert_impl_set (setting, PROP_CA_CERT, value, NULL, scheme, out_format, error);
}
/**
@@ -880,7 +1166,7 @@ nm_setting_802_1x_add_altsubject_match (NMSetting8021x *setting,
priv->altsubject_matches = g_slist_append (priv->altsubject_matches,
g_strdup (altsubject_match));
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_ALTSUBJECT_MATCHES);
return TRUE;
}
@@ -905,7 +1191,7 @@ nm_setting_802_1x_remove_altsubject_match (NMSetting8021x *setting, guint32 i)
g_free (elt->data);
priv->altsubject_matches = g_slist_delete_link (priv->altsubject_matches, elt);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_ALTSUBJECT_MATCHES);
}
/**
@@ -932,7 +1218,7 @@ nm_setting_802_1x_remove_altsubject_match_by_value (NMSetting8021x *setting,
for (iter = priv->altsubject_matches; iter; iter = g_slist_next (iter)) {
if (!strcmp (altsubject_match, (char *) iter->data)) {
priv->altsubject_matches = g_slist_delete_link (priv->altsubject_matches, iter);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_ALTSUBJECT_MATCHES);
return TRUE;
}
}
@@ -955,7 +1241,7 @@ nm_setting_802_1x_clear_altsubject_matches (NMSetting8021x *setting)
priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
g_slist_free_full (priv->altsubject_matches, g_free);
priv->altsubject_matches = NULL;
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_ALTSUBJECT_MATCHES);
}
/**
@@ -988,9 +1274,7 @@ nm_setting_802_1x_get_domain_suffix_match (NMSetting8021x *setting)
NMSetting8021xCKScheme
nm_setting_802_1x_get_client_cert_scheme (NMSetting8021x *setting)
{
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
-
- return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert, NULL);
+ _cert_impl_get_scheme (setting, client_cert);
}
/**
@@ -1006,14 +1290,7 @@ nm_setting_802_1x_get_client_cert_scheme (NMSetting8021x *setting)
GBytes *
nm_setting_802_1x_get_client_cert_blob (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_client_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL);
-
- return NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert;
+ _cert_impl_get_blob (setting, client_cert);
}
/**
@@ -1029,16 +1306,7 @@ nm_setting_802_1x_get_client_cert_blob (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_client_cert_path (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_client_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert, NULL);
- return (const char *)data + strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
+ _cert_impl_get_path (setting, client_cert);
}
/**
@@ -1060,16 +1328,7 @@ nm_setting_802_1x_get_client_cert_path (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_client_cert_uri (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_client_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert, NULL);
- return (const char *)data;
+ _cert_impl_get_uri (setting, client_cert);
}
/**
@@ -1102,77 +1361,7 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *setting,
NMSetting8021xCKFormat *out_format,
GError **error)
{
- NMSetting8021xPrivate *priv;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- GByteArray *data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
-
- if (value) {
- g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
- g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11,
- FALSE);
- }
-
- if (out_format)
- g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE);
-
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- g_clear_pointer (&priv->client_cert, g_bytes_unref);
-
- if (!value) {
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CLIENT_CERT);
- return TRUE;
- }
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- priv->client_cert = g_bytes_new (value, strlen (value) + 1);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CLIENT_CERT);
- return TRUE;
- }
-
- data = load_and_verify_certificate (value, scheme, &format, error);
- if (data) {
- gboolean valid = FALSE;
-
- switch (format) {
- case NM_CRYPTO_FILE_FORMAT_X509:
- if (out_format)
- *out_format = NM_SETTING_802_1X_CK_FORMAT_X509;
- valid = TRUE;
- break;
- case NM_CRYPTO_FILE_FORMAT_PKCS12:
- if (out_format)
- *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12;
- valid = TRUE;
- break;
- default:
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("invalid certificate format"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT);
- break;
- }
-
- if (valid) {
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
- priv->client_cert = g_byte_array_free_to_bytes (data);
- data = NULL;
- } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
- priv->client_cert = path_to_scheme_value (value);
- else
- g_assert_not_reached ();
- }
- if (data)
- g_byte_array_unref (data);
- }
-
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CLIENT_CERT);
- return priv->client_cert != NULL;
+ return _cert_impl_set (setting, PROP_CLIENT_CERT, value, NULL, scheme, out_format, error);
}
/**
@@ -1341,9 +1530,7 @@ nm_setting_802_1x_get_phase2_ca_path (NMSetting8021x *setting)
NMSetting8021xCKScheme
nm_setting_802_1x_get_phase2_ca_cert_scheme (NMSetting8021x *setting)
{
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
-
- return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert, NULL);
+ _cert_impl_get_scheme (setting, phase2_ca_cert);
}
/**
@@ -1362,14 +1549,7 @@ nm_setting_802_1x_get_phase2_ca_cert_scheme (NMSetting8021x *setting)
GBytes *
nm_setting_802_1x_get_phase2_ca_cert_blob (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL);
-
- return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert;
+ _cert_impl_get_blob (setting, phase2_ca_cert);
}
/**
@@ -1388,16 +1568,7 @@ nm_setting_802_1x_get_phase2_ca_cert_blob (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_phase2_ca_cert_path (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert, NULL);
- return (const char *)data + strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
+ _cert_impl_get_path (setting, phase2_ca_cert);
}
/**
@@ -1419,16 +1590,7 @@ nm_setting_802_1x_get_phase2_ca_cert_path (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_phase2_ca_cert_uri (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert, NULL);
- return (const char *)data;
+ _cert_impl_get_uri (setting, phase2_ca_cert);
}
/**
@@ -1457,65 +1619,7 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *setting,
NMSetting8021xCKFormat *out_format,
GError **error)
{
- NMSetting8021xPrivate *priv;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- GByteArray *data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
-
- if (value) {
- g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
- g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11,
- FALSE);
- }
-
- if (out_format)
- g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE);
-
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- g_clear_pointer (&priv->phase2_ca_cert, g_bytes_unref);
-
- if (!value) {
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CA_CERT);
- return TRUE;
- }
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- priv->phase2_ca_cert = g_bytes_new (value, strlen (value) + 1);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CA_CERT);
- return TRUE;
- }
-
- data = load_and_verify_certificate (value, scheme, &format, error);
- if (data) {
- /* wpa_supplicant can only use raw x509 CA certs */
- if (format == NM_CRYPTO_FILE_FORMAT_X509) {
- if (out_format)
- *out_format = NM_SETTING_802_1X_CK_FORMAT_X509;
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
- priv->phase2_ca_cert = g_byte_array_free_to_bytes (data);
- data = NULL;
- } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
- priv->phase2_ca_cert = path_to_scheme_value (value);
- else
- g_assert_not_reached ();
- } else {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("invalid certificate format"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_CA_CERT);
- }
- if (data)
- g_byte_array_unref (data);
- }
-
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CA_CERT);
- return priv->phase2_ca_cert != NULL;
+ return _cert_impl_set (setting, PROP_PHASE2_CA_CERT, value, NULL, scheme, out_format, error);
}
/**
@@ -1656,7 +1760,7 @@ nm_setting_802_1x_add_phase2_altsubject_match (NMSetting8021x *setting,
priv->phase2_altsubject_matches = g_slist_append (priv->phase2_altsubject_matches,
g_strdup (phase2_altsubject_match));
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_PHASE2_ALTSUBJECT_MATCHES);
return TRUE;
}
@@ -1681,7 +1785,7 @@ nm_setting_802_1x_remove_phase2_altsubject_match (NMSetting8021x *setting, guint
g_free (elt->data);
priv->phase2_altsubject_matches = g_slist_delete_link (priv->phase2_altsubject_matches, elt);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_PHASE2_ALTSUBJECT_MATCHES);
}
/**
@@ -1708,7 +1812,7 @@ nm_setting_802_1x_remove_phase2_altsubject_match_by_value (NMSetting8021x *setti
for (iter = priv->phase2_altsubject_matches; iter; iter = g_slist_next (iter)) {
if (!strcmp (phase2_altsubject_match, (char *) iter->data)) {
priv->phase2_altsubject_matches = g_slist_delete_link (priv->phase2_altsubject_matches, iter);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_PHASE2_ALTSUBJECT_MATCHES);
return TRUE;
}
}
@@ -1731,7 +1835,7 @@ nm_setting_802_1x_clear_phase2_altsubject_matches (NMSetting8021x *setting)
priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
g_slist_free_full (priv->phase2_altsubject_matches, g_free);
priv->phase2_altsubject_matches = NULL;
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES);
+ _notify (setting, PROP_PHASE2_ALTSUBJECT_MATCHES);
}
/**
@@ -1751,9 +1855,7 @@ nm_setting_802_1x_clear_phase2_altsubject_matches (NMSetting8021x *setting)
NMSetting8021xCKScheme
nm_setting_802_1x_get_phase2_client_cert_scheme (NMSetting8021x *setting)
{
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
-
- return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert, NULL);
+ _cert_impl_get_scheme (setting, phase2_client_cert);
}
/**
@@ -1769,14 +1871,7 @@ nm_setting_802_1x_get_phase2_client_cert_scheme (NMSetting8021x *setting)
GBytes *
nm_setting_802_1x_get_phase2_client_cert_blob (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_client_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL);
-
- return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert;
+ _cert_impl_get_blob (setting, phase2_client_cert);
}
/**
@@ -1792,16 +1887,7 @@ nm_setting_802_1x_get_phase2_client_cert_blob (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_phase2_client_cert_path (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_client_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert, NULL);
- return (const char *)data + strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
+ _cert_impl_get_path (setting, phase2_client_cert);
}
/**
@@ -1823,16 +1909,7 @@ nm_setting_802_1x_get_phase2_client_cert_path (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_phase2_client_cert_uri (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_client_cert_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert, NULL);
- return (const char *)data;
+ _cert_impl_get_uri (setting, phase2_client_cert);
}
/**
@@ -1865,78 +1942,7 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *setting,
NMSetting8021xCKFormat *out_format,
GError **error)
{
- NMSetting8021xPrivate *priv;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- GByteArray *data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
-
- if (value) {
- g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
- g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11,
- FALSE);
- }
-
- if (out_format)
- g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE);
-
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- g_clear_pointer (&priv->phase2_client_cert, g_bytes_unref);
-
- if (!value) {
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CLIENT_CERT);
- return TRUE;
- }
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- priv->phase2_client_cert = g_bytes_new (value, strlen (value) + 1);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CLIENT_CERT);
- return TRUE;
- }
-
- data = load_and_verify_certificate (value, scheme, &format, error);
- if (data) {
- gboolean valid = FALSE;
-
- /* wpa_supplicant can only use raw x509 CA certs */
- switch (format) {
- case NM_CRYPTO_FILE_FORMAT_X509:
- if (out_format)
- *out_format = NM_SETTING_802_1X_CK_FORMAT_X509;
- valid = TRUE;
- break;
- case NM_CRYPTO_FILE_FORMAT_PKCS12:
- if (out_format)
- *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12;
- valid = TRUE;
- break;
- default:
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("invalid certificate format"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_CLIENT_CERT);
- break;
- }
-
- if (valid) {
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
- priv->phase2_client_cert = g_byte_array_free_to_bytes (data);
- data = NULL;
- } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
- priv->phase2_client_cert = path_to_scheme_value (value);
- else
- g_assert_not_reached ();
- }
- if (data)
- g_byte_array_unref (data);
- }
-
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CLIENT_CERT);
- return priv->phase2_client_cert != NULL;
+ return _cert_impl_set (setting, PROP_PHASE2_CLIENT_CERT, value, NULL, scheme, out_format, error);
}
/**
@@ -2081,9 +2087,7 @@ nm_setting_802_1x_get_pin_flags (NMSetting8021x *setting)
NMSetting8021xCKScheme
nm_setting_802_1x_get_private_key_scheme (NMSetting8021x *setting)
{
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
-
- return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key, NULL);
+ _cert_impl_get_scheme (setting, private_key);
}
/**
@@ -2103,14 +2107,7 @@ nm_setting_802_1x_get_private_key_scheme (NMSetting8021x *setting)
GBytes *
nm_setting_802_1x_get_private_key_blob (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_private_key_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL);
-
- return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key;
+ _cert_impl_get_blob (setting, private_key);
}
/**
@@ -2126,16 +2123,7 @@ nm_setting_802_1x_get_private_key_blob (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_private_key_path (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_private_key_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key, NULL);
- return (const char *)data + strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
+ _cert_impl_get_path (setting, private_key);
}
/**
@@ -2157,42 +2145,7 @@ nm_setting_802_1x_get_private_key_path (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_private_key_uri (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_private_key_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key, NULL);
- return (const char *)data;
-}
-
-static void
-free_secure_bytes (gpointer data)
-{
- GByteArray *array = data;
-
- memset (array->data, 0, array->len);
- g_byte_array_unref (array);
-}
-
-static GBytes *
-file_to_secure_bytes (const char *filename)
-{
- char *contents;
- GByteArray *array = NULL;
- gsize length = 0;
-
- if (g_file_get_contents (filename, &contents, &length, NULL)) {
- array = g_byte_array_sized_new (length);
- g_byte_array_append (array, (guint8 *) contents, length);
- memset (contents, 0, length);
- g_free (contents);
- return g_bytes_new_with_free_func (array->data, array->len, free_secure_bytes, array);
- }
- return NULL;
+ _cert_impl_get_uri (setting, private_key);
}
/**
@@ -2242,88 +2195,7 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *setting,
NMSetting8021xCKFormat *out_format,
GError **error)
{
- NMSetting8021xPrivate *priv;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- gboolean password_changed = FALSE;
- GError *local_err = NULL;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
-
- if (value) {
- g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
- g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11,
- FALSE);
- }
-
- if (out_format)
- g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE);
-
- /* Ensure the private key is a recognized format and if the password was
- * given, that it decrypts the private key.
- */
- if (value && scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- format = crypto_verify_private_key (value, password, NULL, &local_err);
- if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- local_err ? local_err->message : _("invalid private key"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY);
- g_clear_error (&local_err);
- return FALSE;
- }
- }
-
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- if (value == NULL) {
- if (priv->private_key) {
- g_clear_pointer (&priv->private_key, g_bytes_unref);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY);
- }
- if (nm_clear_g_free (&priv->private_key_password))
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD);
- return TRUE;
- }
-
- /* this makes password self-assignment safe. */
- if (!nm_streq0 (priv->private_key_password, password)) {
- g_free (priv->private_key_password);
- priv->private_key_password = g_strdup (password);
- password_changed = TRUE;
- }
-
- g_bytes_unref (priv->private_key);
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
- /* FIXME: potential race after verifying the private key above */
- /* FIXME: ensure blob doesn't start with file:// */
- priv->private_key = file_to_secure_bytes (value);
- nm_assert (priv->private_key);
- } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
- priv->private_key = path_to_scheme_value (value);
- else {
- nm_assert (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11);
- priv->private_key = g_bytes_new (value, strlen (value) + 1);
- }
-
- /* As required by NM and wpa_supplicant, set the client-cert
- * property to the same PKCS#12 data.
- */
- if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) {
- if (priv->client_cert)
- g_bytes_unref (priv->client_cert);
- priv->client_cert = g_bytes_ref (priv->private_key);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_CLIENT_CERT);
- }
-
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY);
- if (password_changed)
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD);
-
- NM_SET_OUT (out_format, (NMSetting8021xCKFormat) format);
- return priv->private_key != NULL;
+ return _cert_impl_set (setting, PROP_PRIVATE_KEY, value, password, scheme, out_format, error);
}
/**
@@ -2367,38 +2239,7 @@ nm_setting_802_1x_get_private_key_password_flags (NMSetting8021x *setting)
NMSetting8021xCKFormat
nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting)
{
- NMSetting8021xPrivate *priv;
- const char *path;
- GError *error = NULL;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- if (!priv->private_key)
- return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
-
- switch (nm_setting_802_1x_get_private_key_scheme (setting)) {
- case NM_SETTING_802_1X_CK_SCHEME_BLOB:
- if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL),
- g_bytes_get_size (priv->private_key),
- NULL))
- return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
- return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
- case NM_SETTING_802_1X_CK_SCHEME_PATH:
- path = nm_setting_802_1x_get_private_key_path (setting);
- if (crypto_is_pkcs12_file (path, &error))
- return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
- if (error && error->domain == G_FILE_ERROR) {
- g_error_free (error);
- return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
- }
- g_error_free (error);
- return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
- default:
- break;
- }
-
- return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+ return _cert_impl_get_key_format (setting, private_key);
}
/**
@@ -2449,9 +2290,7 @@ nm_setting_802_1x_get_phase2_private_key_password_flags (NMSetting8021x *setting
NMSetting8021xCKScheme
nm_setting_802_1x_get_phase2_private_key_scheme (NMSetting8021x *setting)
{
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
-
- return get_cert_scheme (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key, NULL);
+ _cert_impl_get_scheme (setting, phase2_private_key);
}
/**
@@ -2471,14 +2310,7 @@ nm_setting_802_1x_get_phase2_private_key_scheme (NMSetting8021x *setting)
GBytes *
nm_setting_802_1x_get_phase2_private_key_blob (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_private_key_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB, NULL);
-
- return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key;
+ _cert_impl_get_blob (setting, phase2_private_key);
}
/**
@@ -2494,16 +2326,7 @@ nm_setting_802_1x_get_phase2_private_key_blob (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_phase2_private_key_path (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_private_key_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key, NULL);
- return (const char *)data + strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
+ _cert_impl_get_path (setting, phase2_private_key);
}
/**
@@ -2525,16 +2348,7 @@ nm_setting_802_1x_get_phase2_private_key_path (NMSetting8021x *setting)
const char *
nm_setting_802_1x_get_phase2_private_key_uri (NMSetting8021x *setting)
{
- NMSetting8021xCKScheme scheme;
- gconstpointer data;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
-
- scheme = nm_setting_802_1x_get_phase2_private_key_scheme (setting);
- g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11, NULL);
-
- data = g_bytes_get_data (NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key, NULL);
- return (const char *)data;
+ _cert_impl_get_uri (setting, phase2_private_key);
}
/**
@@ -2584,88 +2398,7 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *setting,
NMSetting8021xCKFormat *out_format,
GError **error)
{
- NMSetting8021xPrivate *priv;
- NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- gboolean password_changed = FALSE;
- GError *local_err = NULL;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
-
- if (value) {
- g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
- g_return_val_if_fail ( scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
- || scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11,
- FALSE);
- }
-
- if (out_format)
- g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE);
-
- /* Ensure the private key is a recognized format and if the password was
- * given, that it decrypts the private key.
- */
- if (value && scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- format = crypto_verify_private_key (value, password, NULL, &local_err);
- if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) {
- g_set_error_literal (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- local_err ? local_err->message : _("invalid phase2 private key"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY);
- g_clear_error (&local_err);
- return FALSE;
- }
- }
-
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- if (value == NULL) {
- if (priv->phase2_private_key) {
- g_clear_pointer (&priv->phase2_private_key, g_bytes_unref);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY);
- }
- if (nm_clear_g_free (&priv->phase2_private_key_password))
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD);
- return TRUE;
- }
-
- /* this makes password self-assignment safe. */
- if (!nm_streq0 (priv->phase2_private_key_password, password)) {
- g_free (priv->phase2_private_key_password);
- priv->phase2_private_key_password = g_strdup (password);
- password_changed = TRUE;
- }
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
- /* FIXME: potential race after verifying the private key above */
- /* FIXME: ensure blob doesn't start with file:// */
- priv->phase2_private_key = file_to_secure_bytes (value);
- nm_assert (priv->phase2_private_key);
- } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
- priv->phase2_private_key = path_to_scheme_value (value);
- else {
- nm_assert (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11);
- priv->phase2_private_key = g_bytes_new (value, strlen (value) + 1);
- }
-
- /* As required by NM and wpa_supplicant, set the client-cert
- * property to the same PKCS#12 data.
- */
- if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) {
- if (priv->phase2_client_cert)
- g_bytes_unref (priv->phase2_client_cert);
-
- priv->phase2_client_cert = g_bytes_ref (priv->phase2_private_key);
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_CLIENT_CERT);
- }
-
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY);
- if (password_changed)
- g_object_notify (G_OBJECT (setting), NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD);
-
- NM_SET_OUT (out_format, (NMSetting8021xCKFormat) format);
- return priv->phase2_private_key != NULL;
+ return _cert_impl_set (setting, PROP_PHASE2_PRIVATE_KEY, value, password, scheme, out_format, error);
}
/**
@@ -2678,38 +2411,7 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *setting,
NMSetting8021xCKFormat
nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting)
{
- NMSetting8021xPrivate *priv;
- const char *path;
- GError *error = NULL;
-
- g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_802_1X_CK_FORMAT_UNKNOWN);
- priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
-
- if (!priv->phase2_private_key)
- return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
-
- switch (nm_setting_802_1x_get_phase2_private_key_scheme (setting)) {
- case NM_SETTING_802_1X_CK_SCHEME_BLOB:
- if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL),
- g_bytes_get_size (priv->phase2_private_key),
- NULL))
- return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
- return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
- case NM_SETTING_802_1X_CK_SCHEME_PATH:
- path = nm_setting_802_1x_get_phase2_private_key_path (setting);
- if (crypto_is_pkcs12_file (path, &error))
- return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
- if (error && error->domain == G_FILE_ERROR) {
- g_error_free (error);
- return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
- }
- g_error_free (error);
- return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
- default:
- break;
- }
-
- return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+ return _cert_impl_get_key_format (setting, phase2_private_key);
}
/**
@@ -2731,6 +2433,8 @@ nm_setting_802_1x_get_auth_timeout (NMSetting8021x *setting)
return NM_SETTING_802_1X_GET_PRIVATE (setting)->auth_timeout;
}
+/*****************************************************************************/
+
static void
need_secrets_password (NMSetting8021x *self,
GPtrArray *secrets,
@@ -2775,11 +2479,11 @@ need_private_key_password (GBytes *blob,
/* Private key password is required */
if (password) {
if (path)
- format = crypto_verify_private_key (path, password, NULL, NULL);
+ format = nm_crypto_verify_private_key (path, password, NULL, NULL);
else if (blob)
- format = crypto_verify_private_key_data (g_bytes_get_data (blob, NULL),
- g_bytes_get_size (blob),
- password, NULL, NULL);
+ format = nm_crypto_verify_private_key_data (g_bytes_get_data (blob, NULL),
+ g_bytes_get_size (blob),
+ password, NULL, NULL);
else
return FALSE;
}
@@ -2894,9 +2598,9 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error)
}
/* If the private key is PKCS#12, check that it matches the client cert */
- if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL),
- g_bytes_get_size (priv->phase2_private_key),
- NULL)) {
+ if (nm_crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL),
+ g_bytes_get_size (priv->phase2_private_key),
+ NULL)) {
if (!g_bytes_equal (priv->phase2_private_key, priv->phase2_client_cert)) {
g_set_error (error,
NM_CONNECTION_ERROR,
@@ -2942,9 +2646,9 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error)
}
/* If the private key is PKCS#12, check that it matches the client cert */
- if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL),
- g_bytes_get_size (priv->private_key),
- NULL)) {
+ if (nm_crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL),
+ g_bytes_get_size (priv->private_key),
+ NULL)) {
if (!g_bytes_equal (priv->private_key, priv->client_cert)) {
g_set_error (error,
NM_CONNECTION_ERROR,
@@ -3052,43 +2756,6 @@ verify_identity (NMSetting8021x *self, gboolean phase2, GError **error)
return TRUE;
}
-/* Implemented below... */
-static void need_secrets_phase2 (NMSetting8021x *self,
- GPtrArray *secrets,
- gboolean phase2);
-
-typedef void (*EAPMethodNeedSecretsFunc) (NMSetting8021x *self,
- GPtrArray *secrets,
- gboolean phase2);
-
-typedef gboolean (*EAPMethodValidateFunc)(NMSetting8021x *self,
- gboolean phase2,
- GError **error);
-
-typedef struct {
- const char *method;
- EAPMethodNeedSecretsFunc ns_func;
- EAPMethodValidateFunc v_func;
-} EAPMethodsTable;
-
-static EAPMethodsTable eap_methods_table[] = {
- { "leap", need_secrets_password, verify_identity },
- { "pwd", need_secrets_password, verify_identity },
- { "md5", need_secrets_password, verify_identity },
- { "pap", need_secrets_password, verify_identity },
- { "chap", need_secrets_password, verify_identity },
- { "mschap", need_secrets_password, verify_identity },
- { "mschapv2", need_secrets_password, verify_identity },
- { "fast", need_secrets_password, verify_identity },
- { "tls", need_secrets_tls, verify_tls },
- { "peap", need_secrets_phase2, verify_ttls },
- { "ttls", need_secrets_phase2, verify_ttls },
- { "sim", need_secrets_sim, NULL },
- { "gtc", need_secrets_password, verify_identity },
- { "otp", NULL, NULL }, // FIXME: implement
- { NULL, NULL, NULL }
-};
-
static void
need_secrets_phase2 (NMSetting8021x *self,
GPtrArray *secrets,
@@ -3122,79 +2789,23 @@ need_secrets_phase2 (NMSetting8021x *self,
}
}
-static GPtrArray *
-need_secrets (NMSetting *setting)
-{
- NMSetting8021x *self = NM_SETTING_802_1X (setting);
- NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self);
- GSList *iter;
- GPtrArray *secrets;
- gboolean eap_method_found = FALSE;
-
- secrets = g_ptr_array_sized_new (4);
-
- /* Ask each configured EAP method if it needs secrets */
- for (iter = priv->eap; iter && !eap_method_found; iter = g_slist_next (iter)) {
- const char *method = (const char *) iter->data;
- int i;
-
- for (i = 0; eap_methods_table[i].method; i++) {
- if (eap_methods_table[i].ns_func == NULL)
- continue;
- if (!strcmp (eap_methods_table[i].method, method)) {
- (*eap_methods_table[i].ns_func) (self, secrets, FALSE);
-
- /* Only break out of the outer loop if this EAP method
- * needed secrets.
- */
- if (secrets->len > 0)
- eap_method_found = TRUE;
- break;
- }
- }
- }
-
- if (secrets->len == 0) {
- g_ptr_array_free (secrets, TRUE);
- secrets = NULL;
- }
-
- return secrets;
-}
-
-static gboolean
-verify_cert (GBytes *bytes, const char *prop_name,
- const char *password, const char *password_prop_name, GError **error)
-{
- GError *local = NULL;
- NMSetting8021xCKScheme scheme;
-
- if (bytes)
- scheme = get_cert_scheme (bytes, &local);
- else
- return TRUE;
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) {
- g_set_error (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("certificate is invalid: %s"), local->message);
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, prop_name);
- g_error_free (local);
- return FALSE;
- }
-
- if (password && (scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11)) {
- g_set_error (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("password is not supported when certificate is not on a PKCS#11 token"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, password_prop_name);
- return FALSE;
- }
-
- return TRUE;
-}
+static EAPMethodsTable eap_methods_table[] = {
+ { "leap", need_secrets_password, verify_identity },
+ { "pwd", need_secrets_password, verify_identity },
+ { "md5", need_secrets_password, verify_identity },
+ { "pap", need_secrets_password, verify_identity },
+ { "chap", need_secrets_password, verify_identity },
+ { "mschap", need_secrets_password, verify_identity },
+ { "mschapv2", need_secrets_password, verify_identity },
+ { "fast", need_secrets_password, verify_identity },
+ { "tls", need_secrets_tls, verify_tls },
+ { "peap", need_secrets_phase2, verify_ttls },
+ { "ttls", need_secrets_phase2, verify_ttls },
+ { "sim", need_secrets_sim, NULL },
+ { "gtc", need_secrets_password, verify_identity },
+ { "otp", NULL, NULL }, // FIXME: implement
+ { NULL, NULL, NULL }
+};
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
@@ -3202,11 +2813,6 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
NMSetting8021x *self = NM_SETTING_802_1X (setting);
NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self);
const char *valid_eap[] = { "leap", "md5", "tls", "peap", "ttls", "sim", "fast", "pwd", NULL };
- const char *valid_phase1_peapver[] = { "0", "1", NULL };
- const char *valid_phase1_peaplabel[] = { "0", "1", NULL };
- const char *valid_phase1_fast_pac[] = { "0", "1", "2", "3", NULL };
- const char *valid_phase2_auth[] = { "pap", "chap", "mschap", "mschapv2", "gtc", "otp", "md5", "tls", NULL };
- const char *valid_phase2_autheap[] = { "md5", "mschapv2", "otp", "gtc", "tls", NULL };
GSList *iter;
if (error)
@@ -3246,7 +2852,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
- if (priv->phase1_peapver && !g_strv_contains (valid_phase1_peapver, priv->phase1_peapver)) {
+ if (!NM_IN_STRSET (priv->phase1_peapver, NULL,
+ "0",
+ "1")) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -3256,7 +2864,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
- if (priv->phase1_peaplabel && !g_strv_contains (valid_phase1_peaplabel, priv->phase1_peaplabel)) {
+ if (!NM_IN_STRSET (priv->phase1_peaplabel, NULL,
+ "0",
+ "1")) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -3266,7 +2876,11 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
- if (priv->phase1_fast_provisioning && !g_strv_contains (valid_phase1_fast_pac, priv->phase1_fast_provisioning)) {
+ if (!NM_IN_STRSET (priv->phase1_fast_provisioning, NULL,
+ "0",
+ "1",
+ "2",
+ "3")) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -3285,7 +2899,15 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
- if (priv->phase2_auth && !g_strv_contains (valid_phase2_auth, priv->phase2_auth)) {
+ if (!NM_IN_STRSET (priv->phase2_auth, NULL,
+ "pap",
+ "chap",
+ "mschap",
+ "mschapv2",
+ "gtc",
+ "otp",
+ "md5",
+ "tls")) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -3295,7 +2917,12 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
- if (priv->phase2_autheap && !g_strv_contains (valid_phase2_autheap, priv->phase2_autheap)) {
+ if (!NM_IN_STRSET (priv->phase2_autheap, NULL,
+ "md5",
+ "mschapv2",
+ "otp",
+ "gtc",
+ "tls")) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -3305,307 +2932,231 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
- if (!verify_cert (priv->ca_cert, NM_SETTING_802_1X_CA_CERT,
- priv->ca_cert_password, NM_SETTING_802_1X_CA_CERT_PASSWORD, error))
+ if (!_cert_verify_property (priv->ca_cert,
+ NM_SETTING_802_1X_CA_CERT,
+ priv->ca_cert_password,
+ NM_SETTING_802_1X_CA_CERT_PASSWORD,
+ error))
return FALSE;
- if (!verify_cert (priv->phase2_ca_cert, NM_SETTING_802_1X_PHASE2_CA_CERT,
- priv->phase2_ca_cert_password, NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD, error))
+ if (!_cert_verify_property (priv->phase2_ca_cert,
+ NM_SETTING_802_1X_PHASE2_CA_CERT,
+ priv->phase2_ca_cert_password,
+ NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD,
+ error))
return FALSE;
- if (!verify_cert (priv->client_cert, NM_SETTING_802_1X_CLIENT_CERT,
- priv->client_cert_password, NM_SETTING_802_1X_CLIENT_CERT_PASSWORD, error))
+ if (!_cert_verify_property (priv->client_cert,
+ NM_SETTING_802_1X_CLIENT_CERT,
+ priv->client_cert_password,
+ NM_SETTING_802_1X_CLIENT_CERT_PASSWORD,
+ error))
return FALSE;
- if (!verify_cert (priv->phase2_client_cert, NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
- priv->phase2_client_cert_password, NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD, error))
+ if (!_cert_verify_property (priv->phase2_client_cert,
+ NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
+ priv->phase2_client_cert_password,
+ NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD,
+ error))
return FALSE;
- if (!verify_cert (priv->private_key, NM_SETTING_802_1X_PRIVATE_KEY, NULL, NULL, error))
+ if (!_cert_verify_property (priv->private_key,
+ NM_SETTING_802_1X_PRIVATE_KEY,
+ NULL,
+ NULL,
+ error))
return FALSE;
- if (!verify_cert (priv->phase2_private_key, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, NULL, NULL, error))
+ if (!_cert_verify_property (priv->phase2_private_key,
+ NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
+ NULL,
+ NULL,
+ error))
return FALSE;
- /* FIXME: finish */
-
return TRUE;
}
-static void
-nm_setting_802_1x_init (NMSetting8021x *setting)
-{
-}
+/*****************************************************************************/
-static void
-finalize (GObject *object)
+static GPtrArray *
+need_secrets (NMSetting *setting)
{
- NMSetting8021x *self = NM_SETTING_802_1X (object);
+ NMSetting8021x *self = NM_SETTING_802_1X (setting);
NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self);
+ GSList *iter;
+ GPtrArray *secrets;
+ gboolean eap_method_found = FALSE;
- /* Strings first. g_free() already checks for NULLs so we don't have to */
-
- g_free (priv->identity);
- g_free (priv->anonymous_identity);
- g_free (priv->ca_path);
- g_free (priv->subject_match);
- g_free (priv->domain_suffix_match);
- g_free (priv->phase1_peapver);
- g_free (priv->phase1_peaplabel);
- g_free (priv->phase1_fast_provisioning);
- g_free (priv->phase2_auth);
- g_free (priv->phase2_autheap);
- g_free (priv->phase2_ca_path);
- g_free (priv->phase2_subject_match);
- g_free (priv->phase2_domain_suffix_match);
- g_free (priv->password);
- if (priv->password_raw)
- g_bytes_unref (priv->password_raw);
- g_free (priv->pin);
+ secrets = g_ptr_array_sized_new (4);
- g_slist_free_full (priv->eap, g_free);
- g_slist_free_full (priv->altsubject_matches, g_free);
- g_slist_free_full (priv->phase2_altsubject_matches, g_free);
+ /* Ask each configured EAP method if it needs secrets */
+ for (iter = priv->eap; iter && !eap_method_found; iter = g_slist_next (iter)) {
+ const char *method = (const char *) iter->data;
+ int i;
- if (priv->ca_cert)
- g_bytes_unref (priv->ca_cert);
- g_free (priv->ca_cert_password);
- if (priv->client_cert)
- g_bytes_unref (priv->client_cert);
- g_free (priv->client_cert_password);
- if (priv->private_key)
- g_bytes_unref (priv->private_key);
- g_free (priv->private_key_password);
- if (priv->phase2_ca_cert)
- g_bytes_unref (priv->phase2_ca_cert);
- g_free (priv->phase2_ca_cert_password);
- if (priv->phase2_client_cert)
- g_bytes_unref (priv->phase2_client_cert);
- g_free (priv->phase2_client_cert_password);
- if (priv->phase2_private_key)
- g_bytes_unref (priv->phase2_private_key);
- g_free (priv->phase2_private_key_password);
+ for (i = 0; eap_methods_table[i].method; i++) {
+ if (eap_methods_table[i].ns_func == NULL)
+ continue;
+ if (!strcmp (eap_methods_table[i].method, method)) {
+ (*eap_methods_table[i].ns_func) (self, secrets, FALSE);
- G_OBJECT_CLASS (nm_setting_802_1x_parent_class)->finalize (object);
-}
+ /* Only break out of the outer loop if this EAP method
+ * needed secrets.
+ */
+ if (secrets->len > 0)
+ eap_method_found = TRUE;
+ break;
+ }
+ }
+ }
-static GBytes *
-set_cert_prop_helper (const GValue *value, const char *prop_name, GError **error)
-{
- gboolean valid;
- GBytes *bytes = NULL;
-
- bytes = g_value_dup_boxed (value);
- /* Verify the new data */
- if (bytes) {
- valid = verify_cert (bytes, prop_name, NULL, NULL, error);
- if (!valid)
- g_clear_pointer (&bytes, g_bytes_unref);
+ if (secrets->len == 0) {
+ g_ptr_array_free (secrets, TRUE);
+ return NULL;
}
- return bytes;
+
+ return secrets;
}
+/*****************************************************************************/
+
static void
-set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
{
NMSetting8021x *setting = NM_SETTING_802_1X (object);
NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
- GError *error = NULL;
switch (prop_id) {
case PROP_EAP:
- g_slist_free_full (priv->eap, g_free);
- priv->eap = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+ g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->eap, TRUE));
break;
case PROP_IDENTITY:
- g_free (priv->identity);
- priv->identity = g_value_dup_string (value);
+ g_value_set_string (value, priv->identity);
break;
case PROP_ANONYMOUS_IDENTITY:
- g_free (priv->anonymous_identity);
- priv->anonymous_identity = g_value_dup_string (value);
+ g_value_set_string (value, priv->anonymous_identity);
break;
case PROP_PAC_FILE:
- g_free (priv->pac_file);
- priv->pac_file = g_value_dup_string (value);
+ g_value_set_string (value, priv->pac_file);
break;
case PROP_CA_CERT:
- if (priv->ca_cert)
- g_bytes_unref (priv->ca_cert);
- priv->ca_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_CA_CERT, &error);
- if (error) {
- g_warning ("Error setting certificate (invalid data): %s", error->message);
- g_error_free (error);
- }
+ g_value_set_boxed (value, priv->ca_cert);
break;
case PROP_CA_CERT_PASSWORD:
- g_free (priv->ca_cert_password);
- priv->ca_cert_password = g_value_dup_string (value);
+ g_value_set_string (value, priv->ca_cert_password);
break;
case PROP_CA_CERT_PASSWORD_FLAGS:
- priv->ca_cert_password_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->ca_cert_password_flags);
break;
case PROP_CA_PATH:
- g_free (priv->ca_path);
- priv->ca_path = g_value_dup_string (value);
+ g_value_set_string (value, priv->ca_path);
break;
case PROP_SUBJECT_MATCH:
- g_free (priv->subject_match);
- priv->subject_match = nm_strdup_not_empty (g_value_get_string (value));
+ g_value_set_string (value, priv->subject_match);
break;
case PROP_ALTSUBJECT_MATCHES:
- g_slist_free_full (priv->altsubject_matches, g_free);
- priv->altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+ g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->altsubject_matches, TRUE));
break;
case PROP_DOMAIN_SUFFIX_MATCH:
- g_free (priv->domain_suffix_match);
- priv->domain_suffix_match = nm_strdup_not_empty (g_value_get_string (value));
+ g_value_set_string (value, priv->domain_suffix_match);
break;
case PROP_CLIENT_CERT:
- if (priv->client_cert)
- g_bytes_unref (priv->client_cert);
- priv->client_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_CLIENT_CERT, &error);
- if (error) {
- g_warning ("Error setting certificate (invalid data): %s", error->message);
- g_error_free (error);
- }
+ g_value_set_boxed (value, priv->client_cert);
break;
case PROP_CLIENT_CERT_PASSWORD:
- g_free (priv->client_cert_password);
- priv->client_cert_password = g_value_dup_string (value);
+ g_value_set_string (value, priv->client_cert_password);
break;
case PROP_CLIENT_CERT_PASSWORD_FLAGS:
- priv->client_cert_password_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->client_cert_password_flags);
break;
case PROP_PHASE1_PEAPVER:
- g_free (priv->phase1_peapver);
- priv->phase1_peapver = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase1_peapver);
break;
case PROP_PHASE1_PEAPLABEL:
- g_free (priv->phase1_peaplabel);
- priv->phase1_peaplabel = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase1_peaplabel);
break;
case PROP_PHASE1_FAST_PROVISIONING:
- g_free (priv->phase1_fast_provisioning);
- priv->phase1_fast_provisioning = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase1_fast_provisioning);
break;
case PROP_PHASE1_AUTH_FLAGS:
- priv->phase1_auth_flags = g_value_get_uint (value);
+ g_value_set_uint (value, priv->phase1_auth_flags);
break;
case PROP_PHASE2_AUTH:
- g_free (priv->phase2_auth);
- priv->phase2_auth = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase2_auth);
break;
case PROP_PHASE2_AUTHEAP:
- g_free (priv->phase2_autheap);
- priv->phase2_autheap = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase2_autheap);
break;
case PROP_PHASE2_CA_CERT:
- if (priv->phase2_ca_cert)
- g_bytes_unref (priv->phase2_ca_cert);
- priv->phase2_ca_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_CA_CERT, &error);
- if (error) {
- g_warning ("Error setting certificate (invalid data): %s", error->message);
- g_error_free (error);
- }
+ g_value_set_boxed (value, priv->phase2_ca_cert);
break;
case PROP_PHASE2_CA_CERT_PASSWORD:
- g_free (priv->phase2_ca_cert_password);
- priv->phase2_ca_cert_password = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase2_ca_cert_password);
break;
case PROP_PHASE2_CA_CERT_PASSWORD_FLAGS:
- priv->phase2_ca_cert_password_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->phase2_ca_cert_password_flags);
break;
case PROP_PHASE2_CA_PATH:
- g_free (priv->phase2_ca_path);
- priv->phase2_ca_path = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase2_ca_path);
break;
case PROP_PHASE2_SUBJECT_MATCH:
- g_free (priv->phase2_subject_match);
- priv->phase2_subject_match = nm_strdup_not_empty (g_value_get_string (value));
+ g_value_set_string (value, priv->phase2_subject_match);
break;
case PROP_PHASE2_ALTSUBJECT_MATCHES:
- g_slist_free_full (priv->phase2_altsubject_matches, g_free);
- priv->phase2_altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+ g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->phase2_altsubject_matches, TRUE));
break;
case PROP_PHASE2_DOMAIN_SUFFIX_MATCH:
- g_free (priv->phase2_domain_suffix_match);
- priv->phase2_domain_suffix_match = nm_strdup_not_empty (g_value_get_string (value));
+ g_value_set_string (value, priv->phase2_domain_suffix_match);
break;
case PROP_PHASE2_CLIENT_CERT:
-
- if (priv->phase2_client_cert)
- g_bytes_unref (priv->phase2_client_cert);
- priv->phase2_client_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &error);
- if (error) {
- g_warning ("Error setting certificate (invalid data): %s", error->message);
- g_error_free (error);
- }
+ g_value_set_boxed (value, priv->phase2_client_cert);
break;
case PROP_PHASE2_CLIENT_CERT_PASSWORD:
- g_free (priv->phase2_client_cert_password);
- priv->phase2_client_cert_password = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase2_client_cert_password);
break;
case PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS:
- priv->phase2_client_cert_password_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->phase2_client_cert_password_flags);
break;
case PROP_PASSWORD:
- g_free (priv->password);
- priv->password = g_value_dup_string (value);
+ g_value_set_string (value, priv->password);
break;
case PROP_PASSWORD_FLAGS:
- priv->password_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->password_flags);
break;
case PROP_PASSWORD_RAW:
- if (priv->password_raw)
- g_bytes_unref (priv->password_raw);
- priv->password_raw = g_value_dup_boxed (value);
+ g_value_set_boxed (value, priv->password_raw);
break;
case PROP_PASSWORD_RAW_FLAGS:
- priv->password_raw_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->password_raw_flags);
break;
case PROP_PRIVATE_KEY:
- if (priv->private_key)
- g_bytes_unref (priv->private_key);
- priv->private_key = set_cert_prop_helper (value, NM_SETTING_802_1X_PRIVATE_KEY, &error);
- if (error) {
- g_warning ("Error setting private key (invalid data): %s", error->message);
- g_error_free (error);
- }
+ g_value_set_boxed (value, priv->private_key);
break;
case PROP_PRIVATE_KEY_PASSWORD:
- g_free (priv->private_key_password);
- priv->private_key_password = g_value_dup_string (value);
+ g_value_set_string (value, priv->private_key_password);
break;
case PROP_PRIVATE_KEY_PASSWORD_FLAGS:
- priv->private_key_password_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->private_key_password_flags);
break;
case PROP_PHASE2_PRIVATE_KEY:
- if (priv->phase2_private_key)
- g_bytes_unref (priv->phase2_private_key);
- priv->phase2_private_key = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &error);
- if (error) {
- g_warning ("Error setting private key (invalid data): %s", error->message);
- g_error_free (error);
- }
+ g_value_set_boxed (value, priv->phase2_private_key);
break;
case PROP_PHASE2_PRIVATE_KEY_PASSWORD:
- g_free (priv->phase2_private_key_password);
- priv->phase2_private_key_password = g_value_dup_string (value);
+ g_value_set_string (value, priv->phase2_private_key_password);
break;
case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS:
- priv->phase2_private_key_password_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->phase2_private_key_password_flags);
break;
case PROP_PIN:
- g_free (priv->pin);
- priv->pin = g_value_dup_string (value);
+ g_value_set_string (value, priv->pin);
break;
case PROP_PIN_FLAGS:
- priv->pin_flags = g_value_get_flags (value);
+ g_value_set_flags (value, priv->pin_flags);
break;
case PROP_SYSTEM_CA_CERTS:
- priv->system_ca_certs = g_value_get_boolean (value);
+ g_value_set_boolean (value, priv->system_ca_certs);
break;
case PROP_AUTH_TIMEOUT:
- priv->auth_timeout = g_value_get_int (value);
+ g_value_set_int (value, priv->auth_timeout);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -3614,144 +3165,176 @@ set_property (GObject *object, guint prop_id,
}
static void
-get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
{
NMSetting8021x *setting = NM_SETTING_802_1X (object);
NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (setting);
switch (prop_id) {
case PROP_EAP:
- g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->eap, TRUE));
+ g_slist_free_full (priv->eap, g_free);
+ priv->eap = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
break;
case PROP_IDENTITY:
- g_value_set_string (value, priv->identity);
+ g_free (priv->identity);
+ priv->identity = g_value_dup_string (value);
break;
case PROP_ANONYMOUS_IDENTITY:
- g_value_set_string (value, priv->anonymous_identity);
+ g_free (priv->anonymous_identity);
+ priv->anonymous_identity = g_value_dup_string (value);
break;
case PROP_PAC_FILE:
- g_value_set_string (value, priv->pac_file);
+ g_free (priv->pac_file);
+ priv->pac_file = g_value_dup_string (value);
break;
case PROP_CA_CERT:
- g_value_set_boxed (value, priv->ca_cert);
+ g_bytes_unref (priv->ca_cert);
+ priv->ca_cert = g_value_dup_boxed (value);
break;
case PROP_CA_CERT_PASSWORD:
- g_value_set_string (value, priv->ca_cert_password);
+ g_free (priv->ca_cert_password);
+ priv->ca_cert_password = g_value_dup_string (value);
break;
case PROP_CA_CERT_PASSWORD_FLAGS:
- g_value_set_flags (value, priv->ca_cert_password_flags);
+ priv->ca_cert_password_flags = g_value_get_flags (value);
break;
case PROP_CA_PATH:
- g_value_set_string (value, priv->ca_path);
+ g_free (priv->ca_path);
+ priv->ca_path = g_value_dup_string (value);
break;
case PROP_SUBJECT_MATCH:
- g_value_set_string (value, priv->subject_match);
+ g_free (priv->subject_match);
+ priv->subject_match = nm_strdup_not_empty (g_value_get_string (value));
break;
case PROP_ALTSUBJECT_MATCHES:
- g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->altsubject_matches, TRUE));
+ g_slist_free_full (priv->altsubject_matches, g_free);
+ priv->altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
break;
case PROP_DOMAIN_SUFFIX_MATCH:
- g_value_set_string (value, priv->domain_suffix_match);
+ g_free (priv->domain_suffix_match);
+ priv->domain_suffix_match = nm_strdup_not_empty (g_value_get_string (value));
break;
case PROP_CLIENT_CERT:
- g_value_set_boxed (value, priv->client_cert);
+ g_bytes_unref (priv->client_cert);
+ priv->client_cert = g_value_dup_boxed (value);
break;
case PROP_CLIENT_CERT_PASSWORD:
- g_value_set_string (value, priv->client_cert_password);
+ g_free (priv->client_cert_password);
+ priv->client_cert_password = g_value_dup_string (value);
break;
case PROP_CLIENT_CERT_PASSWORD_FLAGS:
- g_value_set_flags (value, priv->client_cert_password_flags);
+ priv->client_cert_password_flags = g_value_get_flags (value);
break;
case PROP_PHASE1_PEAPVER:
- g_value_set_string (value, priv->phase1_peapver);
+ g_free (priv->phase1_peapver);
+ priv->phase1_peapver = g_value_dup_string (value);
break;
case PROP_PHASE1_PEAPLABEL:
- g_value_set_string (value, priv->phase1_peaplabel);
+ g_free (priv->phase1_peaplabel);
+ priv->phase1_peaplabel = g_value_dup_string (value);
break;
case PROP_PHASE1_FAST_PROVISIONING:
- g_value_set_string (value, priv->phase1_fast_provisioning);
+ g_free (priv->phase1_fast_provisioning);
+ priv->phase1_fast_provisioning = g_value_dup_string (value);
break;
case PROP_PHASE1_AUTH_FLAGS:
- g_value_set_uint (value, priv->phase1_auth_flags);
+ priv->phase1_auth_flags = g_value_get_uint (value);
break;
case PROP_PHASE2_AUTH:
- g_value_set_string (value, priv->phase2_auth);
+ g_free (priv->phase2_auth);
+ priv->phase2_auth = g_value_dup_string (value);
break;
case PROP_PHASE2_AUTHEAP:
- g_value_set_string (value, priv->phase2_autheap);
+ g_free (priv->phase2_autheap);
+ priv->phase2_autheap = g_value_dup_string (value);
break;
case PROP_PHASE2_CA_CERT:
- g_value_set_boxed (value, priv->phase2_ca_cert);
+ g_bytes_unref (priv->phase2_ca_cert);
+ priv->phase2_ca_cert = g_value_dup_boxed (value);
break;
case PROP_PHASE2_CA_CERT_PASSWORD:
- g_value_set_string (value, priv->phase2_ca_cert_password);
+ g_free (priv->phase2_ca_cert_password);
+ priv->phase2_ca_cert_password = g_value_dup_string (value);
break;
case PROP_PHASE2_CA_CERT_PASSWORD_FLAGS:
- g_value_set_flags (value, priv->phase2_ca_cert_password_flags);
+ priv->phase2_ca_cert_password_flags = g_value_get_flags (value);
break;
case PROP_PHASE2_CA_PATH:
- g_value_set_string (value, priv->phase2_ca_path);
+ g_free (priv->phase2_ca_path);
+ priv->phase2_ca_path = g_value_dup_string (value);
break;
case PROP_PHASE2_SUBJECT_MATCH:
- g_value_set_string (value, priv->phase2_subject_match);
+ g_free (priv->phase2_subject_match);
+ priv->phase2_subject_match = nm_strdup_not_empty (g_value_get_string (value));
break;
case PROP_PHASE2_ALTSUBJECT_MATCHES:
- g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->phase2_altsubject_matches, TRUE));
+ g_slist_free_full (priv->phase2_altsubject_matches, g_free);
+ priv->phase2_altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
break;
case PROP_PHASE2_DOMAIN_SUFFIX_MATCH:
- g_value_set_string (value, priv->phase2_domain_suffix_match);
+ g_free (priv->phase2_domain_suffix_match);
+ priv->phase2_domain_suffix_match = nm_strdup_not_empty (g_value_get_string (value));
break;
case PROP_PHASE2_CLIENT_CERT:
- g_value_set_boxed (value, priv->phase2_client_cert);
+ g_bytes_unref (priv->phase2_client_cert);
+ priv->phase2_client_cert = g_value_dup_boxed (value);
break;
case PROP_PHASE2_CLIENT_CERT_PASSWORD:
- g_value_set_string (value, priv->phase2_client_cert_password);
+ g_free (priv->phase2_client_cert_password);
+ priv->phase2_client_cert_password = g_value_dup_string (value);
break;
case PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS:
- g_value_set_flags (value, priv->phase2_client_cert_password_flags);
+ priv->phase2_client_cert_password_flags = g_value_get_flags (value);
break;
case PROP_PASSWORD:
- g_value_set_string (value, priv->password);
+ g_free (priv->password);
+ priv->password = g_value_dup_string (value);
break;
case PROP_PASSWORD_FLAGS:
- g_value_set_flags (value, priv->password_flags);
+ priv->password_flags = g_value_get_flags (value);
break;
case PROP_PASSWORD_RAW:
- g_value_set_boxed (value, priv->password_raw);
+ g_bytes_unref (priv->password_raw);
+ priv->password_raw = g_value_dup_boxed (value);
break;
case PROP_PASSWORD_RAW_FLAGS:
- g_value_set_flags (value, priv->password_raw_flags);
+ priv->password_raw_flags = g_value_get_flags (value);
break;
case PROP_PRIVATE_KEY:
- g_value_set_boxed (value, priv->private_key);
+ g_bytes_unref (priv->private_key);
+ priv->private_key = g_value_dup_boxed (value);
break;
case PROP_PRIVATE_KEY_PASSWORD:
- g_value_set_string (value, priv->private_key_password);
+ nm_free_secret (priv->private_key_password);
+ priv->private_key_password = g_value_dup_string (value);
break;
case PROP_PRIVATE_KEY_PASSWORD_FLAGS:
- g_value_set_flags (value, priv->private_key_password_flags);
+ priv->private_key_password_flags = g_value_get_flags (value);
break;
case PROP_PHASE2_PRIVATE_KEY:
- g_value_set_boxed (value, priv->phase2_private_key);
+ g_bytes_unref (priv->phase2_private_key);
+ priv->phase2_private_key = g_value_dup_boxed (value);
break;
case PROP_PHASE2_PRIVATE_KEY_PASSWORD:
- g_value_set_string (value, priv->phase2_private_key_password);
+ nm_free_secret (priv->phase2_private_key_password);
+ priv->phase2_private_key_password = g_value_dup_string (value);
break;
case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS:
- g_value_set_flags (value, priv->phase2_private_key_password_flags);
+ priv->phase2_private_key_password_flags = g_value_get_flags (value);
break;
case PROP_PIN:
- g_value_set_string (value, priv->pin);
+ g_free (priv->pin);
+ priv->pin = g_value_dup_string (value);
break;
case PROP_PIN_FLAGS:
- g_value_set_flags (value, priv->pin_flags);
+ priv->pin_flags = g_value_get_flags (value);
break;
case PROP_SYSTEM_CA_CERTS:
- g_value_set_boolean (value, priv->system_ca_certs);
+ priv->system_ca_certs = g_value_get_boolean (value);
break;
case PROP_AUTH_TIMEOUT:
- g_value_set_int (value, priv->auth_timeout);
+ priv->auth_timeout = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -3759,6 +3342,71 @@ get_property (GObject *object, guint prop_id,
}
}
+/*****************************************************************************/
+
+static void
+nm_setting_802_1x_init (NMSetting8021x *setting)
+{
+}
+
+/**
+ * nm_setting_802_1x_new:
+ *
+ * Creates a new #NMSetting8021x object with default values.
+ *
+ * Returns: the new empty #NMSetting8021x object
+ **/
+NMSetting *
+nm_setting_802_1x_new (void)
+{
+ return (NMSetting *) g_object_new (NM_TYPE_SETTING_802_1X, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ NMSetting8021x *self = NM_SETTING_802_1X (object);
+ NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self);
+
+ /* Strings first. g_free() already checks for NULLs so we don't have to */
+
+ g_free (priv->identity);
+ g_free (priv->anonymous_identity);
+ g_free (priv->ca_path);
+ g_free (priv->subject_match);
+ g_free (priv->domain_suffix_match);
+ g_free (priv->phase1_peapver);
+ g_free (priv->phase1_peaplabel);
+ g_free (priv->phase1_fast_provisioning);
+ g_free (priv->phase2_auth);
+ g_free (priv->phase2_autheap);
+ g_free (priv->phase2_ca_path);
+ g_free (priv->phase2_subject_match);
+ g_free (priv->phase2_domain_suffix_match);
+ g_free (priv->password);
+ g_bytes_unref (priv->password_raw);
+ g_free (priv->pin);
+
+ g_slist_free_full (priv->eap, g_free);
+ g_slist_free_full (priv->altsubject_matches, g_free);
+ g_slist_free_full (priv->phase2_altsubject_matches, g_free);
+
+ g_bytes_unref (priv->ca_cert);
+ g_free (priv->ca_cert_password);
+ g_bytes_unref (priv->client_cert);
+ g_free (priv->client_cert_password);
+ g_bytes_unref (priv->private_key);
+ nm_free_secret (priv->private_key_password);
+ g_bytes_unref (priv->phase2_ca_cert);
+ g_free (priv->phase2_ca_cert_password);
+ g_bytes_unref (priv->phase2_client_cert);
+ g_free (priv->phase2_client_cert_password);
+ g_bytes_unref (priv->phase2_private_key);
+ nm_free_secret (priv->phase2_private_key_password);
+
+ G_OBJECT_CLASS (nm_setting_802_1x_parent_class)->finalize (object);
+}
+
static void
nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
{
@@ -3791,12 +3439,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_EAP_METHODS=PEAP
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_EAP,
- g_param_spec_boxed (NM_SETTING_802_1X_EAP, "", "",
- G_TYPE_STRV,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_EAP] =
+ g_param_spec_boxed (NM_SETTING_802_1X_EAP, "", "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:identity:
@@ -3811,12 +3458,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_IDENTITY=itsme
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_IDENTITY,
- g_param_spec_string (NM_SETTING_802_1X_IDENTITY, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_IDENTITY] =
+ g_param_spec_string (NM_SETTING_802_1X_IDENTITY, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:anonymous-identity:
@@ -3831,12 +3477,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Anonymous identity for EAP authentication methods.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_ANONYMOUS_IDENTITY,
- g_param_spec_string (NM_SETTING_802_1X_ANONYMOUS_IDENTITY, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_ANONYMOUS_IDENTITY] =
+ g_param_spec_string (NM_SETTING_802_1X_ANONYMOUS_IDENTITY, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:pac-file:
@@ -3850,12 +3495,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_PAC_FILE=/home/joe/my-fast.pac
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PAC_FILE,
- g_param_spec_string (NM_SETTING_802_1X_PAC_FILE, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PAC_FILE] =
+ g_param_spec_string (NM_SETTING_802_1X_PAC_FILE, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:ca-cert:
@@ -3882,12 +3526,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_CA_CERT=/home/joe/cacert.crt
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_CA_CERT,
- g_param_spec_boxed (NM_SETTING_802_1X_CA_CERT, "", "",
- G_TYPE_BYTES,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_CA_CERT] =
+ g_param_spec_boxed (NM_SETTING_802_1X_CA_CERT, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:ca-cert-password:
@@ -3901,13 +3544,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_CA_CERT_PASSWORD,
- g_param_spec_string (NM_SETTING_802_1X_CA_CERT_PASSWORD, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_CA_CERT_PASSWORD] =
+ g_param_spec_string (NM_SETTING_802_1X_CA_CERT_PASSWORD, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:ca-cert-password-flags:
@@ -3919,13 +3561,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_CA_CERT_PASSWORD_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_CA_CERT_PASSWORD_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:ca-path:
@@ -3940,12 +3581,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: The property is not handled by ifcfg-rh plugin.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_CA_PATH,
- g_param_spec_string (NM_SETTING_802_1X_CA_PATH, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_CA_PATH] =
+ g_param_spec_string (NM_SETTING_802_1X_CA_PATH, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:subject-match:
@@ -3963,12 +3603,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_SUBJECT_MATCH="Red Hat"
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_SUBJECT_MATCH,
- g_param_spec_string (NM_SETTING_802_1X_SUBJECT_MATCH, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_SUBJECT_MATCH] =
+ g_param_spec_string (NM_SETTING_802_1X_SUBJECT_MATCH, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:altsubject-matches:
@@ -3984,12 +3623,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_ALTSUBJECT_MATCHES="s1.domain.cc"
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_ALTSUBJECT_MATCHES,
- g_param_spec_boxed (NM_SETTING_802_1X_ALTSUBJECT_MATCHES, "", "",
- G_TYPE_STRV,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_ALTSUBJECT_MATCHES] =
+ g_param_spec_boxed (NM_SETTING_802_1X_ALTSUBJECT_MATCHES, "", "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:domain-suffix-match:
@@ -4008,12 +3646,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* variable: IEEE_8021X_DOMAIN_SUFFIX_MATCH(+)
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_DOMAIN_SUFFIX_MATCH,
- g_param_spec_string (NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_DOMAIN_SUFFIX_MATCH] =
+ g_param_spec_string (NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:client-cert:
@@ -4038,12 +3675,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_CLIENT_CERT=/home/joe/mycert.crt
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_CLIENT_CERT,
- g_param_spec_boxed (NM_SETTING_802_1X_CLIENT_CERT, "", "",
- G_TYPE_BYTES,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_CLIENT_CERT] =
+ g_param_spec_boxed (NM_SETTING_802_1X_CLIENT_CERT, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:client-cert-password:
@@ -4057,13 +3693,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_CLIENT_CERT_PASSWORD,
- g_param_spec_string (NM_SETTING_802_1X_CLIENT_CERT_PASSWORD, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_CLIENT_CERT_PASSWORD] =
+ g_param_spec_string (NM_SETTING_802_1X_CLIENT_CERT_PASSWORD, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:client-cert-password-flags:
@@ -4075,13 +3710,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_CLIENT_CERT_PASSWORD_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_CLIENT_CERT_PASSWORD_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase1-peapver:
@@ -4100,12 +3734,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Use to force a specific PEAP version.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE1_PEAPVER,
- g_param_spec_string (NM_SETTING_802_1X_PHASE1_PEAPVER, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE1_PEAPVER] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE1_PEAPVER, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase1-peaplabel:
@@ -4123,12 +3756,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Use to force the new PEAP label during key derivation.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE1_PEAPLABEL,
- g_param_spec_string (NM_SETTING_802_1X_PHASE1_PEAPLABEL, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE1_PEAPLABEL] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE1_PEAPLABEL, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase1-fast-provisioning:
@@ -4148,12 +3780,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_FAST_PROVISIONING="allow-auth allow-unauth"
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE1_FAST_PROVISIONING,
- g_param_spec_string (NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE1_FAST_PROVISIONING] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase1-auth-flags:
@@ -4175,13 +3806,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_PHASE1_AUTH_FLAGS="tls-1-0-disable tls-1-1-disable"
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE1_AUTH_FLAGS,
- g_param_spec_uint (NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, "", "",
- 0, G_MAXUINT32, NM_SETTING_802_1X_AUTH_FLAGS_NONE,
- G_PARAM_CONSTRUCT |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE1_AUTH_FLAGS] =
+ g_param_spec_uint (NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, "", "",
+ 0, G_MAXUINT32, NM_SETTING_802_1X_AUTH_FLAGS_NONE,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-auth:
@@ -4202,12 +3832,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_INNER_AUTH_METHODS=PAP
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_AUTH,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_AUTH, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_AUTH] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_AUTH, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-autheap:
@@ -4228,12 +3857,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_INNER_AUTH_METHODS="MSCHAPV2 EAP-TLS"
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_AUTHEAP,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_AUTHEAP, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_AUTHEAP] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_AUTHEAP, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-ca-cert:
@@ -4254,12 +3882,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* Setting this property directly is discouraged; use the
* nm_setting_802_1x_set_phase2_ca_cert() function instead.
**/
- g_object_class_install_property
- (object_class, PROP_PHASE2_CA_CERT,
- g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_CA_CERT, "", "",
- G_TYPE_BYTES,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_CA_CERT] =
+ g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_CA_CERT, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-ca-cert-password:
@@ -4273,13 +3900,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_CA_CERT_PASSWORD,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_CA_CERT_PASSWORD] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-ca-cert-password-flags:
@@ -4291,13 +3917,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_CA_CERT_PASSWORD_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_CA_CERT_PASSWORD_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-ca-path:
@@ -4306,12 +3931,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* certificates to be added to the verification chain in addition to the
* certificate specified in the #NMSetting8021x:phase2-ca-cert property.
**/
- g_object_class_install_property
- (object_class, PROP_PHASE2_CA_PATH,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_CA_PATH, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_CA_PATH] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_CA_PATH, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-subject-match:
@@ -4330,12 +3954,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_PHASE2_SUBJECT_MATCH="Red Hat"
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_SUBJECT_MATCH,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_SUBJECT_MATCH] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-altsubject-matches:
@@ -4350,12 +3973,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* variable: IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES(+)
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_ALTSUBJECT_MATCHES,
- g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES, "", "",
- G_TYPE_STRV,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_ALTSUBJECT_MATCHES] =
+ g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES, "", "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-domain-suffix-match:
@@ -4375,12 +3997,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* variable: IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH(+)
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_DOMAIN_SUFFIX_MATCH,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_DOMAIN_SUFFIX_MATCH] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-client-cert:
@@ -4408,12 +4029,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_INNER_CLIENT_CERT=/home/joe/mycert.crt
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_CLIENT_CERT,
- g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_CLIENT_CERT, "", "",
- G_TYPE_BYTES,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_CLIENT_CERT] =
+ g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_CLIENT_CERT, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-client-cert-password:
@@ -4427,13 +4047,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_CLIENT_CERT_PASSWORD,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_CLIENT_CERT_PASSWORD] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-client-cert-password-flags:
@@ -4445,13 +4064,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/* ---ifcfg-rh---
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:password:
@@ -4467,13 +4085,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* lookaside file, or it can be owned by a secret agent.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PASSWORD,
- g_param_spec_string (NM_SETTING_802_1X_PASSWORD, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PASSWORD] =
+ g_param_spec_string (NM_SETTING_802_1X_PASSWORD, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:password-flags:
@@ -4487,13 +4104,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Password flags for IEEE_8021X_PASSWORD password.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PASSWORD_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_PASSWORD_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PASSWORD_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_PASSWORD_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:password-raw:
@@ -4511,13 +4127,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_PASSWORD_RAW=041c8320083aa4bf
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PASSWORD_RAW,
- g_param_spec_boxed (NM_SETTING_802_1X_PASSWORD_RAW, "", "",
- G_TYPE_BYTES,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PASSWORD_RAW] =
+ g_param_spec_boxed (NM_SETTING_802_1X_PASSWORD_RAW, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:password-raw-flags:
@@ -4530,13 +4145,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: The property is not handled by ifcfg-rh plugin.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PASSWORD_RAW_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_PASSWORD_RAW_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PASSWORD_RAW_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_PASSWORD_RAW_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:private-key:
@@ -4576,12 +4190,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* example: IEEE_8021X_PRIVATE_KEY=/home/joe/mykey.p12
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PRIVATE_KEY,
- g_param_spec_boxed (NM_SETTING_802_1X_PRIVATE_KEY, "", "",
- G_TYPE_BYTES,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PRIVATE_KEY] =
+ g_param_spec_boxed (NM_SETTING_802_1X_PRIVATE_KEY, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:private-key-password:
@@ -4600,13 +4213,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* lookaside file, or it can be owned by a secret agent.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PRIVATE_KEY_PASSWORD,
- g_param_spec_string (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PRIVATE_KEY_PASSWORD] =
+ g_param_spec_string (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:private-key-password-flags:
@@ -4621,13 +4233,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Password flags for IEEE_8021X_PRIVATE_KEY_PASSWORD password.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PRIVATE_KEY_PASSWORD_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PRIVATE_KEY_PASSWORD_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-private-key:
@@ -4661,12 +4272,11 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Private key for inner authentication method for EAP-TLS.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_PRIVATE_KEY,
- g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, "", "",
- G_TYPE_BYTES,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_PRIVATE_KEY] =
+ g_param_spec_boxed (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-private-key-password:
@@ -4686,13 +4296,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* lookaside file, or it can be owned by a secret agent.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD,
- g_param_spec_string (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_PRIVATE_KEY_PASSWORD] =
+ g_param_spec_string (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:phase2-private-key-password-flags:
@@ -4707,13 +4316,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Password flags for IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD password.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:pin:
@@ -4726,13 +4334,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: The property is not handled by ifcfg-rh plugin.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PIN,
- g_param_spec_string (NM_SETTING_802_1X_PIN, "", "",
- NULL,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_SECRET |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PIN] =
+ g_param_spec_string (NM_SETTING_802_1X_PIN, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_SECRET |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:pin-flags:
@@ -4745,13 +4352,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: The property is not handled by ifcfg-rh plugin.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_PIN_FLAGS,
- g_param_spec_flags (NM_SETTING_802_1X_PIN_FLAGS, "", "",
- NM_TYPE_SETTING_SECRET_FLAGS,
- NM_SETTING_SECRET_FLAG_NONE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_PIN_FLAGS] =
+ g_param_spec_flags (NM_SETTING_802_1X_PIN_FLAGS, "", "",
+ NM_TYPE_SETTING_SECRET_FLAGS,
+ NM_SETTING_SECRET_FLAG_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:system-ca-certs:
@@ -4772,13 +4378,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: The property is not handled by ifcfg-rh plugin.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_SYSTEM_CA_CERTS,
- g_param_spec_boolean (NM_SETTING_802_1X_SYSTEM_CA_CERTS, "", "",
- FALSE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_SYSTEM_CA_CERTS] =
+ g_param_spec_boolean (NM_SETTING_802_1X_SYSTEM_CA_CERTS, "", "",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
/**
* NMSetting8021x:auth-timeout:
@@ -4795,13 +4400,14 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
* description: Timeout in seconds for the 802.1X authentication. Zero means the global default or 25.
* ---end---
*/
- g_object_class_install_property
- (object_class, PROP_AUTH_TIMEOUT,
- g_param_spec_int (NM_SETTING_802_1X_AUTH_TIMEOUT, "", "",
- 0, G_MAXINT32, 0,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_FUZZY_IGNORE |
- G_PARAM_STATIC_STRINGS));
+ obj_properties[PROP_AUTH_TIMEOUT] =
+ g_param_spec_int (NM_SETTING_802_1X_AUTH_TIMEOUT, "", "",
+ 0, G_MAXINT32, 0,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_FUZZY_IGNORE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_802_1X);
}
diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c
index 3b61736128..fcbeec6854 100644
--- a/libnm-core/nm-setting-vpn.c
+++ b/libnm-core/nm-setting-vpn.c
@@ -25,6 +25,8 @@
#include <errno.h>
#include <stdlib.h>
+#include "nm-utils/nm-secret-utils.h"
+
#include "nm-setting-vpn.h"
#include "nm-utils.h"
#include "nm-utils-private.h"
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index cb71d6e77d..c9162e971e 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -43,7 +43,7 @@
#include "nm-common-macros.h"
#include "nm-utils-private.h"
#include "nm-setting-private.h"
-#include "crypto.h"
+#include "nm-crypto.h"
#include "nm-setting-bond.h"
#include "nm-setting-bridge.h"
#include "nm-setting-infiniband.h"
@@ -2838,9 +2838,17 @@ nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, g
g_return_val_if_fail (uuid_type == NM_UTILS_UUID_TYPE_LEGACY || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
g_return_val_if_fail (!type_args || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
+ if (slen < 0)
+ slen = s ? strlen (s) : 0;
+
switch (uuid_type) {
case NM_UTILS_UUID_TYPE_LEGACY:
- crypto_md5_hash (NULL, 0, s, slen, (char *) uuid, sizeof (uuid));
+ nm_crypto_md5_hash (NULL,
+ 0,
+ (guint8 *) s,
+ slen,
+ (guint8 *) uuid,
+ sizeof (uuid));
break;
case NM_UTILS_UUID_TYPE_VARIANT3: {
uuid_t ns_uuid = { 0 };
@@ -2851,7 +2859,12 @@ nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, g
g_return_val_if_reached (NULL);
}
- crypto_md5_hash (s, slen, (char *) ns_uuid, sizeof (ns_uuid), (char *) uuid, sizeof (uuid));
+ nm_crypto_md5_hash ((guint8 *) s,
+ slen,
+ (guint8 *) ns_uuid,
+ sizeof (ns_uuid),
+ (guint8 *) uuid,
+ sizeof (uuid));
uuid[6] = (uuid[6] & 0x0F) | 0x30;
uuid[8] = (uuid[8] & 0x3F) | 0x80;
@@ -2911,110 +2924,6 @@ _nm_utils_uuid_generate_from_strings (const char *string1, ...)
/*****************************************************************************/
-/**
- * nm_utils_rsa_key_encrypt:
- * @data: (array length=len): RSA private key data to be encrypted
- * @len: length of @data
- * @in_password: (allow-none): existing password to use, if any
- * @out_password: (out) (allow-none): if @in_password was %NULL, a random
- * password will be generated and returned in this argument
- * @error: detailed error information on return, if an error occurred
- *
- * Encrypts the given RSA private key data with the given password (or generates
- * a password if no password was given) and converts the data to PEM format
- * suitable for writing to a file. It uses Triple DES cipher for the encryption.
- *
- * Returns: (transfer full): on success, PEM-formatted data suitable for writing
- * to a PEM-formatted certificate/private key file.
- **/
-GByteArray *
-nm_utils_rsa_key_encrypt (const guint8 *data,
- gsize len,
- const char *in_password,
- char **out_password,
- GError **error)
-{
- char salt[16];
- int salt_len;
- char *key = NULL, *enc = NULL, *pw_buf[32];
- gsize key_len = 0, enc_len = 0;
- GString *pem = NULL;
- char *tmp, *tmp_password = NULL;
- int left;
- const char *p;
- GByteArray *ret = NULL;
-
- g_return_val_if_fail (data != NULL, NULL);
- g_return_val_if_fail (len > 0, NULL);
- if (out_password)
- g_return_val_if_fail (*out_password == NULL, NULL);
-
- /* Make the password if needed */
- if (!in_password) {
- if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
- return NULL;
- in_password = tmp_password = nm_utils_bin2hexstr (pw_buf, sizeof (pw_buf), -1);
- }
-
- salt_len = 8;
- if (!crypto_randomize (salt, salt_len, error))
- goto out;
-
- key = crypto_make_des_aes_key (CIPHER_DES_EDE3_CBC, &salt[0], salt_len, in_password, &key_len, NULL);
- if (!key)
- g_return_val_if_reached (NULL);
-
- enc = crypto_encrypt (CIPHER_DES_EDE3_CBC, data, len, salt, salt_len, key, key_len, &enc_len, error);
- if (!enc)
- goto out;
-
- pem = g_string_sized_new (enc_len * 2 + 100);
- g_string_append (pem, "-----BEGIN RSA PRIVATE KEY-----\n");
- g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n");
-
- /* Convert the salt to a hex string */
- tmp = nm_utils_bin2hexstr (salt, salt_len, salt_len * 2);
- g_string_append_printf (pem, "DEK-Info: %s,%s\n\n", CIPHER_DES_EDE3_CBC, tmp);
- g_free (tmp);
-
- /* Convert the encrypted key to a base64 string */
- p = tmp = g_base64_encode ((const guchar *) enc, enc_len);
- left = strlen (tmp);
- while (left > 0) {
- g_string_append_len (pem, p, (left < 64) ? left : 64);
- g_string_append_c (pem, '\n');
- left -= 64;
- p += 64;
- }
- g_free (tmp);
-
- g_string_append (pem, "-----END RSA PRIVATE KEY-----\n");
-
- ret = g_byte_array_sized_new (pem->len);
- g_byte_array_append (ret, (const unsigned char *) pem->str, pem->len);
- if (tmp_password && out_password)
- *out_password = g_strdup (tmp_password);
-
-out:
- if (key) {
- memset (key, 0, key_len);
- g_free (key);
- }
- if (enc) {
- memset (enc, 0, enc_len);
- g_free (enc);
- }
- if (pem)
- g_string_free (pem, TRUE);
-
- if (tmp_password) {
- memset (tmp_password, 0, strlen (tmp_password));
- g_free (tmp_password);
- }
-
- return ret;
-}
-
static gboolean
file_has_extension (const char *filename, const char *extensions[])
{
@@ -3047,18 +2956,15 @@ gboolean
nm_utils_file_is_certificate (const char *filename)
{
const char *extensions[] = { ".der", ".pem", ".crt", ".cer", NULL };
- NMCryptoFileFormat file_format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
- GByteArray *cert;
+ NMCryptoFileFormat file_format;
g_return_val_if_fail (filename != NULL, FALSE);
if (!file_has_extension (filename, extensions))
return FALSE;
- cert = crypto_load_and_verify_certificate (filename, &file_format, NULL);
- if (cert)
- g_byte_array_unref (cert);
-
+ if (!nm_crypto_load_and_verify_certificate (filename, &file_format, NULL, NULL))
+ return FALSE;
return file_format = NM_CRYPTO_FILE_FORMAT_X509;
}
@@ -3084,7 +2990,7 @@ nm_utils_file_is_private_key (const char *filename, gboolean *out_encrypted)
if (!file_has_extension (filename, extensions))
return FALSE;
- return crypto_verify_private_key (filename, NULL, out_encrypted, NULL) != NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+ return nm_crypto_verify_private_key (filename, NULL, out_encrypted, NULL) != NM_CRYPTO_FILE_FORMAT_UNKNOWN;
}
/**
@@ -3100,7 +3006,7 @@ nm_utils_file_is_pkcs12 (const char *filename)
{
g_return_val_if_fail (filename != NULL, FALSE);
- return crypto_is_pkcs12_file (filename, NULL);
+ return nm_crypto_is_pkcs12_file (filename, NULL);
}
/*****************************************************************************/
@@ -3620,13 +3526,13 @@ nm_utils_hwaddr_len (int type)
g_return_val_if_reached (0);
}
-static guint8 *
-_str2bin (const char *asc,
- gboolean delimiter_required,
- const char *delimiter_candidates,
- guint8 *buffer,
- gsize buffer_length,
- gsize *out_len)
+guint8 *
+_nm_utils_str2bin_full (const char *asc,
+ gboolean delimiter_required,
+ const char *delimiter_candidates,
+ guint8 *buffer,
+ gsize buffer_length,
+ gsize *out_len)
{
const char *in = asc;
guint8 *out = buffer;
@@ -3696,7 +3602,7 @@ _str2bin (const char *asc,
return buffer;
}
-#define hwaddr_aton(asc, buffer, buffer_length, out_len) _str2bin ((asc), TRUE, ":-", (buffer), (buffer_length), (out_len))
+#define hwaddr_aton(asc, buffer, buffer_length, out_len) _nm_utils_str2bin_full ((asc), TRUE, ":-", (buffer), (buffer_length), (out_len))
/**
* nm_utils_hexstr2bin:
@@ -3722,7 +3628,7 @@ nm_utils_hexstr2bin (const char *hex)
buffer_length = strlen (hex) / 2 + 3;
buffer = g_malloc (buffer_length);
- if (!_str2bin (hex, FALSE, ":", buffer, buffer_length, &len)) {
+ if (!_nm_utils_str2bin_full (hex, FALSE, ":", buffer, buffer_length, &len)) {
g_free (buffer);
return NULL;
}
@@ -4602,7 +4508,7 @@ _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin)
return TRUE;
}
- if (_str2bin (duid, FALSE, ":", duid_arr, sizeof (duid_arr), &duid_len)) {
+ if (_nm_utils_str2bin_full (duid, FALSE, ":", duid_arr, sizeof (duid_arr), &duid_len)) {
/* MAX DUID length is 128 octects + the type code (2 octects). */
if ( duid_len > 2
&& duid_len <= (128 + 2)) {
diff --git a/libnm-core/tests/test-crypto.c b/libnm-core/tests/test-crypto.c
index 5fb26c1fcc..6b63e6fdd4 100644
--- a/libnm-core/tests/test-crypto.c
+++ b/libnm-core/tests/test-crypto.c
@@ -28,7 +28,7 @@
#include <stdio.h>
#include <string.h>
-#include "crypto.h"
+#include "nm-crypto-impl.h"
#include "nm-utils.h"
#include "nm-errors.h"
#include "nm-core-internal.h"
@@ -99,37 +99,20 @@ static void
test_cert (gconstpointer test_data)
{
gs_free char *path = NULL;
- GByteArray *array;
+ gs_unref_bytes GBytes *cert = NULL;
NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
GError *error = NULL;
+ gboolean success;
path = g_build_filename (TEST_CERT_DIR, (const char *) test_data, NULL);
- array = crypto_load_and_verify_certificate (path, &format, &error);
- g_assert_no_error (error);
+ success = nm_crypto_load_and_verify_certificate (path, &format, &cert, &error);
+ nmtst_assert_success (success, error);
g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_X509);
- g_byte_array_free (array, TRUE);
-
g_assert (nm_utils_file_is_certificate (path));
}
-static GByteArray *
-file_to_byte_array (const char *filename)
-{
- char *contents;
- GByteArray *array = NULL;
- gsize length = 0;
-
- if (g_file_get_contents (filename, &contents, &length, NULL)) {
- array = g_byte_array_sized_new (length);
- g_byte_array_append (array, (guint8 *) contents, length);
- g_assert (array->len == length);
- g_free (contents);
- }
- return array;
-}
-
static void
test_load_private_key (const char *path,
const char *password,
@@ -138,13 +121,13 @@ test_load_private_key (const char *path,
{
NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
gboolean is_encrypted = FALSE;
- GByteArray *array, *decrypted;
+ gs_unref_bytes GBytes *array = NULL;
GError *error = NULL;
g_assert (nm_utils_file_is_private_key (path, &is_encrypted));
g_assert (is_encrypted);
- array = crypto_decrypt_openssl_private_key (path, password, &key_type, &error);
+ array = nmtst_crypto_decrypt_openssl_private_key (path, password, &key_type, &error);
/* Even if the password is wrong, we should determine the key type */
g_assert_cmpint (key_type, ==, NM_CRYPTO_KEY_TYPE_RSA);
@@ -164,16 +147,14 @@ test_load_private_key (const char *path,
g_assert (array != NULL);
if (decrypted_path) {
- /* Compare the crypto decrypted key against a known-good decryption */
- decrypted = file_to_byte_array (decrypted_path);
- g_assert (decrypted != NULL);
- g_assert (decrypted->len == array->len);
- g_assert (memcmp (decrypted->data, array->data, array->len) == 0);
+ gs_free char *contents = NULL;
+ gsize length;
- g_byte_array_free (decrypted, TRUE);
+ /* Compare the crypto decrypted key against a known-good decryption */
+ if (!g_file_get_contents (decrypted_path, &contents, &length, NULL))
+ g_assert_not_reached ();
+ g_assert (nm_utils_gbytes_equal_mem (array, contents, length));
}
-
- g_byte_array_free (array, TRUE);
}
static void
@@ -187,7 +168,7 @@ test_load_pkcs12 (const char *path,
g_assert (nm_utils_file_is_private_key (path, NULL));
- format = crypto_verify_private_key (path, password, &is_encrypted, &error);
+ format = nm_crypto_verify_private_key (path, password, &is_encrypted, &error);
if (expected_error != -1) {
g_assert_error (error, NM_CRYPTO_ERROR, expected_error);
g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
@@ -209,7 +190,7 @@ test_load_pkcs12_no_password (const char *path)
g_assert (nm_utils_file_is_private_key (path, NULL));
/* We should still get a valid returned crypto file format */
- format = crypto_verify_private_key (path, NULL, &is_encrypted, &error);
+ format = nm_crypto_verify_private_key (path, NULL, &is_encrypted, &error);
g_assert_no_error (error);
g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_PKCS12);
g_assert (is_encrypted);
@@ -221,7 +202,7 @@ test_is_pkcs12 (const char *path, gboolean expect_fail)
gboolean is_pkcs12;
GError *error = NULL;
- is_pkcs12 = crypto_is_pkcs12_file (path, &error);
+ is_pkcs12 = nm_crypto_is_pkcs12_file (path, &error);
if (expect_fail) {
g_assert_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA);
@@ -244,7 +225,7 @@ test_load_pkcs8 (const char *path,
g_assert (nm_utils_file_is_private_key (path, NULL));
- format = crypto_verify_private_key (path, password, &is_encrypted, &error);
+ format = nm_crypto_verify_private_key (path, password, &is_encrypted, &error);
if (expected_error != -1) {
g_assert_error (error, NM_CRYPTO_ERROR, expected_error);
g_assert_cmpint (format, ==, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
@@ -261,34 +242,35 @@ test_encrypt_private_key (const char *path,
const char *password)
{
NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
- GByteArray *array, *encrypted, *re_decrypted;
+ gs_unref_bytes GBytes *array = NULL;
+ gs_unref_bytes GBytes *encrypted = NULL;
+ gs_unref_bytes GBytes *re_decrypted = NULL;
GError *error = NULL;
- array = crypto_decrypt_openssl_private_key (path, password, &key_type, &error);
- g_assert_no_error (error);
- g_assert (array != NULL);
+ array = nmtst_crypto_decrypt_openssl_private_key (path, password, &key_type, &error);
+ nmtst_assert_success (array, error);
g_assert_cmpint (key_type, ==, NM_CRYPTO_KEY_TYPE_RSA);
/* Now re-encrypt the private key */
- encrypted = nm_utils_rsa_key_encrypt (array->data, array->len, password, NULL, &error);
- g_assert_no_error (error);
- g_assert (encrypted != NULL);
+ encrypted = nmtst_crypto_rsa_key_encrypt (g_bytes_get_data (array, NULL),
+ g_bytes_get_size (array),
+ password,
+ NULL,
+ &error);
+ nmtst_assert_success (encrypted, error);
/* Then re-decrypt the private key */
key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
- re_decrypted = crypto_decrypt_openssl_private_key_data (encrypted->data, encrypted->len,
- password, &key_type, &error);
- g_assert_no_error (error);
- g_assert (re_decrypted != NULL);
+ re_decrypted = nmtst_crypto_decrypt_openssl_private_key_data (g_bytes_get_data (encrypted, NULL),
+ g_bytes_get_size (encrypted),
+ password,
+ &key_type,
+ &error);
+ nmtst_assert_success (re_decrypted, error);
g_assert_cmpint (key_type, ==, NM_CRYPTO_KEY_TYPE_RSA);
/* Compare the original decrypted key with the re-decrypted key */
- g_assert_cmpint (array->len, ==, re_decrypted->len);
- g_assert (!memcmp (array->data, re_decrypted->data, array->len));
-
- g_byte_array_free (re_decrypted, TRUE);
- g_byte_array_free (encrypted, TRUE);
- g_byte_array_free (array, TRUE);
+ g_assert (g_bytes_equal (array, re_decrypted));
}
static void
@@ -417,15 +399,16 @@ test_md5 (void)
for (i = 0; i < G_N_ELEMENTS (md5_tests); i++) {
memset (digest, 0, sizeof (digest));
- crypto_md5_hash (md5_tests[i].salt,
- /* crypto_md5_hash() used to clamp salt_len to 8. It
- * doesn't any more, so we need to do it here now to
- * get output that matches md5_tests[i].result.
- */
- md5_tests[i].salt ? 8 : 0,
- md5_tests[i].password,
- strlen (md5_tests[i].password),
- digest, md5_tests[i].digest_size);
+ nm_crypto_md5_hash ((const guint8 *) md5_tests[i].salt,
+ /* nm_crypto_md5_hash() used to clamp salt_len to 8. It
+ * doesn't any more, so we need to do it here now to
+ * get output that matches md5_tests[i].result.
+ */
+ md5_tests[i].salt ? 8 : 0,
+ (const guint8 *) md5_tests[i].password,
+ strlen (md5_tests[i].password),
+ (guint8 *) digest,
+ md5_tests[i].digest_size);
hex = nm_utils_bin2hexstr (digest, md5_tests[i].digest_size, -1);
g_assert_cmpstr (hex, ==, md5_tests[i].result);
@@ -444,7 +427,7 @@ main (int argc, char **argv)
nmtst_init (&argc, &argv, TRUE);
- success = crypto_init (&error);
+ success = _nm_crypto_init (&error);
g_assert_no_error (error);
g_assert (success);
diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c
index fb431ed702..c8eda381ee 100644
--- a/libnm-core/tests/test-setting.c
+++ b/libnm-core/tests/test-setting.c
@@ -67,10 +67,12 @@ static void
check_scheme_path (GBytes *value, const char *path)
{
const guint8 *p;
+ gsize l;
g_assert (value);
- p = g_bytes_get_data (value, NULL);
+ p = g_bytes_get_data (value, &l);
+ g_assert_cmpint (l, ==, strlen (path) + NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH) + 1);
g_assert (memcmp (p, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0);
p += strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH);
g_assert (memcmp (p, path, strlen (path)) == 0);
diff --git a/libnm-util/crypto_nss.c b/libnm-util/crypto_nss.c
index 5736db4f89..01bb28c33d 100644
--- a/libnm-util/crypto_nss.c
+++ b/libnm-util/crypto_nss.c
@@ -442,9 +442,6 @@ crypto_verify_pkcs12 (const GByteArray *data,
SECStatus s;
char *ucs2_password;
long ucs2_chars = 0;
-#ifndef WORDS_BIGENDIAN
- guint16 *p;
-#endif /* WORDS_BIGENDIAN */
if (error)
g_return_val_if_fail (*error == NULL, FALSE);
@@ -470,10 +467,14 @@ crypto_verify_pkcs12 (const GByteArray *data,
memset (ucs2_password, 0, ucs2_chars);
g_free (ucs2_password);
-#ifndef WORDS_BIGENDIAN
- for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++)
- *p = GUINT16_SWAP_LE_BE (*p);
-#endif /* WORDS_BIGENDIAN */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ {
+ guint16 *p;
+
+ for (p = (guint16 *) pw.data; p < (guint16 *) (pw.data + pw.len); p++)
+ *p = GUINT16_SWAP_LE_BE (*p);
+ }
+#endif
} else {
/* NULL password */
pw.data = NULL;
diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c
index 29c666c796..2213824edb 100644
--- a/libnm/nm-vpn-service-plugin.c
+++ b/libnm/nm-vpn-service-plugin.c
@@ -27,6 +27,7 @@
#include <signal.h>
#include <stdlib.h>
+#include "nm-utils/nm-secret-utils.h"
#include "nm-enum-types.h"
#include "nm-utils.h"
#include "nm-connection.h"
diff --git a/meson.build b/meson.build
index 4695efb2a2..44a7ee7ff5 100644
--- a/meson.build
+++ b/meson.build
@@ -470,12 +470,16 @@ if enable_polkit_agent
endif
config_h.set10('WITH_POLKIT_AGENT', enable_polkit_agent)
-# crypto
+crypto_gnutls_dep = dependency('gnutls', version: '>= 2.12', required: false)
+crypto_nss_dep = dependency('nss', required: false)
+
crypto = get_option('crypto')
if crypto == 'nss'
- crypto_dep = dependency('nss')
+ assert(crypto_nss_dep.found(), 'Requires gnutls crypto support')
+elif crypto == 'gnutls'
+ assert(crypto_gnutls_dep.found(), 'Requires gnutls crypto support')
else
- crypto_dep = dependency('gnutls', version: '>= 2.12')
+ error('bug')
endif
dbus_conf_dir = get_option('dbus_conf_dir')
@@ -1022,7 +1026,8 @@ output += '\n'
output += ' code coverage: ' + get_option('b_coverage').to_string() + '\n'
output += ' LTO: ' + get_option('b_lto').to_string() + '\n'
output += ' Linker garbage collection: ' + enable_ld_gc.to_string() + '\n'
-output += ' JSON validation for libnm: ' + enable_json_validation.to_string () + '\n'
+output += ' JSON validation for libnm: ' + enable_json_validation.to_string() + '\n'
+output += ' crypto: ' + crypto + ' (have-gnutls: ' + crypto_gnutls_dep.found().to_string() + ', have-nss: ' + crypto_nss_dep.found().to_string() + ')\n'
output += ' sanitizers: ' + get_option('b_sanitize') + '\n'
output += ' Mozilla Public Suffix List: ' + enable_libpsl.to_string() + '\n'
message(output)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ee78d29344..942b066131 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -51,9 +51,9 @@ clients/tui/nmtui-connect.c
clients/tui/nmtui-edit.c
clients/tui/nmtui-hostname.c
clients/tui/nmtui.c
-libnm-core/crypto.c
-libnm-core/crypto_gnutls.c
-libnm-core/crypto_nss.c
+libnm-core/nm-crypto.c
+libnm-core/nm-crypto-gnutls.c
+libnm-core/nm-crypto-nss.c
libnm-core/nm-connection.c
libnm-core/nm-dbus-utils.c
libnm-core/nm-keyfile.c
diff --git a/shared/meson.build b/shared/meson.build
index 8faec8765b..e1cf620bfd 100644
--- a/shared/meson.build
+++ b/shared/meson.build
@@ -50,7 +50,9 @@ shared_files_libnm_core = files('''
nm-utils/nm-dedup-multi.c
nm-utils/nm-enum-utils.c
nm-utils/nm-hash-utils.c
+ nm-utils/nm-io-utils.c
nm-utils/nm-random-utils.c
+ nm-utils/nm-secret-utils.c
nm-utils/nm-shared-utils.c
nm-utils/nm-udev-utils.c
'''.split())
diff --git a/shared/nm-utils/nm-io-utils.c b/shared/nm-utils/nm-io-utils.c
new file mode 100644
index 0000000000..88cb13ff18
--- /dev/null
+++ b/shared/nm-utils/nm-io-utils.c
@@ -0,0 +1,430 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-io-utils.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "nm-shared-utils.h"
+#include "nm-secret-utils.h"
+
+/*****************************************************************************/
+
+_nm_printf (3, 4)
+static int
+_get_contents_error (GError **error, int errsv, const char *format, ...)
+{
+ if (errsv < 0)
+ errsv = -errsv;
+ else if (!errsv)
+ errsv = errno;
+
+ if (error) {
+ char *msg;
+ va_list args;
+
+ va_start (args, format);
+ msg = g_strdup_vprintf (format, args);
+ va_end (args);
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errsv),
+ "%s: %s",
+ msg, g_strerror (errsv));
+ g_free (msg);
+ }
+ return -errsv;
+}
+
+static char *
+_mem_realloc (char *old, gboolean do_bzero_mem, gsize cur_len, gsize new_len)
+{
+ char *new;
+
+ /* re-allocating to zero bytes is an odd case. We don't need it
+ * and it's not supported. */
+ nm_assert (new_len > 0);
+
+ /* regardless of success/failure, @old will always be freed/consumed. */
+
+ if (do_bzero_mem && cur_len > 0) {
+ new = g_try_malloc (new_len);
+ if (new)
+ memcpy (new, old, NM_MIN (cur_len, new_len));
+ nm_explicit_bzero (old, cur_len);
+ g_free (old);
+ } else {
+ new = g_try_realloc (old, new_len);
+ if (!new)
+ g_free (old);
+ }
+
+ return new;
+}
+
+/**
+ * nm_utils_fd_get_contents:
+ * @fd: open file descriptor to read. The fd will not be closed,
+ * but don't rely on its state afterwards.
+ * @close_fd: if %TRUE, @fd will be closed by the function.
+ * Passing %TRUE here might safe a syscall for dup().
+ * @max_length: allocate at most @max_length bytes. If the
+ * file is larger, reading will fail. Set to zero to use
+ * a very large default.
+ * WARNING: @max_length is here to avoid a crash for huge/unlimited files.
+ * For example, stat(/sys/class/net/enp0s25/ifindex) gives a filesize of
+ * 4K, although the actual real is small. @max_length is the memory
+ * allocated in the process of reading the file, thus it must be at least
+ * the size reported by fstat.
+ * If you set it to 1K, read will fail because fstat() claims the
+ * file is larger.
+ * @flags: %NMUtilsFileGetContentsFlags for reading the file.
+ * @contents: the output buffer with the file read. It is always
+ * NUL terminated. The buffer is at most @max_length long, including
+ * the NUL byte. That is, it reads only files up to a length of
+ * @max_length - 1 bytes.
+ * @length: optional output argument of the read file size.
+ *
+ * A reimplementation of g_file_get_contents() with a few differences:
+ * - accepts an open fd, instead of a path name. This allows you to
+ * use openat().
+ * - limits the maxium filesize to max_length.
+ *
+ * Returns: a negative error code on failure.
+ */
+int
+nm_utils_fd_get_contents (int fd,
+ gboolean close_fd,
+ gsize max_length,
+ NMUtilsFileGetContentsFlags flags,
+ char **contents,
+ gsize *length,
+ GError **error)
+{
+ nm_auto_close int fd_keeper = close_fd ? fd : -1;
+ struct stat stat_buf;
+ gs_free char *str = NULL;
+ const bool do_bzero_mem = NM_FLAGS_HAS (flags, NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET);
+
+ g_return_val_if_fail (fd >= 0, -EINVAL);
+ g_return_val_if_fail (contents, -EINVAL);
+ g_return_val_if_fail (!error || !*error, -EINVAL);
+
+ if (fstat (fd, &stat_buf) < 0)
+ return _get_contents_error (error, 0, "failure during fstat");
+
+ if (!max_length) {
+ /* default to a very large size, but not extreme */
+ max_length = 2 * 1024 * 1024;
+ }
+
+ if ( stat_buf.st_size > 0
+ && S_ISREG (stat_buf.st_mode)) {
+ const gsize n_stat = stat_buf.st_size;
+ ssize_t n_read;
+
+ if (n_stat > max_length - 1)
+ return _get_contents_error (error, EMSGSIZE, "file too large (%zu+1 bytes with maximum %zu bytes)", n_stat, max_length);
+
+ str = g_try_malloc (n_stat + 1);
+ if (!str)
+ return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu+1 bytes", n_stat);
+
+ n_read = nm_utils_fd_read_loop (fd, str, n_stat, TRUE);
+ if (n_read < 0) {
+ if (do_bzero_mem)
+ nm_explicit_bzero (str, n_stat);
+ return _get_contents_error (error, n_read, "error reading %zu bytes from file descriptor", n_stat);
+ }
+ str[n_read] = '\0';
+
+ if (n_read < n_stat) {
+ if (!(str = _mem_realloc (str, do_bzero_mem, n_stat + 1, n_read + 1)))
+ return _get_contents_error (error, ENOMEM, "failure to reallocate buffer with %zu bytes", n_read + 1);
+ }
+ NM_SET_OUT (length, n_read);
+ } else {
+ nm_auto_fclose FILE *f = NULL;
+ char buf[4096];
+ gsize n_have, n_alloc;
+ int fd2;
+
+ if (fd_keeper >= 0)
+ fd2 = nm_steal_fd (&fd_keeper);
+ else {
+ fd2 = fcntl (fd, F_DUPFD_CLOEXEC, 0);
+ if (fd2 < 0)
+ return _get_contents_error (error, 0, "error during dup");
+ }
+
+ if (!(f = fdopen (fd2, "r"))) {
+ nm_close (fd2);
+ return _get_contents_error (error, 0, "failure during fdopen");
+ }
+
+ n_have = 0;
+ n_alloc = 0;
+
+ while (!feof (f)) {
+ int errsv;
+ gsize n_read;
+
+ n_read = fread (buf, 1, sizeof (buf), f);
+ errsv = errno;
+ if (ferror (f)) {
+ if (do_bzero_mem)
+ nm_explicit_bzero (buf, sizeof (buf));
+ return _get_contents_error (error, errsv, "error during fread");
+ }
+
+ if ( n_have > G_MAXSIZE - 1 - n_read
+ || n_have + n_read + 1 > max_length) {
+ if (do_bzero_mem)
+ nm_explicit_bzero (buf, sizeof (buf));
+ return _get_contents_error (error, EMSGSIZE, "file stream too large (%zu+1 bytes with maximum %zu bytes)",
+ (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read,
+ max_length);
+ }
+
+ if (n_have + n_read + 1 >= n_alloc) {
+ gsize old_n_alloc = n_alloc;
+
+ if (n_alloc != 0) {
+ nm_assert (str);
+ if (n_alloc >= max_length / 2)
+ n_alloc = max_length;
+ else
+ n_alloc *= 2;
+ } else {
+ nm_assert (!str);
+ n_alloc = NM_MIN (n_read + 1, sizeof (buf));
+ }
+
+ if (!(str = _mem_realloc (str, do_bzero_mem, old_n_alloc, n_alloc))) {
+ if (do_bzero_mem)
+ nm_explicit_bzero (buf, sizeof (buf));
+ return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu bytes", n_alloc);
+ }
+ }
+
+ memcpy (str + n_have, buf, n_read);
+ n_have += n_read;
+ }
+
+ if (do_bzero_mem)
+ nm_explicit_bzero (buf, sizeof (buf));
+
+ if (n_alloc == 0)
+ str = g_new0 (char, 1);
+ else {
+ str[n_have] = '\0';
+ if (n_have + 1 < n_alloc) {
+ if (!(str = _mem_realloc (str, do_bzero_mem, n_alloc, n_have + 1)))
+ return _get_contents_error (error, ENOMEM, "failure to truncate buffer to %zu bytes", n_have + 1);
+ }
+ }
+
+ NM_SET_OUT (length, n_have);
+ }
+
+ *contents = g_steal_pointer (&str);
+ return 0;
+}
+
+/**
+ * nm_utils_file_get_contents:
+ * @dirfd: optional file descriptor to use openat(). If negative, use plain open().
+ * @filename: the filename to open. Possibly relative to @dirfd.
+ * @max_length: allocate at most @max_length bytes.
+ * WARNING: see nm_utils_fd_get_contents() hint about @max_length.
+ * @flags: %NMUtilsFileGetContentsFlags for reading the file.
+ * @contents: the output buffer with the file read. It is always
+ * NUL terminated. The buffer is at most @max_length long, including
+ * the NUL byte. That is, it reads only files up to a length of
+ * @max_length - 1 bytes.
+ * @length: optional output argument of the read file size.
+ *
+ * A reimplementation of g_file_get_contents() with a few differences:
+ * - accepts an @dirfd to open @filename relative to that path via openat().
+ * - limits the maxium filesize to max_length.
+ * - uses O_CLOEXEC on internal file descriptor
+ *
+ * Returns: a negative error code on failure.
+ */
+int
+nm_utils_file_get_contents (int dirfd,
+ const char *filename,
+ gsize max_length,
+ NMUtilsFileGetContentsFlags flags,
+ char **contents,
+ gsize *length,
+ GError **error)
+{
+ int fd;
+ int errsv;
+
+ g_return_val_if_fail (filename && filename[0], -EINVAL);
+
+ if (dirfd >= 0) {
+ fd = openat (dirfd, filename, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ errsv = errno;
+
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errsv),
+ "Failed to open file \"%s\" with openat: %s",
+ filename,
+ g_strerror (errsv));
+ return -errsv;
+ }
+ } else {
+ fd = open (filename, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ errsv = errno;
+
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errsv),
+ "Failed to open file \"%s\": %s",
+ filename,
+ g_strerror (errsv));
+ return -errsv;
+ }
+ }
+ return nm_utils_fd_get_contents (fd,
+ TRUE,
+ max_length,
+ flags,
+ contents,
+ length,
+ error);
+}
+
+/*****************************************************************************/
+
+/*
+ * Copied from GLib's g_file_set_contents() et al., but allows
+ * specifying a mode for the new file.
+ */
+gboolean
+nm_utils_file_set_contents (const char *filename,
+ const char *contents,
+ gssize length,
+ mode_t mode,
+ GError **error)
+{
+ gs_free char *tmp_name = NULL;
+ struct stat statbuf;
+ int errsv;
+ gssize s;
+ int fd;
+
+ g_return_val_if_fail (filename, FALSE);
+ g_return_val_if_fail (contents || !length, FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+ g_return_val_if_fail (length >= -1, FALSE);
+
+ if (length == -1)
+ length = strlen (contents);
+
+ tmp_name = g_strdup_printf ("%s.XXXXXX", filename);
+ fd = g_mkstemp_full (tmp_name, O_RDWR, mode);
+ if (fd < 0) {
+ errsv = errno;
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errsv),
+ "failed to create file %s: %s",
+ tmp_name,
+ g_strerror (errsv));
+ return FALSE;
+ }
+
+ while (length > 0) {
+ s = write (fd, contents, length);
+ if (s < 0) {
+ errsv = errno;
+ if (errsv == EINTR)
+ continue;
+
+ nm_close (fd);
+ unlink (tmp_name);
+
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errsv),
+ "failed to write to file %s: %s",
+ tmp_name,
+ g_strerror (errsv));
+ return FALSE;
+ }
+
+ g_assert (s <= length);
+
+ contents += s;
+ length -= s;
+ }
+
+ /* If the final destination exists and is > 0 bytes, we want to sync the
+ * newly written file to ensure the data is on disk when we rename over
+ * the destination. Otherwise if we get a system crash we can lose both
+ * the new and the old file on some filesystems. (I.E. those that don't
+ * guarantee the data is written to the disk before the metadata.)
+ */
+ if ( lstat (filename, &statbuf) == 0
+ && statbuf.st_size > 0
+ && fsync (fd) != 0) {
+ errsv = errno;
+
+ nm_close (fd);
+ unlink (tmp_name);
+
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errsv),
+ "failed to fsync %s: %s",
+ tmp_name,
+ g_strerror (errsv));
+ return FALSE;
+ }
+
+ nm_close (fd);
+
+ if (rename (tmp_name, filename)) {
+ errsv = errno;
+ unlink (tmp_name);
+ g_set_error (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errsv),
+ "failed to rename %s to %s: %s",
+ tmp_name,
+ filename,
+ g_strerror (errsv));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/shared/nm-utils/nm-io-utils.h b/shared/nm-utils/nm-io-utils.h
new file mode 100644
index 0000000000..dc72a2a6c5
--- /dev/null
+++ b/shared/nm-utils/nm-io-utils.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_IO_UTILS_H__
+#define __NM_IO_UTILS_H__
+
+#include "nm-macros-internal.h"
+
+/*****************************************************************************/
+
+/**
+ * NMUtilsFileGetContentsFlags:
+ * @NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE: no flag
+ * @NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET: if present, ensure that no
+ * data is left in memory. Essentially, it means to call explicity_bzero()
+ * to not leave key material on the heap (when reading secrets).
+ */
+typedef enum {
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE = 0,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET = (1 << 0),
+} NMUtilsFileGetContentsFlags;
+
+int nm_utils_fd_get_contents (int fd,
+ gboolean close_fd,
+ gsize max_length,
+ NMUtilsFileGetContentsFlags flags,
+ char **contents,
+ gsize *length,
+ GError **error);
+
+int nm_utils_file_get_contents (int dirfd,
+ const char *filename,
+ gsize max_length,
+ NMUtilsFileGetContentsFlags flags,
+ char **contents,
+ gsize *length,
+ GError **error);
+
+gboolean nm_utils_file_set_contents (const char *filename,
+ const char *contents,
+ gssize length,
+ mode_t mode,
+ GError **error);
+
+#endif /* __NM_IO_UTILS_H__ */
diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h
index 3d2520d131..084219b4bb 100644
--- a/shared/nm-utils/nm-macros-internal.h
+++ b/shared/nm-utils/nm-macros-internal.h
@@ -91,12 +91,6 @@ static inline void name (Type *v) \
func (*v); \
}
-#define NM_AUTO_DEFINE_FCN_STRUCT(Type, name, func) \
-static inline void name (Type *v) \
-{ \
- func (v); \
-}
-
/*****************************************************************************/
/**
@@ -213,7 +207,6 @@ NM_AUTO_DEFINE_FCN0 (GKeyFile *, gs_local_keyfile_unref, g_key_file_unref)
/*****************************************************************************/
static inline int nm_close (int fd);
-static inline void nm_free_secret (char *secret);
/**
* nm_auto_free:
@@ -244,22 +237,14 @@ NM_AUTO_DEFINE_FCN (GList *, _nm_auto_free_list, g_list_free)
NM_AUTO_DEFINE_FCN0 (GChecksum *, _nm_auto_checksum_free, g_checksum_free)
#define nm_auto_free_checksum nm_auto(_nm_auto_checksum_free)
-NM_AUTO_DEFINE_FCN (char *, _nm_auto_free_secret, nm_free_secret)
-/**
- * nm_auto_free_secret:
- *
- * Call g_free() on a variable location when it goes out of scope.
- * Also, previously, calls memset(loc, 0, strlen(loc)) to clear out
- * the secret.
- */
-#define nm_auto_free_secret nm_auto(_nm_auto_free_secret)
-
-NM_AUTO_DEFINE_FCN_STRUCT (GValue, _nm_auto_unset_gvalue, g_value_unset)
-#define nm_auto_unset_gvalue nm_auto(_nm_auto_unset_gvalue)
+#define nm_auto_unset_gvalue nm_auto(g_value_unset)
NM_AUTO_DEFINE_FCN_VOID0 (void *, _nm_auto_unref_gtypeclass, g_type_class_unref)
#define nm_auto_unref_gtypeclass nm_auto(_nm_auto_unref_gtypeclass)
+NM_AUTO_DEFINE_FCN0 (GByteArray *, _nm_auto_unref_bytearray, g_byte_array_unref)
+#define nm_auto_unref_bytearray nm_auto(_nm_auto_unref_bytearray)
+
static inline void
_nm_auto_free_gstring (GString **str)
{
@@ -834,15 +819,6 @@ fcn (void) \
/*****************************************************************************/
-static inline void
-nm_free_secret (char *secret)
-{
- if (secret) {
- memset (secret, 0, strlen (secret));
- g_free (secret);
- }
-}
-
static inline GString *
nm_gstring_prepare (GString **l)
{
@@ -924,7 +900,7 @@ nm_str_realloc (char *str)
#define NM_GOBJECT_PROPERTIES_DEFINE_BASE(...) \
typedef enum { \
- _PROPERTY_ENUMS_0, \
+ PROP_0, \
__VA_ARGS__ \
_PROPERTY_ENUMS_LAST, \
} _PropertyEnums; \
@@ -945,8 +921,11 @@ _nm_gobject_notify_together_impl (obj_type *obj, guint n, const _PropertyEnums *
while (n-- > 0) { \
const _PropertyEnums prop = *props++; \
\
- nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties)); \
- g_object_notify_by_pspec ((GObject *) obj, obj_properties[prop]); \
+ if (prop != PROP_0) { \
+ nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties)); \
+ nm_assert (obj_properties[prop]); \
+ g_object_notify_by_pspec ((GObject *) obj, obj_properties[prop]); \
+ } \
} \
if (freeze_thaw) \
g_object_thaw_notify ((GObject *) obj); \
diff --git a/shared/nm-utils/nm-secret-utils.c b/shared/nm-utils/nm-secret-utils.c
new file mode 100644
index 0000000000..65f99c65d9
--- /dev/null
+++ b/shared/nm-utils/nm-secret-utils.c
@@ -0,0 +1,134 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-secret-utils.h"
+
+/*****************************************************************************/
+
+void
+nm_explicit_bzero (void *s, gsize n)
+{
+ /* gracefully handle n == 0. This is important, callers rely on it. */
+ if (n > 0) {
+ nm_assert (s);
+#if defined (HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO
+ explicit_bzero (s, n);
+#else
+ /* don't bother with a workaround. Use a reasonable glibc. */
+ memset (s, 0, n);
+#endif
+ }
+}
+
+/*****************************************************************************/
+
+char *
+nm_secret_strchomp (char *secret)
+{
+ gsize len;
+
+ g_return_val_if_fail (secret, NULL);
+
+ /* it's actually identical to g_strchomp(). However,
+ * the glib function does not document, that it clears the
+ * memory. For @secret, we don't only want to truncate trailing
+ * spaces, we want to overwrite them with NUL. */
+
+ len = strlen (secret);
+ while (len--) {
+ if (g_ascii_isspace ((guchar) secret[len]))
+ secret[len] = '\0';
+ else
+ break;
+ }
+
+ return secret;
+}
+
+/*****************************************************************************/
+
+GBytes *
+nm_secret_copy_to_gbytes (gconstpointer mem, gsize mem_len)
+{
+ NMSecretBuf *b;
+
+ if (mem_len == 0)
+ return g_bytes_new_static ("", 0);
+
+ nm_assert (mem);
+
+ /* NUL terminate the buffer.
+ *
+ * The entire buffer is already malloc'ed and likely has some room for padding.
+ * Thus, in many situations, this additional byte will cause no overhead in
+ * practice.
+ *
+ * Even if it causes an overhead, do it just for safety. Yes, the returned
+ * bytes is not a NUL terminated string and no user must rely on this. Do
+ * not treat binary data as NUL terminated strings, unless you know what
+ * you are doing. Anyway, defensive FTW.
+ */
+
+ b = nm_secret_buf_new (mem_len + 1);
+ memcpy (b->bin, mem, mem_len);
+ b->bin[mem_len] = 0;
+ return nm_secret_buf_to_gbytes_take (b, mem_len);
+}
+
+/*****************************************************************************/
+
+NMSecretBuf *
+nm_secret_buf_new (gsize len)
+{
+ NMSecretBuf *secret;
+
+ nm_assert (len > 0);
+
+ secret = g_malloc (sizeof (NMSecretBuf) + len);
+ *((gsize *) &(secret->len)) = len;
+ return secret;
+}
+
+static void
+_secret_buf_free (gpointer user_data)
+{
+ NMSecretBuf *secret = user_data;
+
+ nm_assert (secret);
+ nm_assert (secret->len > 0);
+
+ nm_explicit_bzero (secret->bin, secret->len);
+ g_free (user_data);
+}
+
+GBytes *
+nm_secret_buf_to_gbytes_take (NMSecretBuf *secret, gssize actual_len)
+{
+ nm_assert (secret);
+ nm_assert (secret->len > 0);
+ nm_assert (actual_len == -1 || (actual_len >= 0 && actual_len <= secret->len));
+ return g_bytes_new_with_free_func (secret->bin,
+ actual_len >= 0 ? (gsize) actual_len : secret->len,
+ _secret_buf_free,
+ secret);
+}
diff --git a/shared/nm-utils/nm-secret-utils.h b/shared/nm-utils/nm-secret-utils.h
new file mode 100644
index 0000000000..21a3c1ba11
--- /dev/null
+++ b/shared/nm-utils/nm-secret-utils.h
@@ -0,0 +1,151 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_SECRET_UTILS_H__
+#define __NM_SECRET_UTILS_H__
+
+#include "nm-macros-internal.h"
+
+/*****************************************************************************/
+
+void nm_explicit_bzero (void *s, gsize n);
+
+/*****************************************************************************/
+
+char *nm_secret_strchomp (char *secret);
+
+/*****************************************************************************/
+
+static inline void
+nm_free_secret (char *secret)
+{
+ if (secret) {
+ nm_explicit_bzero (secret, strlen (secret));
+ g_free (secret);
+ }
+}
+
+NM_AUTO_DEFINE_FCN (char *, _nm_auto_free_secret, nm_free_secret)
+/**
+ * nm_auto_free_secret:
+ *
+ * Call g_free() on a variable location when it goes out of scope.
+ * Also, previously, calls memset(loc, 0, strlen(loc)) to clear out
+ * the secret.
+ */
+#define nm_auto_free_secret nm_auto(_nm_auto_free_secret)
+
+/*****************************************************************************/
+
+GBytes *nm_secret_copy_to_gbytes (gconstpointer mem, gsize mem_len);
+
+/*****************************************************************************/
+
+/* NMSecretPtr is a pair of malloc'ed data pointer and the length of the
+ * data. The purpose is to use it in combination with nm_auto_clear_secret_ptr
+ * which ensures that the data pointer (with all len bytes) is cleared upon
+ * cleanup. */
+typedef struct {
+ gsize len;
+
+ /* the data pointer. This pointer must be allocated with malloc (at least
+ * when used with nm_secret_ptr_clear()). */
+ union {
+ char *str;
+ void *ptr;
+ guint8 *bin;
+ };
+} NMSecretPtr;
+
+static inline void
+nm_secret_ptr_clear (NMSecretPtr *secret)
+{
+ if (secret) {
+ if (secret->len > 0) {
+ if (secret->ptr)
+ nm_explicit_bzero (secret->ptr, secret->len);
+ secret->len = 0;
+ }
+ nm_clear_g_free (&secret->ptr);
+ }
+}
+
+#define nm_auto_clear_secret_ptr nm_auto(nm_secret_ptr_clear)
+
+#define NM_SECRET_PTR_STATIC(_len) \
+ ((const NMSecretPtr) { \
+ .len = _len, \
+ .ptr = ((guint8 [_len]) { }), \
+ })
+
+static inline void
+nm_secret_ptr_clear_static (const NMSecretPtr *secret)
+{
+ if (secret) {
+ if (secret->len > 0) {
+ nm_assert (secret->ptr);
+ nm_explicit_bzero (secret->ptr, secret->len);
+ }
+ }
+}
+
+#define nm_auto_clear_static_secret_ptr nm_auto(nm_secret_ptr_clear_static)
+
+static inline void
+nm_secret_ptr_move (NMSecretPtr *dst, NMSecretPtr *src)
+{
+ if (dst && dst != src) {
+ *dst = *src;
+ src->len = 0;
+ src->ptr = NULL;
+ }
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ const gsize len;
+ union {
+ char str[0];
+ guint8 bin[0];
+ };
+} NMSecretBuf;
+
+static inline void
+_nm_auto_free_secret_buf (NMSecretBuf **ptr)
+{
+ NMSecretBuf *b = *ptr;
+
+ if (b) {
+ nm_assert (b->len > 0);
+ nm_explicit_bzero (b->bin, b->len);
+ g_free (b);
+ }
+}
+#define nm_auto_free_secret_buf nm_auto(_nm_auto_free_secret_buf)
+
+NMSecretBuf *nm_secret_buf_new (gsize len);
+
+GBytes *nm_secret_buf_to_gbytes_take (NMSecretBuf *secret, gssize actual_len);
+
+/*****************************************************************************/
+
+#endif /* __NM_SECRET_UTILS_H__ */
diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h
index 26875534d9..171544feab 100644
--- a/shared/nm-utils/nm-shared-utils.h
+++ b/shared/nm-utils/nm-shared-utils.h
@@ -26,6 +26,25 @@
/*****************************************************************************/
+static inline gboolean
+_NM_INT_NOT_NEGATIVE (gssize val)
+{
+ /* whether an enum (without negative values) is a signed int, depends on compiler options
+ * and compiler implementation.
+ *
+ * When using such an enum for accessing an array, one naturally wants to check
+ * that the enum is not negative. However, the compiler doesn't like a plain
+ * comparisong "enum_val >= 0", because (if the enum is unsigned), it will warn
+ * that the expression is always true *duh*. Not even a cast to a signed
+ * type helps to avoid the compiler warning in any case.
+ *
+ * The sole purpose of this function is to avoid a compiler warning, when checking
+ * that an enum is not negative. */
+ return val >= 0;
+}
+
+/*****************************************************************************/
+
static inline char
nm_utils_addr_family_to_char (int addr_family)
{
@@ -202,6 +221,12 @@ nm_utils_is_separator (const char c)
/*****************************************************************************/
+static inline gboolean
+nm_gbytes_equal0 (GBytes *a, GBytes *b)
+{
+ return a == b || (a && b && g_bytes_equal (a, b));
+}
+
gboolean nm_utils_gbytes_equal_mem (GBytes *bytes,
gconstpointer mem_data,
gsize mem_len);
@@ -210,6 +235,27 @@ GVariant *nm_utils_gbytes_to_variant_ay (GBytes *bytes);
/*****************************************************************************/
+static inline int
+nm_utils_hexchar_to_int (char ch)
+{
+ G_STATIC_ASSERT_EXPR ('0' < 'A');
+ G_STATIC_ASSERT_EXPR ('A' < 'a');
+
+ if (ch >= '0') {
+ if (ch <= '9')
+ return ch - '0';
+ if (ch >= 'A') {
+ if (ch <= 'F')
+ return ((int) ch) + (10 - (int) 'A');
+ if (ch >= 'a' && ch <= 'f')
+ return ((int) ch) + (10 - (int) 'a');
+ }
+ }
+ return -1;
+}
+
+/*****************************************************************************/
+
const char *nm_utils_dbus_path_get_last_component (const char *dbus_path);
int nm_utils_dbus_path_cmp (const char *dbus_path_a, const char *dbus_path_b);
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 9aab919ebf..ca8c952671 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -38,6 +38,7 @@
#include <net/ethernet.h>
#include "nm-utils/nm-random-utils.h"
+#include "nm-utils/nm-io-utils.h"
#include "nm-utils.h"
#include "nm-core-internal.h"
#include "nm-setting-connection.h"
@@ -2560,262 +2561,6 @@ nm_utils_machine_id_read (void)
/*****************************************************************************/
-_nm_printf (3, 4)
-static int
-_get_contents_error (GError **error, int errsv, const char *format, ...)
-{
- if (errsv < 0)
- errsv = -errsv;
- else if (!errsv)
- errsv = errno;
-
- if (error) {
- char *msg;
- va_list args;
-
- va_start (args, format);
- msg = g_strdup_vprintf (format, args);
- va_end (args);
- g_set_error (error,
- G_FILE_ERROR,
- g_file_error_from_errno (errsv),
- "%s: %s",
- msg, g_strerror (errsv));
- g_free (msg);
- }
- return -errsv;
-}
-
-/**
- * nm_utils_fd_get_contents:
- * @fd: open file descriptor to read. The fd will not be closed,
- * but don't rely on its state afterwards.
- * @close_fd: if %TRUE, @fd will be closed by the function.
- * Passing %TRUE here might safe a syscall for dup().
- * @max_length: allocate at most @max_length bytes. If the
- * file is larger, reading will fail. Set to zero to use
- * a very large default.
- *
- * WARNING: @max_length is here to avoid a crash for huge/unlimited files.
- * For example, stat(/sys/class/net/enp0s25/ifindex) gives a filesize of
- * 4K, although the actual real is small. @max_length is the memory
- * allocated in the process of reading the file, thus it must be at least
- * the size reported by fstat.
- * If you set it to 1K, read will fail because fstat() claims the
- * file is larger.
- *
- * @contents: the output buffer with the file read. It is always
- * NUL terminated. The buffer is at most @max_length long, including
- * the NUL byte. That is, it reads only files up to a length of
- * @max_length - 1 bytes.
- * @length: optional output argument of the read file size.
- *
- * A reimplementation of g_file_get_contents() with a few differences:
- * - accepts an open fd, instead of a path name. This allows you to
- * use openat().
- * - limits the maxium filesize to max_length.
- *
- * Returns: a negative error code on failure.
- */
-int
-nm_utils_fd_get_contents (int fd,
- gboolean close_fd,
- gsize max_length,
- char **contents,
- gsize *length,
- GError **error)
-{
- nm_auto_close int fd_keeper = close_fd ? fd : -1;
- struct stat stat_buf;
- gs_free char *str = NULL;
-
- g_return_val_if_fail (fd >= 0, -EINVAL);
- g_return_val_if_fail (contents, -EINVAL);
- g_return_val_if_fail (!error || !*error, -EINVAL);
-
- if (fstat (fd, &stat_buf) < 0)
- return _get_contents_error (error, 0, "failure during fstat");
-
- if (!max_length) {
- /* default to a very large size, but not extreme */
- max_length = 2 * 1024 * 1024;
- }
-
- if ( stat_buf.st_size > 0
- && S_ISREG (stat_buf.st_mode)) {
- const gsize n_stat = stat_buf.st_size;
- ssize_t n_read;
-
- if (n_stat > max_length - 1)
- return _get_contents_error (error, EMSGSIZE, "file too large (%zu+1 bytes with maximum %zu bytes)", n_stat, max_length);
-
- str = g_try_malloc (n_stat + 1);
- if (!str)
- return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu+1 bytes", n_stat);
-
- n_read = nm_utils_fd_read_loop (fd, str, n_stat, TRUE);
- if (n_read < 0)
- return _get_contents_error (error, n_read, "error reading %zu bytes from file descriptor", n_stat);
- str[n_read] = '\0';
-
- if (n_read < n_stat) {
- char *tmp;
-
- tmp = g_try_realloc (str, n_read + 1);
- if (!tmp)
- return _get_contents_error (error, ENOMEM, "failure to reallocate buffer with %zu bytes", n_read + 1);
- str = tmp;
- }
- NM_SET_OUT (length, n_read);
- } else {
- nm_auto_fclose FILE *f = NULL;
- char buf[4096];
- gsize n_have, n_alloc;
- int fd2;
-
- if (fd_keeper >= 0)
- fd2 = nm_steal_fd (&fd_keeper);
- else {
- fd2 = fcntl (fd, F_DUPFD_CLOEXEC, 0);
- if (fd2 < 0)
- return _get_contents_error (error, 0, "error during dup");
- }
-
- if (!(f = fdopen (fd2, "r"))) {
- nm_close (fd2);
- return _get_contents_error (error, 0, "failure during fdopen");
- }
-
- n_have = 0;
- n_alloc = 0;
-
- while (!feof (f)) {
- int errsv;
- gsize n_read;
-
- n_read = fread (buf, 1, sizeof (buf), f);
- errsv = errno;
- if (ferror (f))
- return _get_contents_error (error, errsv, "error during fread");
-
- if ( n_have > G_MAXSIZE - 1 - n_read
- || n_have + n_read + 1 > max_length) {
- return _get_contents_error (error, EMSGSIZE, "file stream too large (%zu+1 bytes with maximum %zu bytes)",
- (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read,
- max_length);
- }
-
- if (n_have + n_read + 1 >= n_alloc) {
- char *tmp;
-
- if (str) {
- if (n_alloc >= max_length / 2)
- n_alloc = max_length;
- else
- n_alloc *= 2;
- } else
- n_alloc = NM_MIN (n_read + 1, sizeof (buf));
-
- tmp = g_try_realloc (str, n_alloc);
- if (!tmp)
- return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu bytes", n_alloc);
- str = tmp;
- }
-
- memcpy (str + n_have, buf, n_read);
- n_have += n_read;
- }
-
- if (n_alloc == 0)
- str = g_new0 (char, 1);
- else {
- str[n_have] = '\0';
- if (n_have + 1 < n_alloc) {
- char *tmp;
-
- tmp = g_try_realloc (str, n_have + 1);
- if (!tmp)
- return _get_contents_error (error, ENOMEM, "failure to truncate buffer to %zu bytes", n_have + 1);
- str = tmp;
- }
- }
-
- NM_SET_OUT (length, n_have);
- }
-
- *contents = g_steal_pointer (&str);
- return 0;
-}
-
-/**
- * nm_utils_file_get_contents:
- * @dirfd: optional file descriptor to use openat(). If negative, use plain open().
- * @filename: the filename to open. Possibly relative to @dirfd.
- * @max_length: allocate at most @max_length bytes.
- * WARNING: see nm_utils_fd_get_contents() hint about @max_length.
- * @contents: the output buffer with the file read. It is always
- * NUL terminated. The buffer is at most @max_length long, including
- * the NUL byte. That is, it reads only files up to a length of
- * @max_length - 1 bytes.
- * @length: optional output argument of the read file size.
- *
- * A reimplementation of g_file_get_contents() with a few differences:
- * - accepts an @dirfd to open @filename relative to that path via openat().
- * - limits the maxium filesize to max_length.
- * - uses O_CLOEXEC on internal file descriptor
- *
- * Returns: a negative error code on failure.
- */
-int
-nm_utils_file_get_contents (int dirfd,
- const char *filename,
- gsize max_length,
- char **contents,
- gsize *length,
- GError **error)
-{
- int fd;
- int errsv;
-
- g_return_val_if_fail (filename && filename[0], -EINVAL);
-
- if (dirfd >= 0) {
- fd = openat (dirfd, filename, O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- errsv = errno;
-
- g_set_error (error,
- G_FILE_ERROR,
- g_file_error_from_errno (errsv),
- "Failed to open file \"%s\" with openat: %s",
- filename,
- g_strerror (errsv));
- return -errsv;
- }
- } else {
- fd = open (filename, O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- errsv = errno;
-
- g_set_error (error,
- G_FILE_ERROR,
- g_file_error_from_errno (errsv),
- "Failed to open file \"%s\": %s",
- filename,
- g_strerror (errsv));
- return -errsv;
- }
- }
- return nm_utils_fd_get_contents (fd,
- TRUE,
- max_length,
- contents,
- length,
- error);
-}
-
-/*****************************************************************************/
-
static gboolean
_secret_key_read (guint8 **out_secret_key,
gsize *out_key_len)
@@ -2942,6 +2687,7 @@ nm_utils_get_boot_id (void)
gs_free char *contents = NULL;
nm_utils_file_get_contents (-1, "/proc/sys/kernel/random/boot_id", 0,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
&contents, NULL, NULL);
if (contents) {
g_strstrip (contents);
@@ -3987,110 +3733,6 @@ nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GP
#undef N_SHIFT
}
-/**
- * Copied from GLib's g_file_set_contents() et al., but allows
- * specifying a mode for the new file.
- */
-gboolean
-nm_utils_file_set_contents (const char *filename,
- const char *contents,
- gssize length,
- mode_t mode,
- GError **error)
-{
- gs_free char *tmp_name = NULL;
- struct stat statbuf;
- int errsv;
- gssize s;
- int fd;
-
- g_return_val_if_fail (filename, FALSE);
- g_return_val_if_fail (contents || !length, FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
- g_return_val_if_fail (length >= -1, FALSE);
-
- if (length == -1)
- length = strlen (contents);
-
- tmp_name = g_strdup_printf ("%s.XXXXXX", filename);
- fd = g_mkstemp_full (tmp_name, O_RDWR, mode);
- if (fd < 0) {
- errsv = errno;
- g_set_error (error,
- G_FILE_ERROR,
- g_file_error_from_errno (errsv),
- "failed to create file %s: %s",
- tmp_name,
- g_strerror (errsv));
- return FALSE;
- }
-
- while (length > 0) {
- s = write (fd, contents, length);
- if (s < 0) {
- errsv = errno;
- if (errsv == EINTR)
- continue;
-
- nm_close (fd);
- unlink (tmp_name);
-
- g_set_error (error,
- G_FILE_ERROR,
- g_file_error_from_errno (errsv),
- "failed to write to file %s: %s",
- tmp_name,
- g_strerror (errsv));
- return FALSE;
- }
-
- g_assert (s <= length);
-
- contents += s;
- length -= s;
- }
-
- /* If the final destination exists and is > 0 bytes, we want to sync the
- * newly written file to ensure the data is on disk when we rename over
- * the destination. Otherwise if we get a system crash we can lose both
- * the new and the old file on some filesystems. (I.E. those that don't
- * guarantee the data is written to the disk before the metadata.)
- */
- if ( lstat (filename, &statbuf) == 0
- && statbuf.st_size > 0
- && fsync (fd) != 0) {
- errsv = errno;
-
- nm_close (fd);
- unlink (tmp_name);
-
- g_set_error (error,
- G_FILE_ERROR,
- g_file_error_from_errno (errsv),
- "failed to fsync %s: %s",
- tmp_name,
- g_strerror (errsv));
- return FALSE;
- }
-
- nm_close (fd);
-
- if (rename (tmp_name, filename)) {
- errsv = errno;
- unlink (tmp_name);
- g_set_error (error,
- G_FILE_ERROR,
- g_file_error_from_errno (errsv),
- "failed to rename %s to %s: %s",
- tmp_name,
- filename,
- g_strerror (errsv));
- return FALSE;
- }
-
- return TRUE;
-}
-
struct plugin_info {
char *path;
struct stat st;
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index 53c72e16f9..30d1360a1e 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -264,26 +264,6 @@ gboolean nm_utils_sysctl_ip_conf_is_path (int addr_family, const char *path, con
gboolean nm_utils_is_specific_hostname (const char *name);
-int nm_utils_fd_get_contents (int fd,
- gboolean close_fd,
- gsize max_length,
- char **contents,
- gsize *length,
- GError **error);
-
-int nm_utils_file_get_contents (int dirfd,
- const char *filename,
- gsize max_length,
- char **contents,
- gsize *length,
- GError **error);
-
-gboolean nm_utils_file_set_contents (const char *filename,
- const char *contents,
- gssize length,
- mode_t mode,
- GError **error);
-
char *nm_utils_machine_id_read (void);
gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_uuid);
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 9ff976a259..a8a649c7b4 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -54,6 +54,7 @@
#include "wifi/nm-wifi-utils-wext.h"
#include "wpan/nm-wpan-utils.h"
#include "nm-utils/unaligned.h"
+#include "nm-utils/nm-io-utils.h"
#include "nm-utils/nm-udev-utils.h"
/*****************************************************************************/
@@ -853,7 +854,9 @@ _linktype_read_devtype (int dirfd)
nm_assert (dirfd >= 0);
- if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024, &contents, NULL, NULL) < 0)
+ if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+ &contents, NULL, NULL) < 0)
return NULL;
for (cont = contents; cont; cont = end) {
end = strpbrk (cont, "\r\n");
@@ -3515,7 +3518,9 @@ _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, c
char *contents;
gs_free char *value_escaped = g_strescape (value, NULL);
- if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) {
+ if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+ &contents, NULL, &error) < 0) {
_LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message);
g_clear_error (&error);
return;
@@ -3732,7 +3737,9 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
pathid = path;
}
- if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) {
+ if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+ &contents, NULL, &error) < 0) {
/* We assume FAILED means EOPNOTSUP */
if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)
|| g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV)
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 20b3374b28..057490c406 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <linux/if_tun.h>
+#include "nm-utils/nm-io-utils.h"
#include "platform/nmp-object.h"
#include "platform/nmp-netns.h"
#include "platform/nm-platform-utils.h"
@@ -2622,7 +2623,9 @@ test_sysctl_rename (void)
case 0: {
gs_free char *c = NULL;
- if (nm_utils_file_get_contents (dirfd, "ifindex", 1*1024*1024, &c, NULL, NULL) < 0)
+ if (nm_utils_file_get_contents (dirfd, "ifindex", 1*1024*1024,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+ &c, NULL, NULL) < 0)
g_assert_not_reached();
g_assert_cmpint (ifindex[0], ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1));
break;
@@ -2686,7 +2689,9 @@ test_sysctl_netns_switch (void)
{
gs_free char *c = NULL;
- if (nm_utils_file_get_contents (dirfd, "ifindex", 0, &c, NULL, NULL) < 0)
+ if (nm_utils_file_get_contents (dirfd, "ifindex", 0,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+ &c, NULL, NULL) < 0)
g_assert_not_reached();
g_assert_cmpint (ifindex, ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1));
}
@@ -2698,7 +2703,11 @@ test_sysctl_netns_switch (void)
{
gs_free char *c = NULL;
- if (nm_utils_file_get_contents (-1, nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME), 0, &c, NULL, NULL) < 0)
+ if (nm_utils_file_get_contents (-1,
+ nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME),
+ 0,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+ &c, NULL, NULL) < 0)
ifindex_tmp = -1;
else
ifindex_tmp = _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -2);
diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build
index 00892c22f4..5d9689a52c 100644
--- a/src/settings/plugins/ifcfg-rh/meson.build
+++ b/src/settings/plugins/ifcfg-rh/meson.build
@@ -27,7 +27,6 @@ sources = files(
)
deps = [
- crypto_dep,
nm_dep
]
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index 4d2a16bc84..2f38e16887 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -33,6 +33,7 @@
#include <sys/ioctl.h>
#include <unistd.h>
+#include "nm-utils/nm-secret-utils.h"
#include "nm-connection.h"
#include "nm-dbus-interface.h"
#include "nm-setting-connection.h"
@@ -79,6 +80,210 @@
/*****************************************************************************/
+static char *
+get_full_file_path (const char *ifcfg_path, const char *file_path)
+{
+ const char *base = file_path;
+ char *p, *ret, *dirname;
+
+ g_return_val_if_fail (ifcfg_path != NULL, NULL);
+ g_return_val_if_fail (file_path != NULL, NULL);
+
+ if (file_path[0] == '/')
+ return g_strdup (file_path);
+
+ p = strrchr (file_path, '/');
+ if (p)
+ base = p + 1;
+
+ dirname = g_path_get_dirname (ifcfg_path);
+ ret = g_build_path ("/", dirname, base, NULL);
+ g_free (dirname);
+ return ret;
+}
+
+/*****************************************************************************/
+
+static NMSettingSecretFlags
+_secret_read_ifcfg_flags (shvarFile *ifcfg, const char *flags_key)
+{
+ NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
+ gs_free char *val_free = NULL;
+ const char *val;
+
+ nm_assert (flags_key);
+ nm_assert (g_str_has_suffix (flags_key, "_FLAGS"));
+
+ val = svGetValueStr (ifcfg, flags_key, &val_free);
+ if (val) {
+ if (strstr (val, SECRET_FLAG_AGENT))
+ flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
+ if (strstr (val, SECRET_FLAG_NOT_SAVED))
+ flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED;
+ if (strstr (val, SECRET_FLAG_NOT_REQUIRED))
+ flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED;
+ }
+ return flags;
+}
+
+static void
+_secret_read_ifcfg (shvarFile *ifcfg,
+ shvarFile *keys_ifcfg,
+ const char *name,
+ char **value,
+ NMSettingSecretFlags *flags)
+{
+ char flags_key[250];
+
+ nm_sprintf_buf (flags_key, "%s_FLAGS", name);
+
+ *flags = _secret_read_ifcfg_flags (ifcfg, flags_key);
+
+ if (*flags != NM_SETTING_SECRET_FLAG_NONE)
+ *value = NULL;
+ else {
+ *value = svGetValue_cp (ifcfg, name);
+ if (!*value && keys_ifcfg)
+ *value = svGetValue_cp (keys_ifcfg, name);
+ }
+}
+
+static void
+_secret_set_from_ifcfg (gpointer setting,
+ shvarFile *ifcfg,
+ shvarFile *keys_ifcfg,
+ const char *ifcfg_key,
+ const char *property_name)
+{
+ nm_auto_free_secret char *secret = NULL;
+ NMSettingSecretFlags flags;
+ char flags_key[250];
+
+ nm_assert (NM_IS_SETTING (setting));
+
+ _secret_read_ifcfg (ifcfg, keys_ifcfg, ifcfg_key, &secret, &flags);
+
+ g_object_set (setting,
+ property_name,
+ secret,
+ nm_sprintf_buf (flags_key, "%s-flags", property_name),
+ flags,
+ NULL);
+}
+
+static gboolean
+_secret_password_raw_to_bytes (const char *ifcfg_key,
+ const char *password_raw,
+ GBytes **out_bytes,
+ GError **error)
+{
+ nm_auto_free_secret_buf NMSecretBuf *secret = NULL;
+ gsize len;
+
+ if (!password_raw) {
+ NM_SET_OUT (out_bytes, NULL);
+ return TRUE;
+ }
+
+ if (password_raw[0] == '0' && password_raw[1] == 'x')
+ password_raw += 2;
+
+ secret = nm_secret_buf_new (strlen (password_raw) / 2 + 3);
+ if (!_nm_utils_str2bin_full (password_raw, FALSE, ":", secret->bin, secret->len, &len)) {
+ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+ "Invalid hex password in %s",
+ ifcfg_key);
+ return FALSE;
+ }
+
+ NM_SET_OUT (out_bytes, nm_secret_buf_to_gbytes_take (g_steal_pointer (&secret), len));
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static GBytes *
+_cert_get_cert_bytes (const char *ifcfg_path,
+ const char *value,
+ GError **error)
+{
+ gs_free char *path = NULL;
+
+ if (g_str_has_prefix (value, "pkcs11:"))
+ return _nm_setting_802_1x_cert_value_to_bytes (NM_SETTING_802_1X_CK_SCHEME_PKCS11, (guint8 *) value, -1, error);
+
+ path = get_full_file_path (ifcfg_path, value);
+ return _nm_setting_802_1x_cert_value_to_bytes (NM_SETTING_802_1X_CK_SCHEME_PATH, (guint8 *) path, -1, error);
+}
+
+static gboolean
+_cert_get_cert (shvarFile *ifcfg,
+ const char *ifcfg_key,
+ GBytes **out_cert,
+ NMSetting8021xCKScheme *out_scheme,
+ GError **error)
+{
+ nm_auto_free_secret char *val_free = NULL;
+ const char *val;
+ gs_unref_bytes GBytes *cert = NULL;
+ GError *local = NULL;
+ NMSetting8021xCKScheme scheme;
+
+ val = svGetValueStr (ifcfg, ifcfg_key, &val_free);
+ if (!val) {
+ NM_SET_OUT (out_cert, NULL);
+ NM_SET_OUT (out_scheme, NM_SETTING_802_1X_CK_SCHEME_UNKNOWN);
+ return TRUE;
+ }
+
+ cert = _cert_get_cert_bytes (svFileGetName (ifcfg), val, &local);
+ if (!cert)
+ goto err;
+
+ scheme = _nm_setting_802_1x_cert_get_scheme (cert, &local);
+ if (scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN)
+ goto err;
+
+ NM_SET_OUT (out_cert, g_steal_pointer (&cert));
+ NM_SET_OUT (out_scheme, scheme);
+ return TRUE;
+
+err:
+ g_set_error (error,
+ NM_SETTINGS_ERROR,
+ NM_SETTINGS_ERROR_INVALID_CONNECTION,
+ "invalid certificate %s: %s",
+ ifcfg_key,
+ local->message);
+ g_error_free (local);
+ return FALSE;
+}
+
+static gboolean
+_cert_set_from_ifcfg (gpointer setting,
+ shvarFile *ifcfg,
+ const char *ifcfg_key,
+ const char *property_name,
+ GBytes **out_cert,
+ GError **error)
+{
+ gs_unref_bytes GBytes *cert = NULL;
+
+ if (!_cert_get_cert (ifcfg,
+ ifcfg_key,
+ &cert,
+ NULL,
+ error))
+ return FALSE;
+
+ g_object_set (setting, property_name, cert, NULL);
+
+ NM_SET_OUT (out_cert, g_steal_pointer (&cert));
+ return TRUE;
+}
+
+/*****************************************************************************/
+
static void
check_if_bond_slave (shvarFile *ifcfg,
NMSettingConnection *s_con)
@@ -2608,30 +2813,6 @@ read_wep_keys (shvarFile *ifcfg,
return TRUE;
}
-static NMSettingSecretFlags
-read_secret_flags (shvarFile *ifcfg, const char *flags_key)
-{
- NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
- char *val;
-
- g_return_val_if_fail (flags_key != NULL, NM_SETTING_SECRET_FLAG_NONE);
- g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE);
- g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE);
-
- val = svGetValueStr_cp (ifcfg, flags_key);
- if (val) {
- if (strstr (val, SECRET_FLAG_AGENT))
- flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
- if (strstr (val, SECRET_FLAG_NOT_SAVED))
- flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED;
- if (strstr (val, SECRET_FLAG_NOT_REQUIRED))
- flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED;
-
- g_free (val);
- }
- return flags;
-}
-
static NMSetting *
make_wep_setting (shvarFile *ifcfg,
const char *file,
@@ -2663,7 +2844,7 @@ make_wep_setting (shvarFile *ifcfg,
}
/* Read WEP key flags */
- key_flags = read_secret_flags (ifcfg, "WEP_KEY_FLAGS");
+ key_flags = _secret_read_ifcfg_flags (ifcfg, "WEP_KEY_FLAGS");
g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, key_flags, NULL);
/* Read keys in the ifcfg file if they are system-owned */
@@ -2862,254 +3043,118 @@ parse_wpa_psk (shvarFile *ifcfg,
return g_steal_pointer (&psk);
}
-static void
-read_8021x_password (shvarFile *ifcfg, shvarFile *keys_ifcfg, const char *name,
- char **value, NMSettingSecretFlags *flags)
-{
- gs_free char *flags_key = NULL;
-
- *value = NULL;
- flags_key = g_strdup_printf ("%s_FLAGS", name);
- *flags = read_secret_flags (ifcfg, flags_key);
-
- if (*flags == NM_SETTING_SECRET_FLAG_NONE) {
- *value = svGetValueStr_cp (ifcfg, name);
- if (!*value && keys_ifcfg)
- *value = svGetValueStr_cp (keys_ifcfg, name);
- }
-}
-
static gboolean
eap_simple_reader (const char *eap_method,
shvarFile *ifcfg,
- shvarFile *keys,
+ shvarFile *keys_ifcfg,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
{
NMSettingSecretFlags flags;
- GBytes *bytes;
- char *value;
+ gs_free char *identity_free = NULL;
+ nm_auto_free_secret char *password_raw_str = NULL;
+ gs_unref_bytes GBytes *password_raw_bytes = NULL;
- value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY");
- if (!value) {
- g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
- "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
- eap_method);
- return FALSE;
- }
- g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
- nm_clear_g_free (&value);
+ g_object_set (s_8021x,
+ NM_SETTING_802_1X_IDENTITY,
+ svGetValueStr (ifcfg, "IEEE_8021X_IDENTITY", &identity_free),
+ NULL);
- read_8021x_password (ifcfg, keys, "IEEE_8021X_PASSWORD", &value, &flags);
- g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_FLAGS, flags, NULL);
- if (value) {
- g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
- nm_clear_g_free (&value);
- }
+ _secret_set_from_ifcfg (s_8021x,
+ ifcfg,
+ keys_ifcfg,
+ "IEEE_8021X_PASSWORD",
+ NM_SETTING_802_1X_PASSWORD);
+
+ _secret_read_ifcfg (ifcfg, keys_ifcfg, "IEEE_8021X_PASSWORD_RAW", &password_raw_str, &flags);
+ if (!_secret_password_raw_to_bytes ("IEEE_8021X_PASSWORD_RAW",
+ password_raw_str,
+ &password_raw_bytes,
+ error))
+ return FALSE;
- read_8021x_password (ifcfg, keys, "IEEE_8021X_PASSWORD_RAW", &value, &flags);
- g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_RAW_FLAGS, flags, NULL);
- if (value) {
- bytes = nm_utils_hexstr2bin (value);
- if (!bytes) {
- g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
- "Invalid hex string '%s' in IEEE_8021X_PASSWORD_RAW.",
- value);
- g_free (value);
- return FALSE;
- }
- g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_RAW, bytes, NULL);
- g_bytes_unref (bytes);
- nm_clear_g_free (&value);
- }
+ g_object_set (s_8021x,
+ NM_SETTING_802_1X_PASSWORD_RAW_FLAGS,
+ flags,
+ NM_SETTING_802_1X_PASSWORD_RAW,
+ password_raw_bytes,
+ NULL);
return TRUE;
}
-static char *
-get_full_file_path (const char *ifcfg_path, const char *file_path)
-{
- const char *base = file_path;
- char *p, *ret, *dirname;
-
- g_return_val_if_fail (ifcfg_path != NULL, NULL);
- g_return_val_if_fail (file_path != NULL, NULL);
-
- if (file_path[0] == '/')
- return g_strdup (file_path);
-
- p = strrchr (file_path, '/');
- if (p)
- base = p + 1;
-
- dirname = g_path_get_dirname (ifcfg_path);
- ret = g_build_path ("/", dirname, base, NULL);
- g_free (dirname);
- return ret;
-}
-
-static char *
-get_cert_value (const char *ifcfg_path, const char *value,
- NMSetting8021xCKScheme *out_scheme)
-{
- if (strncmp (value, "pkcs11:", 7) == 0) {
- *out_scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11;
- return g_strdup (value);
- }
-
- *out_scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
- return get_full_file_path (ifcfg_path, value);
-}
-
static gboolean
eap_tls_reader (const char *eap_method,
shvarFile *ifcfg,
- shvarFile *keys,
+ shvarFile *keys_ifcfg,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
{
- gs_free char *ca_cert = NULL;
- gs_free char *privkey = NULL;
- gs_free char *privkey_password = NULL;
- char *value;
- char *ca_cert_password = NULL;
- char *client_cert_password = NULL;
- NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
- const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT";
- const char *ca_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD" : "IEEE_8021X_CA_CERT_PASSWORD";
- const char *ca_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD : NM_SETTING_802_1X_CA_CERT_PASSWORD;
- const char *ca_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CA_CERT_PASSWORD_FLAGS";
- const char *ca_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS;
- const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT";
- const char *cli_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD" : "IEEE_8021X_CLIENT_CERT_PASSWORD";
- const char *cli_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD;
- const char *cli_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CLIENT_CERT_PASSWORD_FLAGS";
- const char *cli_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS;
- const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY";
- const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD";
- const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS" : "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS";
- const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS;
- NMSettingSecretFlags flags;
- NMSetting8021xCKScheme scheme;
+ gs_unref_bytes GBytes *privkey = NULL;
+ gs_unref_bytes GBytes *client_cert = NULL;
+ gs_free char *identity_free = NULL;
- value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY");
- if (value) {
- g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
- g_free (value);
- }
-
- ca_cert = svGetValueStr_cp (ifcfg, ca_cert_key);
- if (ca_cert) {
- gs_free char *real_cert_value = NULL;
-
- real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme);
- if (phase2) {
- if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
- return FALSE;
- } else {
- if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
- return FALSE;
- }
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- flags = read_secret_flags (ifcfg, ca_cert_pw_flags_key);
- g_object_set (s_8021x, ca_cert_pw_flags_prop, flags, NULL);
-
- if (flags == NM_SETTING_SECRET_FLAG_NONE) {
- ca_cert_password = svGetValueStr_cp (ifcfg, ca_cert_pw_key);
- g_object_set (s_8021x, ca_cert_pw_prop, ca_cert_password, NULL);
- }
- }
- } else {
- PARSE_WARNING ("missing %s for EAP method '%s'; this is insecure!",
- ca_cert_key, eap_method);
- }
-
- /* Read and set private key password flags */
- flags = read_secret_flags (ifcfg, pk_pw_flags_key);
- g_object_set (s_8021x, pk_pw_flags_prop, flags, NULL);
-
- /* Read the private key password if it's system-owned */
- if (flags == NM_SETTING_SECRET_FLAG_NONE) {
- /* Private key password */
- privkey_password = svGetValueStr_cp (ifcfg, pk_pw_key);
- if (!privkey_password && keys) {
- /* Try the lookaside keys file */
- privkey_password = svGetValueStr_cp (keys, pk_pw_key);
- }
- }
+ g_object_set (s_8021x,
+ NM_SETTING_802_1X_IDENTITY,
+ svGetValueStr (ifcfg, "IEEE_8021X_IDENTITY", &identity_free),
+ NULL);
- /* The private key itself */
- privkey = svGetValueStr_cp (ifcfg, pk_key);
+ if (!_cert_set_from_ifcfg (s_8021x,
+ ifcfg,
+ phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT",
+ phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT : NM_SETTING_802_1X_CA_CERT,
+ NULL,
+ error))
+ return FALSE;
+ _secret_set_from_ifcfg (s_8021x,
+ ifcfg,
+ keys_ifcfg,
+ phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD" : "IEEE_8021X_CA_CERT_PASSWORD",
+ phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD : NM_SETTING_802_1X_CA_CERT_PASSWORD);
+
+ if (!_cert_set_from_ifcfg (s_8021x,
+ ifcfg,
+ phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY",
+ phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY : NM_SETTING_802_1X_PRIVATE_KEY,
+ &privkey,
+ error))
+ return FALSE;
+ _secret_set_from_ifcfg (s_8021x,
+ ifcfg,
+ keys_ifcfg,
+ phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD" : "IEEE_8021X_PRIVATE_KEY_PASSWORD",
+ phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD);
if (!privkey) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing %s for EAP method '%s'.",
- pk_key,
+ phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY",
eap_method);
return FALSE;
}
- {
- gs_free char *real_cert_value = NULL;
-
- real_cert_value = get_cert_value (svFileGetName (ifcfg), privkey, &scheme);
- if (phase2) {
- if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
- real_cert_value,
- privkey_password,
- scheme,
- &privkey_format,
- error))
- return FALSE;
- } else {
- if (!nm_setting_802_1x_set_private_key (s_8021x,
- real_cert_value,
- privkey_password,
- scheme,
- &privkey_format,
- error))
- return FALSE;
- }
- }
-
- /* Only set the client certificate if the private key is not PKCS#12 format,
- * as NM (due to supplicant restrictions) requires. If the key was PKCS#12,
- * then nm_setting_802_1x_set_private_key() already set the client certificate
- * to the same value as the private key.
- */
- if (privkey_format != NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
- gs_free char *real_cert_value = NULL;
- gs_free char *client_cert = NULL;
-
- client_cert = svGetValueStr_cp (ifcfg, cli_cert_key);
- if (!client_cert) {
- g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
- "Missing %s for EAP method '%s'.",
- cli_cert_key,
- eap_method);
- return FALSE;
- }
-
- real_cert_value = get_cert_value (svFileGetName (ifcfg), client_cert, &scheme);
- if (phase2) {
- if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, real_cert_value, scheme, NULL, error))
- return FALSE;
- } else {
- if (!nm_setting_802_1x_set_client_cert (s_8021x, real_cert_value, scheme, NULL, error))
- return FALSE;
- }
-
- if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
- flags = read_secret_flags (ifcfg, cli_cert_pw_flags_key);
- g_object_set (s_8021x, cli_cert_pw_flags_prop, flags, NULL);
-
- if (flags == NM_SETTING_SECRET_FLAG_NONE) {
- client_cert_password = svGetValueStr_cp (ifcfg, cli_cert_pw_key);
- g_object_set (s_8021x, cli_cert_pw_prop, client_cert_password, NULL);
- }
- }
+ if (!_cert_set_from_ifcfg (s_8021x,
+ ifcfg,
+ phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT",
+ phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT : NM_SETTING_802_1X_CLIENT_CERT,
+ &client_cert,
+ error))
+ return FALSE;
+ /* FIXME: writer does not actually write IEEE_8021X_CLIENT_CERT_PASSWORD and other
+ * certificate related passwords. It should, because otherwise persisting such profiles
+ * to ifcfg looses information. As this currently only matters for PKCS11 URIs, it seems
+ * a seldomly used feature so that it is not fixed yet. */
+ _secret_set_from_ifcfg (s_8021x,
+ ifcfg,
+ keys_ifcfg,
+ phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD" : "IEEE_8021X_CLIENT_CERT_PASSWORD",
+ phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD);
+ if (!client_cert) {
+ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+ "Missing certificate for EAP method '%s'.",
+ eap_method);
+ return FALSE;
}
return TRUE;
@@ -3118,7 +3163,7 @@ eap_tls_reader (const char *eap_method,
static gboolean
eap_peap_reader (const char *eap_method,
shvarFile *ifcfg,
- shvarFile *keys,
+ shvarFile *keys_ifcfg,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
@@ -3127,19 +3172,19 @@ eap_peap_reader (const char *eap_method,
const char *v;
gs_free const char **list = NULL;
const char *const *iter;
- NMSetting8021xCKScheme scheme;
-
- v = svGetValueStr (ifcfg, "IEEE_8021X_CA_CERT", &value);
- if (v) {
- gs_free char *real_cert_value = NULL;
- real_cert_value = get_cert_value (svFileGetName (ifcfg), v, &scheme);
- if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
- return FALSE;
- } else {
- PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
- eap_method);
- }
+ if (!_cert_set_from_ifcfg (s_8021x,
+ ifcfg,
+ "IEEE_8021X_CA_CERT",
+ NM_SETTING_802_1X_CA_CERT,
+ NULL,
+ error))
+ return FALSE;
+ _secret_set_from_ifcfg (s_8021x,
+ ifcfg,
+ keys_ifcfg,
+ "IEEE_8021X_CA_CERT_PASSWORD",
+ NM_SETTING_802_1X_CA_CERT_PASSWORD);
nm_clear_g_free (&value);
v = svGetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", &value);
@@ -3179,10 +3224,10 @@ eap_peap_reader (const char *eap_method,
if (NM_IN_STRSET (*iter, "MSCHAPV2",
"MD5",
"GTC")) {
- if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
} else if (nm_streq (*iter, "TLS")) {
- if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+ if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -3211,7 +3256,7 @@ eap_peap_reader (const char *eap_method,
static gboolean
eap_ttls_reader (const char *eap_method,
shvarFile *ifcfg,
- shvarFile *keys,
+ shvarFile *keys_ifcfg,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
@@ -3221,19 +3266,19 @@ eap_ttls_reader (const char *eap_method,
const char *v;
gs_free const char **list = NULL;
const char *const *iter;
- NMSetting8021xCKScheme scheme;
- v = svGetValueStr (ifcfg, "IEEE_8021X_CA_CERT", &value);
- if (v) {
- gs_free char *real_cert_value = NULL;
-
- real_cert_value = get_cert_value (svFileGetName (ifcfg), v, &scheme);
- if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error))
- return FALSE;
- } else {
- PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
- eap_method);
- }
+ if (!_cert_set_from_ifcfg (s_8021x,
+ ifcfg,
+ "IEEE_8021X_CA_CERT",
+ NM_SETTING_802_1X_CA_CERT,
+ NULL,
+ error))
+ return FALSE;
+ _secret_set_from_ifcfg (s_8021x,
+ ifcfg,
+ keys_ifcfg,
+ "IEEE_8021X_CA_CERT_PASSWORD",
+ NM_SETTING_802_1X_CA_CERT_PASSWORD);
nm_clear_g_free (&value);
v = svGetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY", &value);
@@ -3258,17 +3303,17 @@ eap_ttls_reader (const char *eap_method,
"mschap",
"pap",
"chap")) {
- if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
} else if (nm_streq (*iter, "eap-tls")) {
- if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+ if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
} else if (NM_IN_STRSET (*iter, "eap-mschapv2",
"eap-md5",
"eap-gtc")) {
- if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL);
} else {
@@ -3285,7 +3330,7 @@ eap_ttls_reader (const char *eap_method,
static gboolean
eap_fast_reader (const char *eap_method,
shvarFile *ifcfg,
- shvarFile *keys,
+ shvarFile *keys_ifcfg,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error)
@@ -3351,7 +3396,7 @@ eap_fast_reader (const char *eap_method,
if (iter) {
if ( !strcmp (*iter, "MSCHAPV2")
|| !strcmp (*iter, "GTC")) {
- if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
goto done;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -3386,7 +3431,7 @@ typedef struct {
const char *method;
gboolean (*reader) (const char *eap_method,
shvarFile *ifcfg,
- shvarFile *keys,
+ shvarFile *keys_ifcfg,
NMSetting8021x *s_8021x,
gboolean phase2,
GError **error);
@@ -3438,7 +3483,7 @@ fill_8021x (shvarFile *ifcfg,
gboolean wifi,
GError **error)
{
- nm_auto_shvar_file_close shvarFile *keys = NULL;
+ nm_auto_shvar_file_close shvarFile *keys_ifcfg = NULL;
gs_unref_object NMSetting8021x *s_8021x = NULL;
gs_free char *value = NULL;
const char *v;
@@ -3459,8 +3504,8 @@ fill_8021x (shvarFile *ifcfg,
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
- /* Read in the lookaside keys file, if present */
- keys = utils_get_keys_ifcfg (file, FALSE);
+ /* Read in the lookaside keys_ifcfg file, if present */
+ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
/* Validate and handle each EAP method */
for (iter = list; iter && *iter; iter++) {
@@ -3484,7 +3529,7 @@ fill_8021x (shvarFile *ifcfg,
}
/* Parse EAP method specific options */
- if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error))
+ if (!(*eap->reader)(lower, ifcfg, keys_ifcfg, s_8021x, FALSE, error))
return NULL;
nm_setting_802_1x_add_eap_method (s_8021x, lower);
@@ -3600,7 +3645,7 @@ make_wpa_setting (shvarFile *ifcfg,
if (wpa_psk) {
NMSettingSecretFlags psk_flags;
- psk_flags = read_secret_flags (ifcfg, "WPA_PSK_FLAGS");
+ psk_flags = _secret_read_ifcfg_flags (ifcfg, "WPA_PSK_FLAGS");
g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, psk_flags, NULL);
/* Read PSK if it's system-owned */
@@ -3687,7 +3732,7 @@ make_leap_setting (shvarFile *ifcfg,
return NULL; /* Not LEAP */
nm_clear_g_free (&value);
- flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
+ flags = _secret_read_ifcfg_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, flags, NULL);
/* Read LEAP password if it's system-owned */
@@ -5459,7 +5504,7 @@ connection_from_file_full (const char *filename,
GError **error,
gboolean *out_ignore_error)
{
- nm_auto_shvar_file_close shvarFile *parsed = NULL;
+ nm_auto_shvar_file_close shvarFile *main_ifcfg = NULL;
nm_auto_shvar_file_close shvarFile *network_ifcfg = NULL;
gs_unref_object NMConnection *connection = NULL;
gs_free char *type = NULL;
@@ -5487,14 +5532,14 @@ connection_from_file_full (const char *filename,
return NULL;
}
- parsed = svOpenFile (filename, error);
- if (!parsed)
+ main_ifcfg = svOpenFile (filename, error);
+ if (!main_ifcfg)
return NULL;
network_ifcfg = svOpenFile (network_file, NULL);
- if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) {
- connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled);
+ if (!svGetValueBoolean (main_ifcfg, "NM_CONTROLLED", TRUE)) {
+ connection = create_unhandled_connection (filename, main_ifcfg, "unmanaged", out_unhandled);
if (!connection) {
NM_SET_OUT (out_ignore_error, TRUE);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
@@ -5504,7 +5549,7 @@ connection_from_file_full (const char *filename,
}
/* iBFT is handled by the iBFT settings plugin */
- bootproto = svGetValueStr_cp (parsed, "BOOTPROTO");
+ bootproto = svGetValueStr_cp (main_ifcfg, "BOOTPROTO");
if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) {
NM_SET_OUT (out_ignore_error, TRUE);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -5514,19 +5559,19 @@ connection_from_file_full (const char *filename,
}
g_free (bootproto);
- devtype = svGetValueStr_cp (parsed, "DEVICETYPE");
+ devtype = svGetValueStr_cp (main_ifcfg, "DEVICETYPE");
if (devtype) {
if (!strcasecmp (devtype, TYPE_TEAM))
type = g_strdup (TYPE_TEAM);
else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) {
gs_free char *device = NULL;
- type = svGetValueStr_cp (parsed, "TYPE");
- device = svGetValueStr_cp (parsed, "DEVICE");
+ type = svGetValueStr_cp (main_ifcfg, "TYPE");
+ device = svGetValueStr_cp (main_ifcfg, "DEVICE");
if (type) {
/* nothing to do */
- } else if (device && is_vlan_device (device, parsed))
+ } else if (device && is_vlan_device (device, main_ifcfg))
type = g_strdup (TYPE_VLAN);
else
type = g_strdup (TYPE_ETHERNET);
@@ -5539,26 +5584,26 @@ connection_from_file_full (const char *filename,
/* Team and TeamPort types are also accepted by the mere
* presence of TEAM_CONFIG/TEAM_MASTER. They don't require
* DEVICETYPE. */
- t = svGetValueStr_cp (parsed, "TEAM_CONFIG");
+ t = svGetValueStr_cp (main_ifcfg, "TEAM_CONFIG");
if (t)
type = g_strdup (TYPE_TEAM);
}
if (!type)
- type = svGetValueStr_cp (parsed, "TYPE");
+ type = svGetValueStr_cp (main_ifcfg, "TYPE");
if (!type) {
gs_free char *tmp = NULL;
char *device;
- if ((tmp = svGetValueStr_cp (parsed, "IPV6TUNNELIPV4"))) {
+ if ((tmp = svGetValueStr_cp (main_ifcfg, "IPV6TUNNELIPV4"))) {
NM_SET_OUT (out_ignore_error, TRUE);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Ignoring unsupported connection due to IPV6TUNNELIPV4");
return NULL;
}
- device = svGetValueStr_cp (parsed, "DEVICE");
+ device = svGetValueStr_cp (main_ifcfg, "DEVICE");
if (!device) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"File '%s' had neither TYPE nor DEVICE keys.", filename);
@@ -5574,11 +5619,11 @@ connection_from_file_full (const char *filename,
}
if (!test_type) {
- if (is_bond_device (device, parsed))
+ if (is_bond_device (device, main_ifcfg))
type = g_strdup (TYPE_BOND);
- else if (is_vlan_device (device, parsed))
+ else if (is_vlan_device (device, main_ifcfg))
type = g_strdup (TYPE_VLAN);
- else if (is_wifi_device (device, parsed))
+ else if (is_wifi_device (device, main_ifcfg))
type = g_strdup (TYPE_WIRELESS);
else {
gs_free char *p_path = NULL;
@@ -5644,14 +5689,14 @@ connection_from_file_full (const char *filename,
if (nm_streq0 (type, TYPE_ETHERNET)) {
gs_free char *bond_options = NULL;
- if (svGetValueStr (parsed, "BONDING_OPTS", &bond_options)) {
+ if (svGetValueStr (main_ifcfg, "BONDING_OPTS", &bond_options)) {
/* initscripts consider these as bond masters */
g_free (type);
type = g_strdup (TYPE_BOND);
}
}
- if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE) &&
+ if (svGetValueBoolean (main_ifcfg, "BONDING_MASTER", FALSE) &&
strcasecmp (type, TYPE_BOND)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"BONDING_MASTER=yes key only allowed in TYPE=bond connections");
@@ -5660,21 +5705,21 @@ connection_from_file_full (const char *filename,
/* Construct the connection */
if (!strcasecmp (type, TYPE_ETHERNET))
- connection = wired_connection_from_ifcfg (filename, parsed, error);
+ connection = wired_connection_from_ifcfg (filename, main_ifcfg, error);
else if (!strcasecmp (type, TYPE_WIRELESS))
- connection = wireless_connection_from_ifcfg (filename, parsed, error);
+ connection = wireless_connection_from_ifcfg (filename, main_ifcfg, error);
else if (!strcasecmp (type, TYPE_INFINIBAND))
- connection = infiniband_connection_from_ifcfg (filename, parsed, error);
+ connection = infiniband_connection_from_ifcfg (filename, main_ifcfg, error);
else if (!strcasecmp (type, TYPE_BOND))
- connection = bond_connection_from_ifcfg (filename, parsed, error);
+ connection = bond_connection_from_ifcfg (filename, main_ifcfg, error);
else if (!strcasecmp (type, TYPE_TEAM))
- connection = team_connection_from_ifcfg (filename, parsed, error);
+ connection = team_connection_from_ifcfg (filename, main_ifcfg, error);
else if (!strcasecmp (type, TYPE_VLAN))
- connection = vlan_connection_from_ifcfg (filename, parsed, error);
+ connection = vlan_connection_from_ifcfg (filename, main_ifcfg, error);
else if (!strcasecmp (type, TYPE_BRIDGE))
- connection = bridge_connection_from_ifcfg (filename, parsed, error);
+ connection = bridge_connection_from_ifcfg (filename, main_ifcfg, error);
else {
- connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled);
+ connection = create_unhandled_connection (filename, main_ifcfg, "unrecognized", out_unhandled);
if (!connection) {
PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed");
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -5686,7 +5731,7 @@ connection_from_file_full (const char *filename,
if (!connection)
return NULL;
- parse_ethtool_options (parsed, connection);
+ parse_ethtool_options (main_ifcfg, connection);
has_complex_routes_v4 = utils_has_complex_routes (filename, AF_INET);
has_complex_routes_v6 = utils_has_complex_routes (filename, AF_INET6);
@@ -5700,7 +5745,7 @@ connection_from_file_full (const char *filename,
PARSE_WARNING ("'rule-' and 'rule6-' files are present; you will need to use a dispatcher script to apply these routes");
}
- s_ip6 = make_ip6_setting (parsed,
+ s_ip6 = make_ip6_setting (main_ifcfg,
network_ifcfg,
!has_complex_routes_v4 && !has_complex_routes_v6,
error);
@@ -5709,7 +5754,7 @@ connection_from_file_full (const char *filename,
else
nm_connection_add_setting (connection, s_ip6);
- s_ip4 = make_ip4_setting (parsed,
+ s_ip4 = make_ip4_setting (main_ifcfg,
network_ifcfg,
!has_complex_routes_v4 && !has_complex_routes_v6,
&has_ip4_defroute,
@@ -5723,11 +5768,11 @@ connection_from_file_full (const char *filename,
nm_connection_add_setting (connection, s_ip4);
}
- s_sriov = make_sriov_setting (parsed);
+ s_sriov = make_sriov_setting (main_ifcfg);
if (s_sriov)
nm_connection_add_setting (connection, s_sriov);
- s_tc = make_tc_setting (parsed);
+ s_tc = make_tc_setting (main_ifcfg);
if (s_tc)
nm_connection_add_setting (connection, s_tc);
@@ -5735,31 +5780,31 @@ connection_from_file_full (const char *filename,
* config fails for some reason, we read DOMAIN and put the
* values into IPv6 config instead of IPv4.
*/
- check_dns_search_domains (parsed, s_ip4, s_ip6);
+ check_dns_search_domains (main_ifcfg, s_ip4, s_ip6);
- s_proxy = make_proxy_setting (parsed);
+ s_proxy = make_proxy_setting (main_ifcfg);
if (s_proxy)
nm_connection_add_setting (connection, s_proxy);
- s_user = make_user_setting (parsed);
+ s_user = make_user_setting (main_ifcfg);
if (s_user)
nm_connection_add_setting (connection, s_user);
- s_match = make_match_setting (parsed);
+ s_match = make_match_setting (main_ifcfg);
if (s_match)
nm_connection_add_setting (connection, s_match);
/* Bridge port? */
- s_port = make_bridge_port_setting (parsed);
+ s_port = make_bridge_port_setting (main_ifcfg);
if (s_port)
nm_connection_add_setting (connection, s_port);
/* Team port? */
- s_port = make_team_port_setting (parsed);
+ s_port = make_team_port_setting (main_ifcfg);
if (s_port)
nm_connection_add_setting (connection, s_port);
- if (!make_dcb_setting (parsed, &s_dcb, error))
+ if (!make_dcb_setting (main_ifcfg, &s_dcb, error))
return NULL;
if (s_dcb)
nm_connection_add_setting (connection, s_dcb);
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 74e8497578..530feba6ef 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "nm-utils/nm-enum-utils.h"
+#include "nm-utils/nm-io-utils.h"
#include "nm-manager.h"
#include "nm-setting-connection.h"
#include "nm-setting-wired.h"
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index f09bc2472f..fe82fbddae 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -39,6 +39,7 @@
#include "nm-core-internal.h"
#include "nm-core-utils.h"
#include "nm-utils/nm-enum-utils.h"
+#include "nm-utils/nm-io-utils.h"
#include "c-list/src/c-list.h"
/*****************************************************************************/
@@ -821,6 +822,7 @@ svOpenFileInternal (const char *name, gboolean create, GError **error)
if (nm_utils_fd_get_contents (closefd ? nm_steal_fd (&fd) : fd,
closefd,
10 * 1024 * 1024,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
&arena,
NULL,
&local) < 0) {
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index ab31fbe099..7069386103 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -1901,10 +1901,8 @@ test_read_write_802_1X_subj_matches (void)
gs_unref_object NMConnection *reread = NULL;
NMSetting8021x *s_8021x;
- NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT*peap*");
connection = _connection_from_file (TEST_IFCFG_DIR"/ifcfg-test-wired-802-1X-subj-matches",
NULL, TYPE_ETHERNET, NULL);
- g_test_assert_expected_messages ();
/* ===== 802.1x SETTING ===== */
s_8021x = nm_connection_get_setting_802_1x (connection);
@@ -1922,16 +1920,12 @@ test_read_write_802_1X_subj_matches (void)
g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 0), ==, "x.yourdomain.tld");
g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 1), ==, "y.yourdomain.tld");
- NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!");
_writer_new_connec_exp (connection,
TEST_SCRATCH_DIR,
TEST_IFCFG_DIR"/ifcfg-System_test-wired-802-1X-subj-matches.cexpected",
&testfile);
- g_test_assert_expected_messages ();
- NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!");
reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL);
- g_test_assert_expected_messages ();
nmtst_assert_connection_equals (connection, TRUE, reread, FALSE);
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c
index 228f4d4469..1556f15840 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-writer.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c
@@ -34,6 +34,8 @@
#include "nms-keyfile-utils.h"
#include "nms-keyfile-reader.h"
+#include "nm-utils/nm-io-utils.h"
+
/*****************************************************************************/
typedef struct {