libnm: move dependency to libnm-crypto out of libnm-core's "nm-utils.c"

libnm-core is also used by the daemon, thus currently dragging in
libnm-crypto there. But could we ever drop that dependency?

One use of the libnm-crypto is in functions like nm_utils_file_is_certificate()
in "nm-utils.h". These are part of the public API of libnm.

But this is not used by the daemon. Move it to "libnm-client-core"
to be closer to where it's actually used.

As we have unit tests in "libnm-core-impl/tests" that test this function,
those unit tests also would need to move to "libnm-client-impl".
Instead, add the actual implementation of these function to "libnm-crypto"
and test it there.

This patch moves forward declarations from public header "nm-utils.h" to
"nm-client.h". Arguably, "nm-client.h" is not a great name, but we don't
have a general purpose header in "libnm-client-public", so use this.
Note that libnm users can only include <NetworkManager.h> and including
individual files is not supported (and even prevented). Thus moving
the declarations won't break any users.
This commit is contained in:
Thomas Haller
2022-03-18 21:33:20 +01:00
parent 901787e06f
commit 723e1fc76f
7 changed files with 121 additions and 99 deletions

View File

@@ -10,7 +10,9 @@
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "libnm-crypto/nm-crypto.h"
#include "nm-object.h"
#include "nm-utils.h"
/*****************************************************************************/
@@ -914,3 +916,58 @@ nm_utils_print(int output_mode, const char *msg)
else
g_return_if_reached();
}
/*****************************************************************************/
/**
* 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)
{
g_return_val_if_fail(filename != NULL, FALSE);
return nm_crypto_utils_file_is_certificate(filename);
}
/**
* 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)
{
g_return_val_if_fail(filename != NULL, FALSE);
return nm_crypto_utils_file_is_private_key(filename, out_encrypted);
}
/**
* nm_utils_file_is_pkcs12:
* @filename: name of the file to test
*
* 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 nm_crypto_is_pkcs12_file(filename, NULL);
}

View File

@@ -496,6 +496,10 @@ gboolean nm_client_dbus_set_property_finish(NMClient *client, GAsyncResult *resu
NM_AVAILABLE_IN_1_30
void nm_utils_print(int output_mode, const char *msg);
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);
G_END_DECLS
#endif /* __NM_CLIENT_H__ */

View File

@@ -17,7 +17,6 @@
#include <linux/pkt_sched.h>
#include <linux/if_infiniband.h>
#include "libnm-crypto/nm-crypto.h"
#include "libnm-glib-aux/nm-uuid.h"
#include "libnm-glib-aux/nm-json-aux.h"
#include "libnm-glib-aux/nm-str-buf.h"
@@ -3083,94 +3082,6 @@ nm_utils_uuid_generate(void)
/*****************************************************************************/
static gboolean
file_has_extension(const char *filename, const char *extensions[])
{
const char *ext;
gsize 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;
g_return_val_if_fail(filename != NULL, FALSE);
if (!file_has_extension(filename, extensions))
return FALSE;
if (!nm_crypto_load_and_verify_certificate(filename, &file_format, NULL, NULL))
return FALSE;
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);
NM_SET_OUT(out_encrypted, FALSE);
if (!file_has_extension(filename, extensions))
return FALSE;
return nm_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
*
* 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 nm_crypto_is_pkcs12_file(filename, NULL);
}
/*****************************************************************************/
gboolean
_nm_utils_check_file(const char *filename,
gint64 check_owner,

View File

@@ -92,7 +92,7 @@ test_cert(gconstpointer test_data)
nmtst_assert_success(success, error);
g_assert_cmpint(format, ==, NM_CRYPTO_FILE_FORMAT_X509);
g_assert(nm_utils_file_is_certificate(path));
g_assert(nm_crypto_utils_file_is_certificate(path));
}
static void
@@ -106,7 +106,7 @@ test_load_private_key(const char *path,
gs_unref_bytes GBytes *array = NULL;
GError *error = NULL;
g_assert(nm_utils_file_is_private_key(path, &is_encrypted));
g_assert(nm_crypto_utils_file_is_private_key(path, &is_encrypted));
g_assert(is_encrypted);
array = nmtst_crypto_decrypt_openssl_private_key(path, password, &key_type, &error);
@@ -146,7 +146,7 @@ test_load_pkcs12(const char *path, const char *password, int expected_error)
gboolean is_encrypted = FALSE;
GError *error = NULL;
g_assert(nm_utils_file_is_private_key(path, NULL));
g_assert(nm_crypto_utils_file_is_private_key(path, NULL));
format = nm_crypto_verify_private_key(path, password, &is_encrypted, &error);
if (expected_error != -1) {
@@ -167,7 +167,7 @@ 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));
g_assert(nm_crypto_utils_file_is_private_key(path, NULL));
/* We should still get a valid returned crypto file format */
format = nm_crypto_verify_private_key(path, NULL, &is_encrypted, &error);
@@ -201,7 +201,7 @@ test_load_pkcs8(const char *path, const char *password, int expected_error)
gboolean is_encrypted = FALSE;
GError *error = NULL;
g_assert(nm_utils_file_is_private_key(path, NULL));
g_assert(nm_crypto_utils_file_is_private_key(path, NULL));
format = nm_crypto_verify_private_key(path, password, &is_encrypted, &error);
if (expected_error != -1) {
@@ -285,7 +285,7 @@ test_key_decrypted(gconstpointer test_data)
path = g_build_filename(TEST_CERT_DIR, file, NULL);
g_assert(nm_utils_file_is_private_key(path, &is_encrypted));
g_assert(nm_crypto_utils_file_is_private_key(path, &is_encrypted));
g_assert(!is_encrypted);
g_free(path);

View File

@@ -111,10 +111,6 @@ GPtrArray *nm_utils_ip_routes_from_variant(GVariant *value, int family);
char *nm_utils_uuid_generate(void);
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);
typedef gboolean (*NMUtilsFileSearchInPathsPredicate)(const char *filename, gpointer user_data);
struct stat;

View File

@@ -1042,3 +1042,54 @@ nmtst_crypto_rsa_key_encrypt(const guint8 *data,
NM_SET_OUT(out_password, g_strdup(tmp_password));
return nm_secret_buf_to_gbytes_take(ret, ret_len);
}
/*****************************************************************************/
static gboolean
file_has_extension(const char *filename, const char *extensions[])
{
const char *ext;
gsize 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;
}
gboolean
nm_crypto_utils_file_is_certificate(const char *filename)
{
const char *extensions[] = {".der", ".pem", ".crt", ".cer", NULL};
NMCryptoFileFormat file_format;
nm_assert(filename);
if (!file_has_extension(filename, extensions))
return FALSE;
if (!nm_crypto_load_and_verify_certificate(filename, &file_format, NULL, NULL))
return FALSE;
return file_format = NM_CRYPTO_FILE_FORMAT_X509;
}
gboolean
nm_crypto_utils_file_is_private_key(const char *filename, gboolean *out_encrypted)
{
const char *extensions[] = {".der", ".pem", ".p12", ".key", NULL};
nm_assert(filename);
NM_SET_OUT(out_encrypted, FALSE);
if (!file_has_extension(filename, extensions))
return FALSE;
return nm_crypto_verify_private_key(filename, NULL, out_encrypted, NULL)
!= NM_CRYPTO_FILE_FORMAT_UNKNOWN;
}

View File

@@ -93,4 +93,7 @@ guint8 *nmtst_crypto_make_des_aes_key(NMCryptoCipherType cipher,
/*****************************************************************************/
gboolean nm_crypto_utils_file_is_certificate(const char *filename);
gboolean nm_crypto_utils_file_is_private_key(const char *filename, gboolean *out_encrypted);
#endif /* __NM_CRYPTO_H__ */