mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-04 14:08:19 +02:00
Add support for PKCS#12 private keys (bgo #558982) * libnm-util/crypto.c libnm-util/crypto.h - (parse_old_openssl_key_file): rename from parse_key_file(); adapt to take a GByteArray instead of a filename - (file_to_g_byte_array): handle private key files too - (decrypt_key): take a GByteArray rather than data + len - (crypto_get_private_key_data): refactor crypto_get_private_key() into one function that takes a filename, and one that takes raw data; detect pkcs#12 files as well - (crypto_load_and_verify_certificate): detect file type - (crypto_is_pkcs12_data, crypto_is_pkcs12_file): add pkcs#12 detection functions * libnm-util/crypto_gnutls.c - (crypto_decrypt): take GByteArray rather than data + len; fix a bug whereby tail padding was incorrectly handled, leading to erroneous successes when trying to decrypt the data - (crypto_verify_cert): rework somewhat - (crypto_verify_pkcs12): validate pkcs#12 keys * libnm-util/crypto_nss.c - (crypto_init): enable various pkcs#12 ciphers - (crypto_decrypt): take a GByteArray rather than data + len - (crypto_verify_cert): clean up - (crypto_verify_pkcs12): validate pkcs#12 keys * libnm-util/test-crypto.c - Handle pkcs#12 keys * libnm-util/nm-setting-8021x.c libnm-util/nm-setting-8021x.h libnm-util/libnm-util.ver - Add two new properties, 'private-key-password' and 'phase2-private-key-password', to be used in conjunction with pkcs#12 keys - (nm_setting_802_1x_set_ca_cert_from_file, nm_setting_802_1x_set_client_cert_from_file, nm_setting_802_1x_set_phase2_ca_cert_from_file, nm_setting_802_1x_set_phase2_client_from_file): return certificate type - (nm_setting_802_1x_get_private_key_password, nm_setting_802_1x_get_phase2_private_key_password): return private key passwords - (nm_setting_802_1x_set_private_key_from_file, nm_setting_802_1x_set_phase2_private_key_from_file): set the private key from a file, and update the private key password at the same time - (nm_setting_802_1x_get_private_key_type, nm_setting_802_1x_get_phase2_private_key_type): return the private key type * src/supplicant-manager/nm-supplicant-settings-verify.c - Whitelist private key passwords * src/supplicant-manager/nm-supplicant-config.c - (nm_supplicant_config_add_setting_8021x): for pkcs#12 private keys, add the private key password to the supplicant config, but do not add the client certificate (as required by wpa_supplicant) git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4280 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
200 lines
4.6 KiB
C
200 lines
4.6 KiB
C
/* -*- 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.
|
|
*
|
|
* (C) Copyright 2007 - 2008 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)
|
|
{
|
|
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;
|
|
NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
|
|
|
|
array = crypto_load_and_verify_certificate (file, &format, &error);
|
|
if (!array) {
|
|
g_warning ("Couldn't read certificate file '%s': %d %s",
|
|
file, error->code, error->message);
|
|
goto out;
|
|
}
|
|
|
|
switch (format) {
|
|
case NM_CRYPTO_FILE_FORMAT_X509:
|
|
g_message ("Format: pkcs#1");
|
|
break;
|
|
case NM_CRYPTO_FILE_FORMAT_PKCS12:
|
|
g_message ("Format: pkcs#12");
|
|
break;
|
|
default:
|
|
g_message ("Format: unknown");
|
|
break;
|
|
}
|
|
|
|
g_byte_array_free (array, TRUE);
|
|
} else if (mode == MODE_KEY) {
|
|
NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
|
|
NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
|
|
const char *password = argv[3];
|
|
GByteArray *array;
|
|
|
|
array = crypto_get_private_key (file, password, &key_type, &format, &error);
|
|
if (!array) {
|
|
g_warning ("Couldn't read key file '%s': %d %s",
|
|
file, error->code, error->message);
|
|
goto out;
|
|
}
|
|
|
|
switch (format) {
|
|
case NM_CRYPTO_FILE_FORMAT_RAW_KEY:
|
|
g_message ("Original format: pkcs#1\n");
|
|
dump_key_to_pem ((const char *) array->data, array->len, key_type);
|
|
break;
|
|
case NM_CRYPTO_FILE_FORMAT_PKCS12:
|
|
g_message ("Original format: pkcs#12");
|
|
break;
|
|
default:
|
|
g_message ("Original format: unknown");
|
|
break;
|
|
}
|
|
|
|
g_byte_array_free (array, TRUE);
|
|
} else {
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
out:
|
|
crypto_deinit ();
|
|
|
|
return 0;
|
|
}
|
|
|