libnm-core: add nm_utils_file_is_certificate() and _file_is_private_key()

Add nm-utils methods to check if a file is a certificate or private
key file.

nm-applet currently has its own internal versions of these, but they
ended up having to duplicate a bunch of logic that we already have in
crypto.c.
This commit is contained in:
Dan Winship 2014-10-30 11:15:44 -04:00 committed by Dan Winship
parent 7c74e71e91
commit 1c4f41c610
5 changed files with 136 additions and 1 deletions

View file

@ -2236,17 +2236,91 @@ nm_utils_rsa_key_encrypt_aes (const guint8 *data,
error);
}
static gboolean
file_has_extension (const char *filename, const char *extensions[])
{
const char *ext;
int i;
ext = strrchr (filename, '.');
if (!ext)
return FALSE;
for (i = 0; extensions[i]; i++) {
if (!g_ascii_strcasecmp (ext, extensions[i]))
return TRUE;
}
return FALSE;
}
/**
* nm_utils_file_is_certificate:
* @filename: name of the file to test
*
* Tests if @filename has a valid extension for an X.509 certificate file
* (".cer", ".crt", ".der", or ".pem"), and contains a certificate in a format
* recognized by NetworkManager.
*
* Returns: %TRUE if the file is a certificate, %FALSE if it is not
**/
gboolean
nm_utils_file_is_certificate (const char *filename)
{
const char *extensions[] = { ".der", ".pem", ".crt", ".cer", NULL };
NMCryptoFileFormat file_format;
GByteArray *cert;
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);
return file_format = NM_CRYPTO_FILE_FORMAT_X509;
}
/**
* nm_utils_file_is_private_key:
* @filename: name of the file to test
* @out_encrypted: (out): on return, whether the file is encrypted
*
* Tests if @filename has a valid extension for an X.509 private key file
* (".der", ".key", ".pem", or ".p12"), and contains a private key in a format
* recognized by NetworkManager.
*
* Returns: %TRUE if the file is a private key, %FALSE if it is not
**/
gboolean
nm_utils_file_is_private_key (const char *filename, gboolean *out_encrypted)
{
const char *extensions[] = { ".der", ".pem", ".p12", ".key", NULL };
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (out_encrypted == NULL || *out_encrypted == FALSE, FALSE);
if (!file_has_extension (filename, extensions))
return FALSE;
return crypto_verify_private_key (filename, NULL, out_encrypted, NULL) != NM_CRYPTO_FILE_FORMAT_UNKNOWN;
}
/**
* nm_utils_file_is_pkcs12:
* @filename: name of the file to test
*
* Utility function to find out if the @filename is in PKCS#<!-- -->12 format.
* Tests if @filename is a PKCS#<!-- -->12 file.
*
* Returns: %TRUE if the file is PKCS#<!-- -->12, %FALSE if it is not
**/
gboolean
nm_utils_file_is_pkcs12 (const char *filename)
{
g_return_val_if_fail (filename != NULL, FALSE);
return crypto_is_pkcs12_file (filename, NULL);
}

View file

@ -137,6 +137,8 @@ GByteArray *nm_utils_rsa_key_encrypt_aes (const guint8 *data,
const char *in_password,
char **out_password,
GError **error);
gboolean nm_utils_file_is_certificate (const char *filename);
gboolean nm_utils_file_is_private_key (const char *filename, gboolean *out_encrypted);
gboolean nm_utils_file_is_pkcs12 (const char *filename);
guint32 nm_utils_wifi_freq_to_channel (guint32 freq);

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAztLp+/SkzmaHzIst0sO4+r7qUwiVnidKBHgxoTbS5UL1dvck
cbjTEP23V4ZoKQIb6ZMrr8B+PVgWNBAlhX4oLUL8NH/WTwrntrlAUcjliWDNc1Fj
Z+FZNjFe0IdLXZeKQiLTQvKDYnmERVvYIJfi0TQjXuy/ikF8rYBQ85scUV3kKRzB
xnyhAHAP9nl3AyL1S6t2yiCr4U5TbIZo6dYPbpVLtbXP02zUc9vAPR0gIHKrPiW7
P81fLXf91wuo6wxzwD90JxdWzzGaqe3BOSfHqul3SPRtVok1XHlb9i+Mn5O8ExzQ
dF8wGxVDcY7/Gt9lZWnCilqrBEqA3iApjUgcgwIDAQABAoIBAQC77HCmepf04ryp
Yhz00NoXG7mWUMqBtXlPrlaKAWKG5dxbiBwZKLK/UYlxgbLK8BuklBCx1Nnfq1Yh
YDp3nTWsSp0WpsF3eJUqNhD3Pu8xcD+9dEo6bUu+LgXUu9oC5Fq/1RzYS7qNk5RX
4Sf0FY4GQLWS3tL7MJ20mE71yg5k7qRbDydOyhTh1m1CpRYONWxSsWVLM8KGRDJp
iF0cdPfD5yoPFpgDk8gwzrnXJH2Wqzv8GvyYykRK5AW7tE50y0rTAM42WZ7YS6aZ
FNMmtYxeyzXLY3LgPP0uko5anz3OXRcqCfHfFANG0y7B9MehbrjMgI6S1BbzFl07
V1zVQVqhAoGBAPIfrWMlh1fHlRh4iRGXK2Hvxyv2oNz9KvQ4qRaLV9ejRDzdt7Pi
/utbi5LGBuDw9016nXM3I77b6PukHzsHFnWGRnyRSbkMMt6mE17nggmNqcpFWfE8
E7HcKMhk4gbuo5AHD3Ee1Gac2AUDnzYiE+sS6WI3O9d77cc5ych5jZ+nAoGBANqt
VZCttjY0E+hEyTP37eaE8u0jfdK8AflTJlNUHWKXglES525iu8I/Bso8KaQYsYF3
SezGRd3KQepQhtMjFKfSpF+tbnboP57Y3XGo8xhbxqV4kRX+XGsVoW3Vg2nPKBrR
+dIY5nMwua+gkHWp9RDcemD2reiIZBVx95fK8dfFAoGAdCSH2pBs/MlrFqLzNTHr
iH4pb0hN39O9YAsx6POMfo79s6izbyHLIID4Ub6WHB7ashrIHjVr+yin+NXAeWMr
/dIcS7Kxx4c3e5/0mMi6kvSWZsWfoF0uIVo3YfEqjyK36OXKHXwpbNN9t+IF5ESy
g0e+FfPiy7nR1Ig+5+CO8+8CgYEAp/75+Ug677FaidouaMpT7gC9UAkwJLFjItQK
YYIBgTi8WOSY/2jCrhwVb1CA/RwrYjbuiARasGUt9oEe0x3kRHnC5e4rKxaJqdMZ
bLRK7a+0EHNrouXiwjG/7s1VQ/ht6wzdS9btVBlezdogoQSMzQNU0SExwa7mlMMV
X3v+B7ECgYAK+Yt4jnLH1LNWoDTU0Ug5hyXsQXV8lVBSnrkvS7GtP6ZA/4OqG7lJ
/bTYFZGoiAGzOnC+YlAqSIu45CEnpr2xBsThQiWUVxspmQD1lEWWFcd77DPUwn3C
59pLgx0AqJE3n6lBOwehiXbFKBdVzX8PfPZpuCK6qc/RiTILktwURA==
-----END RSA PRIVATE KEY-----

View file

@ -109,6 +109,8 @@ test_cert (gconstpointer test_data)
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 *
@ -134,9 +136,13 @@ test_load_private_key (const char *path,
int expected_error)
{
NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN;
gboolean is_encrypted = FALSE;
GByteArray *array, *decrypted;
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);
/* Even if the password is wrong, we should determine the key type */
g_assert_cmpint (key_type, ==, NM_CRYPTO_KEY_TYPE_RSA);
@ -178,6 +184,8 @@ test_load_pkcs12 (const char *path,
gboolean is_encrypted = FALSE;
GError *error = NULL;
g_assert (nm_utils_file_is_private_key (path, NULL));
format = crypto_verify_private_key (path, password, &is_encrypted, &error);
if (expected_error != -1) {
g_assert_error (error, NM_CRYPTO_ERROR, expected_error);
@ -197,6 +205,8 @@ test_load_pkcs12_no_password (const char *path)
gboolean is_encrypted = FALSE;
GError *error = NULL;
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);
g_assert_no_error (error);
@ -231,6 +241,8 @@ test_load_pkcs8 (const char *path,
gboolean is_encrypted = FALSE;
GError *error = NULL;
g_assert (nm_utils_file_is_private_key (path, NULL));
format = crypto_verify_private_key (path, password, &is_encrypted, &error);
if (expected_error != -1) {
g_assert_error (error, NM_CRYPTO_ERROR, expected_error);
@ -329,6 +341,21 @@ test_key (gconstpointer test_data)
g_strfreev (parts);
}
static void
test_key_decrypted (gconstpointer test_data)
{
const char *file = (const char *) test_data;
gboolean is_encrypted = FALSE;
char *path;
path = g_build_filename (TEST_CERT_DIR, file, NULL);
g_assert (nm_utils_file_is_private_key (path, &is_encrypted));
g_assert (!is_encrypted);
g_free (path);
}
static void
test_pkcs12 (gconstpointer test_data)
{
@ -418,6 +445,9 @@ main (int argc, char **argv)
g_test_add_data_func ("/libnm/crypto/key/aes",
"test-aes-key.pem, test-aes-password",
test_key);
g_test_add_data_func ("/libnm/crypto/key/decrypted",
"test-key-only-decrypted.pem",
test_key_decrypted);
g_test_add_data_func ("/libnm/crypto/PKCS#12/1",
"test-cert.p12, test",

View file

@ -756,7 +756,9 @@ global:
nm_utils_check_virtual_device_compatibility;
nm_utils_deinit;
nm_utils_escape_ssid;
nm_utils_file_is_certificate;
nm_utils_file_is_pkcs12;
nm_utils_file_is_private_key;
nm_utils_hexstr2bin;
nm_utils_hwaddr_atoba;
nm_utils_hwaddr_aton;