2008-05-15 Tambet Ingo <tambet@gmail.com>

Move crypto functions from nm-applet to libnm-util.

	* libnm-util/nm-setting-8021x.c (nm_setting_802_1x_set_ca_cert)
	(nm_setting_802_1x_set_client_cert)
	(nm_setting_802_1x_set_phase2_ca_cert)
	(nm_setting_802_1x_set_phase2_client_cert)
	(nm_setting_802_1x_set_private_key)
	(nm_setting_802_1x_set_phase2_private_key): Implement. Given a certificate
	file (or private key and it's password), read the certificate data.

	* libnm-util/crypto_nss.c:
	* libnm-util/crypto_gnutls.c:
	* libnm-util/crypto.[ch]: Move here from nm-applet.

	* configure.in: Check for NSS and gnutls here (moved here from nm-applet).

	* system-settings/plugins/ifcfg-suse/parser.c (read_wpa_eap_settings):
	Imlement WPA-EAP configuration reading from sysconfig.


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3673 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Tambet Ingo 2008-05-19 07:43:13 +00:00
parent 192fe93b3a
commit 40a69f986c
12 changed files with 1578 additions and 32 deletions

View file

@ -1,3 +1,24 @@
2008-05-15 Tambet Ingo <tambet@gmail.com>
Move crypto functions from nm-applet to libnm-util.
* libnm-util/nm-setting-8021x.c (nm_setting_802_1x_set_ca_cert)
(nm_setting_802_1x_set_client_cert)
(nm_setting_802_1x_set_phase2_ca_cert)
(nm_setting_802_1x_set_phase2_client_cert)
(nm_setting_802_1x_set_private_key)
(nm_setting_802_1x_set_phase2_private_key): Implement. Given a certificate
file (or private key and it's password), read the certificate data.
* libnm-util/crypto_nss.c:
* libnm-util/crypto_gnutls.c:
* libnm-util/crypto.[ch]: Move here from nm-applet.
* configure.in: Check for NSS and gnutls here (moved here from nm-applet).
* system-settings/plugins/ifcfg-suse/parser.c (read_wpa_eap_settings):
Imlement WPA-EAP configuration reading from sysconfig.
2008-05-16 Dan Williams <dcbw@redhat.com>
* src/nm-device-802-11-wireless.c

View file

@ -261,6 +261,44 @@ AC_SUBST(POLKIT_CFLAGS)
AC_PATH_PROG([POLKIT_POLICY_FILE_VALIDATE], [polkit-policy-file-validate], [false])
AC_ARG_WITH(nss, AC_HELP_STRING([--with-nss], [Use NSS library for certificate and key operations]), ac_nss=$withval, ac_nss=auto)
if test x"$ac_nss" != xno; then
PKG_CHECK_MODULES(NSS, [nss >= 3.11])
AC_DEFINE(HAVE_NSS, 1, [Define if you have NSS])
fi
AM_CONDITIONAL(WITH_NSS, test x"$ac_nss" != xno)
AC_ARG_WITH(gnutls, AC_HELP_STRING([--with-gnutls], [Use gnutls and gcrypt libraries for certificate and key operations]), ac_gnutls=$withval, ac_gnutls=no)
if test x"$ac_gnutls" != xno; then
PKG_CHECK_MODULES(GNUTLS, [gnutls >= 1.2])
AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no)
else
LIBGCRYPT_CONFIG=no
fi
if test x"$LIBGCRYPT_CONFIG" = xno; then
if test x"$ac_gnutls" = xyes; then
AC_MSG_ERROR([gnutls explicitly requested but gcrypt not found on system])
fi
ac_gnutls=no
else
if test x"$ac_gnutls" != xno; then
AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have libgnutls])
LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
AC_SUBST(LIBGCRYPT_CFLAGS)
AC_SUBST(LIBGCRYPT_LIBS)
fi
fi
AM_CONDITIONAL(WITH_GNUTLS, test x"$ac_gnutls" != xno)
if test x"$ac_nss" = xno -a x"$ac_gnutls" = xno; then
AC_MSG_ERROR([Please choose either NSS or gnutls for certificate and key operations])
fi
if test x"$ac_nss" = xyes -a x"$ac_gnutls" = xyes; then
AC_MSG_ERROR([Please choose _one_ of NSS or gnutls for certificate and key operations])
fi
GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
AC_SUBST(GLIB_GENMARSHAL)

View file

@ -28,6 +28,8 @@ libnm_util_include_HEADERS = \
nm-utils.h
libnm_util_la_SOURCES= \
crypto.c \
crypto.h \
nm-connection.c \
nm-param-spec-specialized.c \
nm-setting.c \
@ -51,8 +53,28 @@ libnm_util_la_LDFLAGS= $(GLIB_LIBS) $(DBUS_LIBS)
libnm_util_la_CFLAGS=-fPIC
libnm_util_la_LIBADD =
if WITH_GNUTLS
libnm_util_la_SOURCES += crypto_gnutls.c
libnm_util_la_CPPFLAGS += $(LIBGCRYPT_CFLAGS) $(GNUTLS_CFLAGS)
libnm_util_la_LIBADD += $(LIBGCRYPT_LIBS) $(GNUTLS_LIBS)
endif
if WITH_NSS
libnm_util_la_SOURCES += crypto_nss.c
libnm_util_la_CPPFLAGS += $(NSS_CFLAGS)
libnm_util_la_LIBADD += $(NSS_LIBS)
endif
libnm_util_includedir=$(includedir)/NetworkManager
noinst_PROGRAMS = test-crypto
test_crypto_SOURCES = test-crypto.c
test_crypto_CPPFLAGS = $(GLIB_CFLAGS) -D_GNU_SOURCE
test_crypto_LDADD = $(GLIB_LIBS) ${top_builddir}/libnm-util/libnm-util.la
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnm-util.pc

547
libnm-util/crypto.c Normal file
View file

@ -0,0 +1,547 @@
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#include <glib.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <glib/gi18n.h>
#include "crypto.h"
GQuark
nm_crypto_error_quark (void)
{
static GQuark quark;
if (G_UNLIKELY (!quark))
quark = g_quark_from_static_string ("nm-crypto-error-quark");
return quark;
}
static const char *pem_rsa_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
static const char *pem_rsa_key_end = "-----END RSA PRIVATE KEY-----";
static const char *pem_dsa_key_begin = "-----BEGIN DSA PRIVATE KEY-----";
static const char *pem_dsa_key_end = "-----END DSA PRIVATE KEY-----";
static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
static const char *pem_cert_end = "-----END CERTIFICATE-----";
static const char *
find_tag (const char *tag, const char *buf, gsize len)
{
gsize i, taglen;
taglen = strlen (tag);
if (len < taglen)
return NULL;
for (i = 0; i < len - taglen; i++) {
if (memcmp (buf + i, tag, taglen) == 0)
return buf + i;
}
return NULL;
}
#define DEK_INFO_TAG "DEK-Info: "
#define PROC_TYPE_TAG "Proc-Type: "
static char *
parse_key_file (const char *filename,
int key_type,
gsize *out_length,
char **out_cipher,
char **out_iv,
GError **error)
{
char *contents = NULL;
char **lines = NULL;
char **ln = NULL;
gsize length = 0;
const char *pos;
const char *end;
GString *str = NULL;
int enc_tags = 0;
char *iv = NULL;
char *cipher = NULL;
char *bindata = NULL;
gsize bindata_len = 0;
const char *start_tag;
const char *end_tag;
switch (key_type) {
case NM_CRYPTO_KEY_TYPE_RSA:
start_tag = pem_rsa_key_begin;
end_tag = pem_rsa_key_end;
break;
case NM_CRYPTO_KEY_TYPE_DSA:
start_tag = pem_dsa_key_begin;
end_tag = pem_dsa_key_end;
break;
default:
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_UNKNOWN_KEY_TYPE,
"Unknown key type %d",
key_type);
g_assert_not_reached ();
return NULL;
}
if (!g_file_get_contents (filename, &contents, &length, error))
return NULL;
pos = find_tag (start_tag, contents, length);
if (!pos)
goto parse_error;
pos += strlen (start_tag);
end = find_tag (end_tag, pos, contents + length - pos);
if (end == NULL) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_PEM_FORMAT_INVALID,
_("PEM key file had no end tag '%s'."),
end_tag);
goto parse_error;
}
*((char *) end) = '\0';
lines = g_strsplit (pos, "\n", 0);
if (!lines || g_strv_length (lines) <= 1) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_PEM_FORMAT_INVALID,
_("Doesn't look like a PEM private key file."));
goto parse_error;
}
str = g_string_new_len (NULL, end - pos);
if (!str) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory to store PEM file data."));
goto parse_error;
}
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) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_PEM_FORMAT_INVALID,
_("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_ERR_PEM_FORMAT_INVALID,
_("Malformed PEM file: unknown Proc-Type tag '%s'."),
p);
goto parse_error;
}
} else if (!strncmp (p, DEK_INFO_TAG, strlen (DEK_INFO_TAG))) {
char *comma;
if (enc_tags++ != 1) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_PEM_FORMAT_INVALID,
_("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_ERR_PEM_FORMAT_INVALID,
_("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_ERR_PEM_FORMAT_INVALID,
_("Malformed PEM file: invalid format of IV in DEK-Info tag."));
goto parse_error;
}
iv = g_strdup (comma);
/* Get the private key cipher */
if (!strcasecmp (p, "DES-EDE3-CBC")) {
cipher = g_strdup (p);
} else if (!strcasecmp (p, "DES-CBC")) {
cipher = g_strdup (p);
} else {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_UNKNOWN_KEY_TYPE,
_("Malformed PEM file: unknown private key cipher '%s'."),
p);
goto parse_error;
}
} else {
if ((enc_tags != 0) && (enc_tags != 2)) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_PEM_FORMAT_INVALID,
"Malformed PEM file: both Proc-Type and DEK-Info tags are required.");
goto parse_error;
}
g_string_append (str, p);
}
}
bindata = (char *) g_base64_decode (str->str, &bindata_len);
if (bindata == NULL || !bindata_len) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_DECODE_FAILED,
_("Could not decode private key."));
goto parse_error;
}
if (lines)
g_strfreev (lines);
g_free (contents);
*out_iv = iv;
*out_cipher = cipher;
*out_length = bindata_len;
return bindata;
parse_error:
g_free (bindata);
g_free (cipher);
g_free (iv);
if (lines)
g_strfreev (lines);
g_free (contents);
return NULL;
}
static GByteArray *
file_to_g_byte_array (const char *filename,
GError **error)
{
char *contents, *der = NULL;
GByteArray *array = NULL;
gsize length = 0;
const char *pos;
if (!g_file_get_contents (filename, &contents, &length, error))
return NULL;
pos = find_tag (pem_cert_begin, contents, length);
if (pos) {
const char *end;
pos += strlen (pem_cert_begin);
end = find_tag (pem_cert_end, pos, contents + length - pos);
if (end == NULL) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_PEM_FORMAT_INVALID,
_("PEM certificate '%s' had no end tag '%s'."),
filename, pem_cert_end);
goto done;
}
contents[end - contents - 1] = '\0';
der = (char *) g_base64_decode (pos, &length);
if (der == NULL || !length) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_DECODE_FAILED,
_("Failed to decode certificate."));
goto done;
}
}
array = g_byte_array_sized_new (length);
if (!array) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory to store certificate data."));
goto done;
}
g_byte_array_append (array, der ? (unsigned char *) der : (unsigned char *) contents, length);
if (array->len != length) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory to store certificate data."));
g_byte_array_free (array, TRUE);
array = NULL;
}
done:
g_free (der);
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_ERR_RAW_IV_INVALID,
_("IV must be an even number of bytes in length."));
return NULL;
}
num /= 2;
c = g_malloc0 (num + 1);
if (c == NULL) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory to store the IV."));
return NULL;
}
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_ERR_RAW_IV_INVALID,
_("IV contains non-hexadecimal digits."));
goto error;
}
c[i] = strtol(conv, NULL, 16);
}
*out_len = num;
return c;
error:
g_free (c);
return NULL;
}
static char *
make_des_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, "DES-EDE3-CBC"))
digest_len = 24;
else if (!strcmp (cipher, "DES-CBC"))
digest_len = 8;
else {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_UNKNOWN_CIPHER,
_("Private key cipher '%s' was unknown."),
cipher);
return NULL;
}
key = g_malloc0 (digest_len + 1);
if (!key) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory to create private key decryption key."));
return NULL;
}
if (!crypto_md5_hash (salt,
salt_len,
password,
strlen (password),
key,
digest_len,
error))
goto error;
*out_len = digest_len;
return key;
error:
if (key) {
/* Don't leak stale key material */
memset (key, 0, digest_len);
g_free (key);
}
return NULL;
}
static char *
decrypt_key (const char *cipher,
int key_type,
const char *data,
gsize data_len,
const char *iv,
const char *password,
gsize *out_len,
GError **error)
{
char *bin_iv = NULL;
gsize bin_iv_len = 0;
char *key = NULL;
gsize key_len = 0;
char *output = NULL;
bin_iv = convert_iv (iv, &bin_iv_len, error);
if (!bin_iv)
return NULL;
/* Convert the PIN and IV into a DES key */
key = make_des_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,
out_len,
error);
if (!output)
goto out;
if (*out_len == 0) {
g_free (output);
output = NULL;
goto out;
}
out:
if (key) {
/* Don't leak stale key material */
memset (key, 0, key_len);
g_free (key);
}
g_free (bin_iv);
return output;
}
GByteArray *
crypto_get_private_key (const char *file,
const char *password,
guint32 *out_key_type,
GError **error)
{
GByteArray *array = NULL;
guint32 key_type = NM_CRYPTO_KEY_TYPE_RSA;
char *data = NULL;
gsize data_len = 0;
char *iv = NULL;
char *cipher = NULL;
char *decrypted = NULL;
gsize decrypted_len = 0;
/* Try RSA first */
data = parse_key_file (file, key_type, &data_len, &cipher, &iv, error);
if (!data) {
g_clear_error (error);
/* DSA next */
key_type = NM_CRYPTO_KEY_TYPE_DSA;
data = parse_key_file (file, key_type, &data_len, &cipher, &iv, error);
if (!data)
goto out;
}
decrypted = decrypt_key (cipher,
key_type,
data,
data_len,
iv,
password,
&decrypted_len,
error);
if (!decrypted)
goto out;
array = g_byte_array_sized_new (decrypted_len);
if (!array) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory to store decrypted private key."));
goto out;
}
g_byte_array_append (array, (const guint8 *) decrypted, decrypted_len);
*out_key_type = key_type;
out:
if (decrypted) {
/* Don't expose key material */
memset (decrypted, 0, decrypted_len);
g_free (decrypted);
}
g_free (data);
g_free (cipher);
g_free (iv);
return array;
}
GByteArray *
crypto_load_and_verify_certificate (const char *file,
GError **error)
{
GByteArray *array;
array = file_to_g_byte_array (file, error);
if (!array)
return NULL;
if (!crypto_verify_cert (array->data, array->len, error)) {
g_byte_array_free (array, TRUE);
array = NULL;
}
return array;
}

92
libnm-util/crypto.h Normal file
View file

@ -0,0 +1,92 @@
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#include <glib.h>
#define MD5_HASH_LEN 20
#define CIPHER_DES_EDE3_CBC "DES-EDE3-CBC"
#define CIPHER_DES_CBC "DES-CBC"
enum {
NM_CRYPTO_ERR_NONE = 0,
NM_CRYPTO_ERR_CANT_READ_FILE,
NM_CRYPTO_ERR_PEM_FORMAT_INVALID,
NM_CRYPTO_ERR_CERT_FORMAT_INVALID,
NM_CRYPTO_ERR_DECODE_FAILED,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
NM_CRYPTO_ERR_UNKNOWN_KEY_TYPE,
NM_CRYPTO_ERR_UNKNOWN_CIPHER,
NM_CRYPTO_ERR_RAW_IV_INVALID,
NM_CRYPTO_ERR_MD5_INIT_FAILED,
NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
NM_CRYPTO_ERR_CIPHER_SET_KEY_FAILED,
NM_CRYPTO_ERR_CIPHER_SET_IV_FAILED,
NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
};
enum {
NM_CRYPTO_KEY_TYPE_UNKNOWN = 0,
NM_CRYPTO_KEY_TYPE_RSA,
NM_CRYPTO_KEY_TYPE_DSA,
};
#define NM_CRYPTO_ERROR nm_crypto_error_quark ()
GQuark nm_crypto_error_quark (void);
gboolean crypto_init (GError **error);
void crypto_deinit (void);
GByteArray * crypto_get_private_key (const char *file,
const char *password,
guint32 *out_key_type,
GError **error);
GByteArray * crypto_load_and_verify_certificate (const char *file,
GError **error);
/* Internal utils API bits for crypto providers */
gboolean crypto_md5_hash (const char *salt,
const gsize salt_len,
const char *password,
gsize password_len,
char *buffer,
gsize buflen,
GError **error);
char * crypto_decrypt (const char *cipher,
int key_type,
const char *data,
gsize data_len,
const char *iv,
const gsize iv_len,
const char *key,
const gsize key_len,
gsize *out_len,
GError **error);
gboolean crypto_verify_cert (const unsigned char *data,
gsize len,
GError **error);

227
libnm-util/crypto_gnutls.c Normal file
View file

@ -0,0 +1,227 @@
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#include <glib.h>
#include <glib/gi18n.h>
#include <gcrypt.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "crypto.h"
gboolean
crypto_init (GError **error)
{
gnutls_global_init();
return TRUE;
}
void
crypto_deinit (void)
{
gnutls_global_deinit();
}
gboolean
crypto_md5_hash (const char *salt,
const gsize salt_len,
const char *password,
gsize password_len,
char *buffer,
gsize buflen,
GError **error)
{
gcry_md_hd_t ctx;
gcry_error_t err;
int nkey = buflen;
const gsize digest_len = 16;
int count = 0;
char digest[MD5_HASH_LEN];
char *p = buffer;
g_return_val_if_fail (salt != NULL, FALSE);
g_return_val_if_fail (salt_len >= 8, FALSE);
g_return_val_if_fail (password != NULL, FALSE);
g_return_val_if_fail (password_len > 0, FALSE);
g_return_val_if_fail (buffer != NULL, FALSE);
g_return_val_if_fail (buflen > 0, FALSE);
err = gcry_md_open (&ctx, GCRY_MD_MD5, 0);
if (err) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_MD5_INIT_FAILED,
_("Failed to initialize the MD5 engine: %s / %s."),
gcry_strsource (err), gcry_strerror (err));
return FALSE;
}
while (nkey > 0) {
int i = 0;
if (count++)
gcry_md_write (ctx, digest, digest_len);
gcry_md_write (ctx, password, password_len);
gcry_md_write (ctx, salt, 8); /* Only use 8 bytes of salt */
gcry_md_final (ctx);
memcpy (digest, gcry_md_read (ctx, 0), digest_len);
gcry_md_reset (ctx);
while (nkey && (i < digest_len)) {
*(p++) = digest[i++];
nkey--;
}
}
memset (digest, 0, sizeof (digest));
gcry_md_close (ctx);
return TRUE;
}
char *
crypto_decrypt (const char *cipher,
int key_type,
const char *data,
gsize data_len,
const char *iv,
const gsize iv_len,
const char *key,
const gsize key_len,
gsize *out_len,
GError **error)
{
gcry_cipher_hd_t ctx;
gcry_error_t err;
int cipher_mech;
char *output = NULL;
gboolean success = FALSE;
gsize len;
if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
cipher_mech = GCRY_CIPHER_3DES;
else if (!strcmp (cipher, CIPHER_DES_CBC))
cipher_mech = GCRY_CIPHER_DES;
else {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_UNKNOWN_CIPHER,
_("Private key cipher '%s' was unknown."),
cipher);
return NULL;
}
output = g_malloc0 (data_len + 1);
if (!output) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory for decrypted key buffer."));
return NULL;
}
err = gcry_cipher_open (&ctx, cipher_mech, GCRY_CIPHER_MODE_CBC, 0);
if (err) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
_("Failed to initialize the decryption cipher context: %s / %s."),
gcry_strsource (err), gcry_strerror (err));
goto out;
}
err = gcry_cipher_setkey (ctx, key, key_len);
if (err) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_SET_KEY_FAILED,
_("Failed to set symmetric key for decryption: %s / %s."),
gcry_strsource (err), gcry_strerror (err));
goto out;
}
err = gcry_cipher_setiv (ctx, iv, iv_len);
if (err) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_SET_IV_FAILED,
_("Failed to set IV for decryption: %s / %s."),
gcry_strsource (err), gcry_strerror (err));
goto out;
}
err = gcry_cipher_decrypt (ctx, output, data_len, data, data_len);
if (err) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
_("Failed to decrypt the private key: %s / %s."),
gcry_strsource (err), gcry_strerror (err));
goto out;
}
len = data_len - output[data_len - 1];
if (len > data_len)
goto out;
*out_len = len;
output[*out_len] = '\0';
success = TRUE;
out:
if (!success) {
if (output) {
/* Don't expose key material */
memset (output, 0, data_len);
g_free (output);
output = NULL;
}
}
gcry_cipher_close (ctx);
return output;
}
gboolean
crypto_verify_cert (const unsigned char *data,
gsize len,
GError **error)
{
gnutls_x509_crt_t crt;
gnutls_datum dt;
int err;
err = gnutls_x509_crt_init (&crt);
if (err < 0) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CERT_FORMAT_INVALID,
_("Error initializing certificate data: %s"),
gnutls_strerror (err));
return FALSE;
}
dt.data = (unsigned char *) data;
dt.size = len;
err = gnutls_x509_crt_import (crt, &dt, GNUTLS_X509_FMT_DER);
if (err < 0) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CERT_FORMAT_INVALID,
_("Couldn't decode certificate: %s"),
gnutls_strerror (err));
return FALSE;
}
gnutls_x509_crt_deinit (crt);
return TRUE;
}

256
libnm-util/crypto_nss.c Normal file
View file

@ -0,0 +1,256 @@
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#include <glib.h>
#include <glib/gi18n.h>
#include <prinit.h>
#include <nss.h>
#include <pk11pub.h>
#include <pkcs11t.h>
#include <cert.h>
#include "crypto.h"
gboolean
crypto_init (GError **error)
{
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1);
NSS_NoDB_Init (NULL);
return TRUE;
}
void
crypto_deinit (void)
{
NSS_Shutdown ();
PR_Cleanup ();
}
gboolean
crypto_md5_hash (const char *salt,
const gsize salt_len,
const char *password,
gsize password_len,
char *buffer,
gsize buflen,
GError **error)
{
PK11Context *ctx;
int nkey = buflen;
unsigned int digest_len;
int count = 0;
char digest[MD5_HASH_LEN];
char *p = buffer;
g_return_val_if_fail (salt != NULL, FALSE);
g_return_val_if_fail (salt_len >= 8, FALSE);
g_return_val_if_fail (password != NULL, FALSE);
g_return_val_if_fail (password_len > 0, FALSE);
g_return_val_if_fail (buffer != NULL, FALSE);
g_return_val_if_fail (buflen > 0, FALSE);
ctx = PK11_CreateDigestContext (SEC_OID_MD5);
if (!ctx) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_MD5_INIT_FAILED,
_("Failed to initialize the MD5 context: %d."),
PORT_GetError ());
return FALSE;
}
while (nkey > 0) {
int i = 0;
PK11_DigestBegin (ctx);
if (count++)
PK11_DigestOp (ctx, (const unsigned char *) digest, digest_len);
PK11_DigestOp (ctx, (const unsigned char *) password, password_len);
PK11_DigestOp (ctx, (const unsigned char *) salt, 8); /* Only use 8 bytes of salt */
PK11_DigestFinal (ctx, (unsigned char *) digest, &digest_len, sizeof (digest));
while (nkey && (i < digest_len)) {
*(p++) = digest[i++];
nkey--;
}
}
memset (digest, 0, sizeof (digest));
PK11_DestroyContext (ctx, PR_TRUE);
return TRUE;
}
char *
crypto_decrypt (const char *cipher,
int key_type,
const char *data,
gsize data_len,
const char *iv,
const gsize iv_len,
const char *key,
const gsize key_len,
gsize *out_len,
GError **error)
{
char *output = NULL;
int tmp1_len = 0;
unsigned int tmp2_len = 0;
CK_MECHANISM_TYPE cipher_mech;
PK11SlotInfo *slot = NULL;
SECItem key_item;
PK11SymKey *sym_key = NULL;
SECItem *sec_param = NULL;
PK11Context *ctx = NULL;
SECStatus s;
gboolean success = FALSE;
gsize len;
if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
cipher_mech = CKM_DES3_CBC_PAD;
else if (!strcmp (cipher, CIPHER_DES_CBC))
cipher_mech = CKM_DES_CBC_PAD;
else {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_UNKNOWN_CIPHER,
_("Private key cipher '%s' was unknown."),
cipher);
return NULL;
}
output = g_malloc0 (data_len + 1);
if (!output) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_OUT_OF_MEMORY,
_("Not enough memory for decrypted key buffer."));
return NULL;
}
slot = PK11_GetBestSlot (cipher_mech, NULL);
if (!slot) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
_("Failed to initialize the decryption cipher slot."));
goto out;
}
key_item.data = (unsigned char *) key;
key_item.len = key_len;
sym_key = PK11_ImportSymKey (slot, cipher_mech, PK11_OriginUnwrap, CKA_DECRYPT, &key_item, NULL);
if (!sym_key) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_SET_KEY_FAILED,
_("Failed to set symmetric key for decryption."));
goto out;
}
key_item.data = (unsigned char *) iv;
key_item.len = iv_len;
sec_param = PK11_ParamFromIV (cipher_mech, &key_item);
if (!sec_param) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_SET_IV_FAILED,
_("Failed to set IV for decryption."));
goto out;
}
ctx = PK11_CreateContextBySymKey (cipher_mech, CKA_DECRYPT, sym_key, sec_param);
if (!ctx) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
_("Failed to initialize the decryption context."));
goto out;
}
s = PK11_CipherOp (ctx,
(unsigned char *) output,
&tmp1_len,
data_len,
(unsigned char *) data,
data_len);
if (s != SECSuccess) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
_("Failed to decrypt the private key: %d."),
PORT_GetError ());
goto out;
}
s = PK11_DigestFinal (ctx,
(unsigned char *) (output + tmp1_len),
&tmp2_len,
data_len - tmp1_len);
if (s != SECSuccess) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
_("Failed to finalize decryption of the private key: %d."),
PORT_GetError ());
goto out;
}
len = tmp1_len + tmp2_len;
if (len > data_len)
goto out;
*out_len = len;
output[*out_len] = '\0';
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 (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;
}
gboolean
crypto_verify_cert (const unsigned char *data,
gsize len,
GError **error)
{
CERTCertificate *cert;
cert = CERT_DecodeCertFromPackage ((char *) data, len);
if (!cert) {
g_set_error (error, NM_CRYPTO_ERROR,
NM_CRYPTO_ERR_CERT_FORMAT_INVALID,
_("Couldn't decode certificate: %d"),
PORT_GetError());
return FALSE;
}
CERT_DestroyCertificate (cert);
return TRUE;
}

View file

@ -7,6 +7,7 @@
#include "nm-param-spec-specialized.h"
#include "nm-utils.h"
#include "nm-dbus-glib-types.h"
#include "crypto.h"
G_DEFINE_TYPE (NMSetting8021x, nm_setting_802_1x, NM_TYPE_SETTING)
@ -41,6 +42,117 @@ nm_setting_802_1x_new (void)
return (NMSetting *) g_object_new (NM_TYPE_SETTING_802_1X, NULL);
}
gboolean
nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
const char *filename,
GError **err)
{
g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
if (self->ca_cert)
g_byte_array_free (self->ca_cert, TRUE);
self->ca_cert = crypto_load_and_verify_certificate (filename, err);
return self->ca_cert != NULL;
}
gboolean
nm_setting_802_1x_set_client_cert (NMSetting8021x *self,
const char *filename,
GError **err)
{
g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
if (self->client_cert)
g_byte_array_free (self->client_cert, TRUE);
self->client_cert = crypto_load_and_verify_certificate (filename, err);
return self->client_cert != NULL;
}
gboolean
nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self,
const char *filename,
GError **err)
{
g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
if (self->phase2_ca_cert)
g_byte_array_free (self->phase2_ca_cert, TRUE);
self->phase2_ca_cert = crypto_load_and_verify_certificate (filename, err);
return self->phase2_ca_cert != NULL;
}
gboolean
nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self,
const char *filename,
GError **err)
{
g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
if (self->phase2_client_cert)
g_byte_array_free (self->phase2_client_cert, TRUE);
self->phase2_client_cert = crypto_load_and_verify_certificate (filename, err);
return self->phase2_client_cert != NULL;
}
gboolean
nm_setting_802_1x_set_private_key (NMSetting8021x *self,
const char *filename,
const char *password,
GError **err)
{
guint32 ignore;
g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (password != NULL, FALSE);
if (self->private_key) {
/* Try not to leave the decrypted private key around in memory */
memset (self->private_key, 0, self->private_key->len);
g_byte_array_free (self->private_key, TRUE);
}
self->private_key = crypto_get_private_key (filename, password, &ignore, err);
return self->private_key != NULL;
}
gboolean
nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self,
const char *filename,
const char *password,
GError **err)
{
guint32 ignore;
g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (password != NULL, FALSE);
if (self->phase2_private_key) {
/* Try not to leave the decrypted private key around in memory */
memset (self->phase2_private_key, 0, self->phase2_private_key->len);
g_byte_array_free (self->phase2_private_key, TRUE);
}
self->phase2_private_key = crypto_get_private_key (filename, password, &ignore, err);
return self->phase2_private_key != NULL;
}
static void
need_secrets_password (NMSetting8021x *self,
GPtrArray *secrets,
@ -487,6 +599,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
GError *error = NULL;
/* virtual methods */
object_class->set_property = set_property;
@ -632,4 +745,12 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
"Phase2 private key",
DBUS_TYPE_G_UCHAR_ARRAY,
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
/* Initialize crypto lbrary. */
if (!crypto_init (&error)) {
g_warning ("Couldn't initilize crypto system: %d %s",
error->code, error->message);
g_error_free (error);
}
}

View file

@ -68,6 +68,32 @@ GType nm_setting_802_1x_get_type (void);
NMSetting *nm_setting_802_1x_new (void);
gboolean nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
const char *filename,
GError **err);
gboolean nm_setting_802_1x_set_client_cert (NMSetting8021x *self,
const char *filename,
GError **err);
gboolean nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self,
const char *filename,
GError **err);
gboolean nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self,
const char *filename,
GError **err);
gboolean nm_setting_802_1x_set_private_key (NMSetting8021x *self,
const char *filename,
const char *password,
GError **err);
gboolean nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self,
const char *filename,
const char *password,
GError **err);
G_END_DECLS
#endif /* NM_SETTING_8021X_H */

171
libnm-util/test-crypto.c Normal file
View file

@ -0,0 +1,171 @@
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#include <glib.h>
#include <unistd.h>
#include <stdlib.h>
#include <glib/gi18n.h>
#include <stdio.h>
#include <string.h>
#include "crypto.h"
static const char *pem_rsa_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
static const char *pem_rsa_key_end = "-----END RSA PRIVATE KEY-----";
static const char *pem_dsa_key_begin = "-----BEGIN DSA PRIVATE KEY-----";
static const char *pem_dsa_key_end = "-----END DSA PRIVATE KEY-----";
static void
dump_key_to_pem (const char *key, gsize key_len, int key_type)
{
char *b64 = NULL;
GString *str = NULL;
const char *start_tag;
const char *end_tag;
char *p;
switch (key_type) {
case NM_CRYPTO_KEY_TYPE_RSA:
start_tag = pem_rsa_key_begin;
end_tag = pem_rsa_key_end;
break;
case NM_CRYPTO_KEY_TYPE_DSA:
start_tag = pem_dsa_key_begin;
end_tag = pem_dsa_key_end;
break;
default:
g_warning ("Unknown key type %d", key_type);
return;
}
b64 = g_base64_encode ((const unsigned char *) key, key_len);
if (!b64) {
g_warning ("Couldn't base64 encode the key.");
goto out;
}
str = g_string_new (NULL);
if (!str) {
g_warning ("Couldn't allocate buffer to write out key.");
goto out;
}
g_string_append (str, start_tag);
g_string_append_c (str, '\n');
for (p = b64; p < (b64 + strlen (b64)); p += 64) {
g_string_append_len (str, p, strnlen (p, 64));
g_string_append_c (str, '\n');
}
g_string_append (str, end_tag);
g_string_append_c (str, '\n');
g_message ("Decrypted private key:\n\n%s", str->str);
out:
g_free (b64);
if (str)
g_string_free (str, TRUE);
}
static void
usage (const char *prgname)
{
fprintf (stderr, "Usage: %s cert <file>\n"
" %s key <file> <password>\n",
prgname, prgname);
}
#define MODE_CERT 1
#define MODE_KEY 2
int main (int argc, char **argv)
{
guint32 key_type = 0;
int mode = 0;
const char *file;
GError *error = NULL;
if (argc < 2) {
usage (argv[0]);
return 1;
}
if (!strcmp (argv[1], "key")) {
if (argc < 4) {
usage (argv[0]);
return 1;
}
mode = MODE_KEY;
} else if (!strcmp (argv[1], "cert")) {
if (argc < 3) {
usage (argv[0]);
return 1;
}
mode = MODE_CERT;
} else {
usage (argv[0]);
return 1;
}
if (!crypto_init (&error)) {
g_warning ("Couldn't initialize crypto library: %d %s.",
error->code, error->message);
return 1;
}
file = argv[2];
if (mode == MODE_CERT) {
GByteArray *array;
array = crypto_load_and_verify_certificate (file, &error);
if (!array) {
g_warning ("Couldn't read certificate file '%s': %d %s",
file, error->code, error->message);
goto out;
}
g_byte_array_free (array, TRUE);
} else if (mode == MODE_KEY) {
const char *password = argv[3];
GByteArray *array;
array = crypto_get_private_key (file, password, &key_type, &error);
if (!array) {
g_warning ("Couldn't read key file '%s': %d %s",
file, error->code, error->message);
goto out;
}
dump_key_to_pem ((const char *) array->data, array->len, key_type);
g_byte_array_free (array, TRUE);
} else {
g_assert_not_reached ();
}
out:
crypto_deinit ();
return 0;
}

View file

@ -6,4 +6,7 @@ src/NetworkManager.c
src/named-manager/nm-named-manager.c
system-settings/plugins/ifcfg-fedora/plugin.c
system-settings/src/main.c
libnm-util/crypto.c
libnm-util/crypto_gnutls.c
libnm-util/crypto_nss.c

View file

@ -436,12 +436,14 @@ read_wpa_psk_settings (shvarFile *ifcfg,
g_warning ("Missing WPA-PSK key");
}
#if 0
static void
read_wpa_eap_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security)
static NMSetting *
read_wpa_eap_settings (shvarFile *ifcfg)
{
NMSetting8021x *s_802_1x;
char *str;
GError *err = NULL;
s_802_1x = NM_SETTING_802_1X (nm_setting_802_1x_new ());
str = svGetValue (ifcfg, "WIRELESS_EAP_MODE");
if (str) {
@ -450,35 +452,61 @@ read_wpa_eap_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security)
pieces = g_strsplit (str, " ", 0);
for (i = 0; pieces[i]; i++)
s_8021x->eap = g_slist_append (s_8021x->eap, pieces[i]);
s_802_1x->eap = g_slist_append (s_802_1x->eap, pieces[i]);
g_free (pieces);
g_free (str);
}
s_802_1x->anonymous_identity = svGetValue (ifcfg, "WIRELESS_WPA_ANONID");
char *ca_path;
GByteArray *ca_cert;
"WIRELESS_CA_CERT";
GByteArray *client_cert;
"WIRELESS_CLIENT_CERT";
GByteArray *private_key;
"WIRELESS_CLIENT_KEY";
private_key_passwd
"WIRELESS_CLIENT_KEY_PASSWORD";
s_802_1x->phase1_peapver = svGetValue (ifcfg, "WIRELESS_PEAP_VERSION");
s_802_1x->phase2_auth = svGetValue (ifcfg, "WIRELESS_EAP_AUTH");
s_802_1x->identity = svGetValue (ifcfg, "WIRELESS_WPA_IDENTITY");
s_802_1x->password = svGetValue (ifcfg, "WIRELESS_WPA_PASSWORD");
str = svGetValue (ifcfg, "WIRELESS_CA_CERT");
if (str) {
nm_setting_802_1x_set_ca_cert (s_802_1x, str, &err);
if (err) {
g_warning ("Error loading WIRELESS_CA_CERT: %s", err->message);
g_error_free (err);
}
g_free (str);
}
str = svGetValue (ifcfg, "WIRELESS_CLIENT_CERT");
if (str) {
nm_setting_802_1x_set_client_cert (s_802_1x, str, &err);
if (err) {
g_warning ("Error loading WIRELESS_CLIENT_CERT: %s", err->message);
g_error_free (err);
}
g_free (str);
}
str = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY");
if (str) {
char *password;
password = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY_PASSWORD");
if (password) {
nm_setting_802_1x_set_private_key (s_802_1x, str, password, &err);
if (err) {
g_warning ("Error loading WIRELESS_CLIENT_KEY: %s", err->message);
g_error_free (err);
}
g_free (password);
} else
g_warning ("Missing WIRELESS_CLIENT_KEY_PASSWORD");
g_free (str);
}
return (NMSetting *) s_802_1x;
}
#endif
static NMSetting *
make_wireless_security_setting (shvarFile *ifcfg, NMSettingWireless *s_wireless)
@ -492,6 +520,9 @@ make_wireless_security_setting (shvarFile *ifcfg, NMSettingWireless *s_wireless)
return NULL;
}
if (!g_ascii_strcasecmp (str, "eap"))
return read_wpa_eap_settings (ifcfg);
security = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
if (!g_ascii_strcasecmp (str, "open")) {
@ -500,18 +531,9 @@ make_wireless_security_setting (shvarFile *ifcfg, NMSettingWireless *s_wireless)
} else if (!g_ascii_strcasecmp (str, "sharedkey")) {
security->auth_alg = g_strdup ("shared");
read_wep_settings (ifcfg, security);
}
else if (!g_ascii_strcasecmp (str, "psk")) {
} else if (!g_ascii_strcasecmp (str, "psk")) {
security->key_mgmt = g_strdup ("wpa-psk");
read_wpa_psk_settings (ifcfg, security, s_wireless);
} else if (!g_ascii_strcasecmp (str, "eap")) {
/* FIXME */
/* security->key_mgmt = g_strdup ("wps-eap"); */
/* read_wpa_eap_settings (ifcfg, security); */
g_warning ("WPA-EAP is currently not supported.");
g_object_unref (security);
security = NULL;
} else
g_warning ("Invalid authentication algorithm: '%s'", str);