libnm/crypto: clear data loaded from files
Data that we load from crypto files should be cleared once it's no longer used. Just a small step. There are many other places where we copy the data and leave it around.
This commit is contained in:
@@ -49,6 +49,21 @@
|
||||
#define PEM_PKCS8_DEC_KEY_BEGIN "-----BEGIN PRIVATE KEY-----"
|
||||
#define PEM_PKCS8_DEC_KEY_END "-----END PRIVATE KEY-----"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static GByteArray *
|
||||
to_gbyte_array_mem (gconstpointer mem, gsize len)
|
||||
{
|
||||
GByteArray *arr;
|
||||
|
||||
arr = g_byte_array_sized_new (len);
|
||||
if (len > 0)
|
||||
g_byte_array_append (arr, mem, len);
|
||||
return arr;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
find_tag (const char *tag,
|
||||
const guint8 *data,
|
||||
@@ -295,19 +310,16 @@ parse_pkcs8_key_file (const guint8 *data,
|
||||
return key;
|
||||
}
|
||||
|
||||
static GByteArray *
|
||||
file_to_g_byte_array (const char *filename, GError **error)
|
||||
static gboolean
|
||||
file_read_contents (const char *filename,
|
||||
NMSecretPtr *out_contents,
|
||||
GError **error)
|
||||
{
|
||||
gs_free char *contents = NULL;
|
||||
GByteArray *array = NULL;
|
||||
gsize length = 0;
|
||||
nm_assert (out_contents);
|
||||
nm_assert (out_contents->len == 0);
|
||||
nm_assert (!out_contents->str);
|
||||
|
||||
if (!g_file_get_contents (filename, &contents, &length, error))
|
||||
return NULL;
|
||||
|
||||
array = g_byte_array_sized_new (length);
|
||||
g_byte_array_append (array, (guint8 *) contents, length);
|
||||
return array;
|
||||
return g_file_get_contents (filename, &out_contents->str, &out_contents->len, error);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -520,61 +532,66 @@ nmtst_crypto_decrypt_openssl_private_key (const char *file,
|
||||
NMCryptoKeyType *out_key_type,
|
||||
GError **error)
|
||||
{
|
||||
nm_auto_unref_bytearray GByteArray *contents = NULL;
|
||||
nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
|
||||
|
||||
if (!crypto_init (error))
|
||||
return NULL;
|
||||
|
||||
contents = file_to_g_byte_array (file, error);
|
||||
if (!contents)
|
||||
if (!file_read_contents (file, &contents, error))
|
||||
return NULL;
|
||||
|
||||
return nmtst_crypto_decrypt_openssl_private_key_data (contents->data, contents->len,
|
||||
password, out_key_type, error);
|
||||
return nmtst_crypto_decrypt_openssl_private_key_data (contents.bin,
|
||||
contents.len,
|
||||
password,
|
||||
out_key_type,
|
||||
error);
|
||||
}
|
||||
|
||||
static GByteArray *
|
||||
extract_pem_cert_data (GByteArray *contents, GError **error)
|
||||
static gboolean
|
||||
extract_pem_cert_data (const guint8 *contents,
|
||||
gsize contents_len,
|
||||
NMSecretPtr *out_cert,
|
||||
GError **error)
|
||||
{
|
||||
GByteArray *cert = NULL;
|
||||
gsize start = 0, end = 0;
|
||||
gs_free unsigned char *der = NULL;
|
||||
guint8 save_end;
|
||||
gsize length = 0;
|
||||
gsize start = 0;
|
||||
gsize end = 0;
|
||||
nm_auto_free_secret char *der_base64 = NULL;
|
||||
|
||||
if (!find_tag (PEM_CERT_BEGIN, contents->data, contents->len, 0, &start)) {
|
||||
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 NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
start += strlen (PEM_CERT_BEGIN);
|
||||
if (!find_tag (PEM_CERT_END, contents->data, contents->len, start, &end)) {
|
||||
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 NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
der_base64 = g_strndup ((const char *) &contents[start], end - start);
|
||||
|
||||
if (!der || !length) {
|
||||
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."));
|
||||
return NULL;
|
||||
nm_secret_ptr_clear (out_cert);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cert = g_byte_array_sized_new (length);
|
||||
g_byte_array_append (cert, der, length);
|
||||
return cert;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GByteArray *
|
||||
@@ -582,42 +599,41 @@ crypto_load_and_verify_certificate (const char *file,
|
||||
NMCryptoFileFormat *out_file_format,
|
||||
GError **error)
|
||||
{
|
||||
nm_auto_unref_bytearray GByteArray *contents = NULL;
|
||||
nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
|
||||
|
||||
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);
|
||||
|
||||
*out_file_format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
|
||||
|
||||
if (!crypto_init (error))
|
||||
return NULL;
|
||||
|
||||
contents = file_to_g_byte_array (file, error);
|
||||
if (!contents)
|
||||
if (!file_read_contents (file, &contents, error))
|
||||
return NULL;
|
||||
|
||||
/* Check for PKCS#12 */
|
||||
if (crypto_is_pkcs12_data (contents->data, contents->len, NULL)) {
|
||||
if (crypto_is_pkcs12_data (contents.bin, contents.len, NULL)) {
|
||||
*out_file_format = NM_CRYPTO_FILE_FORMAT_PKCS12;
|
||||
return g_steal_pointer (&contents);
|
||||
return to_gbyte_array_mem (contents.bin, contents.len);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (contents.len > 2 && contents.bin[0] == 0x30 && contents.bin[1] == 0x82) {
|
||||
*out_file_format = crypto_verify_cert (contents.bin, contents.len, error);
|
||||
} else {
|
||||
nm_auto_unref_bytearray GByteArray *array = NULL;
|
||||
nm_auto_clear_secret_ptr NMSecretPtr pem_cert = { 0 };
|
||||
|
||||
array = extract_pem_cert_data (contents, error);
|
||||
if (!array)
|
||||
if (!extract_pem_cert_data (contents.bin, contents.len, &pem_cert, error))
|
||||
return NULL;
|
||||
|
||||
*out_file_format = crypto_verify_cert (array->data, array->len, error);
|
||||
*out_file_format = crypto_verify_cert (pem_cert.bin, pem_cert.len, error);
|
||||
}
|
||||
|
||||
if (*out_file_format != NM_CRYPTO_FILE_FORMAT_X509)
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer (&contents);
|
||||
return to_gbyte_array_mem (contents.bin, contents.len);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -653,18 +669,17 @@ crypto_is_pkcs12_data (const guint8 *data,
|
||||
gboolean
|
||||
crypto_is_pkcs12_file (const char *file, GError **error)
|
||||
{
|
||||
nm_auto_unref_bytearray GByteArray *contents = NULL;
|
||||
nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
|
||||
|
||||
g_return_val_if_fail (file != NULL, FALSE);
|
||||
|
||||
if (!crypto_init (error))
|
||||
return FALSE;
|
||||
|
||||
contents = file_to_g_byte_array (file, error);
|
||||
if (!contents)
|
||||
if (!file_read_contents (file, &contents, error))
|
||||
return FALSE;
|
||||
|
||||
return crypto_is_pkcs12_data (contents->data, contents->len, error);
|
||||
return crypto_is_pkcs12_data (contents.bin, contents.len, error);
|
||||
}
|
||||
|
||||
/* Verifies that a private key can be read, and if a password is given, that
|
||||
@@ -730,18 +745,17 @@ crypto_verify_private_key (const char *filename,
|
||||
gboolean *out_is_encrypted,
|
||||
GError **error)
|
||||
{
|
||||
nm_auto_unref_bytearray GByteArray *contents = NULL;
|
||||
nm_auto_clear_secret_ptr NMSecretPtr contents = { 0 };
|
||||
|
||||
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)
|
||||
if (!file_read_contents (filename, &contents, error))
|
||||
return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
|
||||
|
||||
return crypto_verify_private_key_data (contents->data, contents->len, password, out_is_encrypted, error);
|
||||
return crypto_verify_private_key_data (contents.bin, contents.len, password, out_is_encrypted, error);
|
||||
}
|
||||
|
||||
void
|
||||
|
Reference in New Issue
Block a user