libnm-core: call crypto_init() on the fly

Rather than requiring crypto_init() to have been called beforehand,
just have every method that depends on it call it itself.

This required adding a GError argument to crypto_is_pkcs12_data(),
which in turn required a few other changes elsewhere.
This commit is contained in:
Dan Winship 2014-12-01 14:13:06 -05:00
parent 48ff21b5bc
commit bddc0de51e
7 changed files with 86 additions and 36 deletions

View file

@ -482,6 +482,9 @@ crypto_decrypt_openssl_private_key_data (const guint8 *data,
if (out_key_type) if (out_key_type)
g_return_val_if_fail (*out_key_type == NM_CRYPTO_KEY_TYPE_UNKNOWN, NULL); g_return_val_if_fail (*out_key_type == NM_CRYPTO_KEY_TYPE_UNKNOWN, NULL);
if (!crypto_init (error))
return NULL;
parsed = parse_old_openssl_key_file (data, data_len, &key_type, &cipher, &iv, NULL); parsed = parse_old_openssl_key_file (data, data_len, &key_type, &cipher, &iv, NULL);
/* return the key type even if decryption failed */ /* return the key type even if decryption failed */
if (out_key_type) if (out_key_type)
@ -527,6 +530,9 @@ crypto_decrypt_openssl_private_key (const char *file,
GByteArray *contents; GByteArray *contents;
GByteArray *key = NULL; GByteArray *key = NULL;
if (!crypto_init (error))
return NULL;
contents = file_to_g_byte_array (file, error); contents = file_to_g_byte_array (file, error);
if (contents) { if (contents) {
key = crypto_decrypt_openssl_private_key_data (contents->data, contents->len, key = crypto_decrypt_openssl_private_key_data (contents->data, contents->len,
@ -594,12 +600,15 @@ crypto_load_and_verify_certificate (const char *file,
g_return_val_if_fail (out_file_format != 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); g_return_val_if_fail (*out_file_format == NM_CRYPTO_FILE_FORMAT_UNKNOWN, NULL);
if (!crypto_init (error))
return NULL;
contents = file_to_g_byte_array (file, error); contents = file_to_g_byte_array (file, error);
if (!contents) if (!contents)
return NULL; return NULL;
/* Check for PKCS#12 */ /* Check for PKCS#12 */
if (crypto_is_pkcs12_data (contents->data, contents->len)) { if (crypto_is_pkcs12_data (contents->data, contents->len, NULL)) {
*out_file_format = NM_CRYPTO_FILE_FORMAT_PKCS12; *out_file_format = NM_CRYPTO_FILE_FORMAT_PKCS12;
return contents; return contents;
} }
@ -628,20 +637,26 @@ crypto_load_and_verify_certificate (const char *file,
gboolean gboolean
crypto_is_pkcs12_data (const guint8 *data, crypto_is_pkcs12_data (const guint8 *data,
gsize data_len) gsize data_len,
GError **error)
{ {
GError *error = NULL; GError *local = NULL;
gboolean success; gboolean success;
g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE);
success = crypto_verify_pkcs12 (data, data_len, NULL, &error); if (!crypto_init (error))
return FALSE;
success = crypto_verify_pkcs12 (data, data_len, NULL, &local);
if (success == FALSE) { if (success == FALSE) {
/* If the error was just a decryption error, then it's pkcs#12 */ /* If the error was just a decryption error, then it's pkcs#12 */
if (error) { if (local) {
if (g_error_matches (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED)) if (g_error_matches (local, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_DECRYPTION_FAILED)) {
success = TRUE; success = TRUE;
g_error_free (error); g_error_free (local);
} else
g_propagate_error (error, local);
} }
} }
return success; return success;
@ -655,9 +670,12 @@ crypto_is_pkcs12_file (const char *file, GError **error)
g_return_val_if_fail (file != NULL, FALSE); g_return_val_if_fail (file != NULL, FALSE);
if (!crypto_init (error))
return FALSE;
contents = file_to_g_byte_array (file, error); contents = file_to_g_byte_array (file, error);
if (contents) { if (contents) {
success = crypto_is_pkcs12_data (contents->data, contents->len); success = crypto_is_pkcs12_data (contents->data, contents->len, error);
g_byte_array_free (contents, TRUE); g_byte_array_free (contents, TRUE);
} }
return success; return success;
@ -681,8 +699,11 @@ crypto_verify_private_key_data (const guint8 *data,
g_return_val_if_fail (data != NULL, NM_CRYPTO_FILE_FORMAT_UNKNOWN); g_return_val_if_fail (data != NULL, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
g_return_val_if_fail (out_is_encrypted == NULL || *out_is_encrypted == FALSE, NM_CRYPTO_FILE_FORMAT_UNKNOWN); g_return_val_if_fail (out_is_encrypted == NULL || *out_is_encrypted == FALSE, NM_CRYPTO_FILE_FORMAT_UNKNOWN);
if (!crypto_init (error))
return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
/* Check for PKCS#12 first */ /* Check for PKCS#12 first */
if (crypto_is_pkcs12_data (data, data_len)) { if (crypto_is_pkcs12_data (data, data_len, NULL)) {
is_encrypted = TRUE; is_encrypted = TRUE;
if (!password || crypto_verify_pkcs12 (data, data_len, password, error)) if (!password || crypto_verify_pkcs12 (data, data_len, password, error))
format = NM_CRYPTO_FILE_FORMAT_PKCS12; format = NM_CRYPTO_FILE_FORMAT_PKCS12;
@ -727,7 +748,10 @@ crypto_verify_private_key (const char *filename,
GByteArray *contents; GByteArray *contents;
NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
g_return_val_if_fail (filename != NULL, FALSE); 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); contents = file_to_g_byte_array (filename, error);
if (contents) { if (contents) {

View file

@ -63,7 +63,7 @@ GByteArray *crypto_load_and_verify_certificate (const char *file,
gboolean crypto_is_pkcs12_file (const char *file, GError **error); gboolean crypto_is_pkcs12_file (const char *file, GError **error);
gboolean crypto_is_pkcs12_data (const guint8 *data, gsize len); gboolean crypto_is_pkcs12_data (const guint8 *data, gsize len, GError **error);
NMCryptoFileFormat crypto_verify_private_key_data (const guint8 *data, NMCryptoFileFormat crypto_verify_private_key_data (const guint8 *data,
gsize data_len, gsize data_len,

View file

@ -75,6 +75,9 @@ crypto_decrypt (const char *cipher,
gboolean success = FALSE; gboolean success = FALSE;
gsize pad_len, real_iv_len; gsize pad_len, real_iv_len;
if (!crypto_init (error))
return NULL;
if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
cipher_mech = GCRY_CIPHER_3DES; cipher_mech = GCRY_CIPHER_3DES;
real_iv_len = SALT_LEN; real_iv_len = SALT_LEN;
@ -196,6 +199,9 @@ crypto_encrypt (const char *cipher,
guint32 i; guint32 i;
gsize salt_len; gsize salt_len;
if (!crypto_init (error))
return NULL;
if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
cipher_mech = GCRY_CIPHER_3DES; cipher_mech = GCRY_CIPHER_3DES;
salt_len = SALT_LEN; salt_len = SALT_LEN;
@ -291,6 +297,9 @@ crypto_verify_cert (const unsigned char *data,
gnutls_datum_t dt; gnutls_datum_t dt;
int err; int err;
if (!crypto_init (error))
return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
err = gnutls_x509_crt_init (&der); err = gnutls_x509_crt_init (&der);
if (err < 0) { if (err < 0) {
g_set_error (error, NM_CRYPTO_ERROR, g_set_error (error, NM_CRYPTO_ERROR,
@ -335,6 +344,9 @@ crypto_verify_pkcs12 (const guint8 *data,
g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE);
if (!crypto_init (error))
return FALSE;
dt.data = (unsigned char *) data; dt.data = (unsigned char *) data;
dt.size = data_len; dt.size = data_len;
@ -389,6 +401,9 @@ crypto_verify_pkcs8 (const guint8 *data,
g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE);
if (!crypto_init (error))
return FALSE;
dt.data = (unsigned char *) data; dt.data = (unsigned char *) data;
dt.size = data_len; dt.size = data_len;
@ -431,6 +446,9 @@ crypto_verify_pkcs8 (const guint8 *data,
gboolean gboolean
crypto_randomize (void *buffer, gsize buffer_len, GError **error) crypto_randomize (void *buffer, gsize buffer_len, GError **error)
{ {
if (!crypto_init (error))
return FALSE;
gcry_randomize (buffer, buffer_len, GCRY_STRONG_RANDOM); gcry_randomize (buffer, buffer_len, GCRY_STRONG_RANDOM);
return TRUE; return TRUE;
} }

View file

@ -97,6 +97,9 @@ crypto_decrypt (const char *cipher,
unsigned int pad_len = 0, extra = 0; unsigned int pad_len = 0, extra = 0;
guint32 i, real_iv_len = 0; guint32 i, real_iv_len = 0;
if (!crypto_init (error))
return NULL;
if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
cipher_mech = CKM_DES3_CBC_PAD; cipher_mech = CKM_DES3_CBC_PAD;
real_iv_len = 8; real_iv_len = 8;
@ -264,6 +267,9 @@ crypto_encrypt (const char *cipher,
gboolean success = FALSE; gboolean success = FALSE;
gsize padded_buf_len, pad_len; gsize padded_buf_len, pad_len;
if (!crypto_init (error))
return NULL;
if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) if (!strcmp (cipher, CIPHER_DES_EDE3_CBC))
cipher_mech = CKM_DES3_CBC_PAD; cipher_mech = CKM_DES3_CBC_PAD;
else if (!strcmp (cipher, CIPHER_AES_CBC)) else if (!strcmp (cipher, CIPHER_AES_CBC))
@ -368,6 +374,9 @@ crypto_verify_cert (const unsigned char *data,
{ {
CERTCertificate *cert; CERTCertificate *cert;
if (!crypto_init (error))
return NM_CRYPTO_FILE_FORMAT_UNKNOWN;
/* Try DER/PEM first */ /* Try DER/PEM first */
cert = CERT_DecodeCertFromPackage ((char *) data, len); cert = CERT_DecodeCertFromPackage ((char *) data, len);
if (!cert) { if (!cert) {
@ -401,6 +410,9 @@ crypto_verify_pkcs12 (const guint8 *data,
if (error) if (error)
g_return_val_if_fail (*error == NULL, FALSE); g_return_val_if_fail (*error == NULL, FALSE);
if (!crypto_init (error))
return FALSE;
/* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do /* PKCS#12 passwords are apparently UCS2 BIG ENDIAN, and NSS doesn't do
* any conversions for us. * any conversions for us.
*/ */
@ -485,6 +497,9 @@ crypto_verify_pkcs8 (const guint8 *data,
{ {
g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE);
if (!crypto_init (error))
return FALSE;
/* NSS apparently doesn't do PKCS#8 natively, but you have to put the /* NSS apparently doesn't do PKCS#8 natively, but you have to put the
* PKCS#8 key into a PKCS#12 file and import that?? So until we figure * PKCS#8 key into a PKCS#12 file and import that?? So until we figure
* all that out, we can only assume the password is valid. * all that out, we can only assume the password is valid.
@ -497,6 +512,9 @@ crypto_randomize (void *buffer, gsize buffer_len, GError **error)
{ {
SECStatus s; SECStatus s;
if (!crypto_init (error))
return FALSE;
s = PK11_GenerateRandom (buffer, buffer_len); s = PK11_GenerateRandom (buffer, buffer_len);
if (s != SECSuccess) { if (s != SECSuccess) {
g_set_error_literal (error, NM_CRYPTO_ERROR, g_set_error_literal (error, NM_CRYPTO_ERROR,

View file

@ -1871,15 +1871,15 @@ nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting)
switch (nm_setting_802_1x_get_private_key_scheme (setting)) { switch (nm_setting_802_1x_get_private_key_scheme (setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB: case NM_SETTING_802_1X_CK_SCHEME_BLOB:
if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL), if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL),
g_bytes_get_size (priv->private_key))) g_bytes_get_size (priv->private_key),
NULL))
return NM_SETTING_802_1X_CK_FORMAT_PKCS12; return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
case NM_SETTING_802_1X_CK_SCHEME_PATH: case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_private_key_path (setting); path = nm_setting_802_1x_get_private_key_path (setting);
if (crypto_is_pkcs12_file (path, &error)) if (crypto_is_pkcs12_file (path, &error))
return NM_SETTING_802_1X_CK_FORMAT_PKCS12; return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
if (error) { if (error && error->domain == G_FILE_ERROR) {
/* Couldn't read the file or something */
g_error_free (error); g_error_free (error);
return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
} }
@ -2151,15 +2151,15 @@ nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting)
switch (nm_setting_802_1x_get_phase2_private_key_scheme (setting)) { switch (nm_setting_802_1x_get_phase2_private_key_scheme (setting)) {
case NM_SETTING_802_1X_CK_SCHEME_BLOB: case NM_SETTING_802_1X_CK_SCHEME_BLOB:
if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL), if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL),
g_bytes_get_size (priv->phase2_private_key))) g_bytes_get_size (priv->phase2_private_key),
NULL))
return NM_SETTING_802_1X_CK_FORMAT_PKCS12; return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY;
case NM_SETTING_802_1X_CK_SCHEME_PATH: case NM_SETTING_802_1X_CK_SCHEME_PATH:
path = nm_setting_802_1x_get_phase2_private_key_path (setting); path = nm_setting_802_1x_get_phase2_private_key_path (setting);
if (crypto_is_pkcs12_file (path, &error)) if (crypto_is_pkcs12_file (path, &error))
return NM_SETTING_802_1X_CK_FORMAT_PKCS12; return NM_SETTING_802_1X_CK_FORMAT_PKCS12;
if (error) { if (error && error->domain == G_FILE_ERROR) {
/* Couldn't read the file or something */
g_error_free (error); g_error_free (error);
return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
} }
@ -2300,7 +2300,8 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error)
/* If the private key is PKCS#12, check that it matches the client cert */ /* If the private key is PKCS#12, check that it matches the client cert */
if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL), if (crypto_is_pkcs12_data (g_bytes_get_data (priv->phase2_private_key, NULL),
g_bytes_get_size (priv->phase2_private_key))) { g_bytes_get_size (priv->phase2_private_key),
NULL)) {
if (!g_bytes_equal (priv->phase2_private_key, priv->phase2_client_cert)) { if (!g_bytes_equal (priv->phase2_private_key, priv->phase2_client_cert)) {
g_set_error (error, g_set_error (error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
@ -2347,7 +2348,8 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error)
/* If the private key is PKCS#12, check that it matches the client cert */ /* If the private key is PKCS#12, check that it matches the client cert */
if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL), if (crypto_is_pkcs12_data (g_bytes_get_data (priv->private_key, NULL),
g_bytes_get_size (priv->private_key))) { g_bytes_get_size (priv->private_key),
NULL)) {
if (!g_bytes_equal (priv->private_key, priv->client_cert)) { if (!g_bytes_equal (priv->private_key, priv->client_cert)) {
g_set_error (error, g_set_error (error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
@ -3078,7 +3080,6 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (setting_class); GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
GError *error = NULL;
g_type_class_add_private (setting_class, sizeof (NMSetting8021xPrivate)); g_type_class_add_private (setting_class, sizeof (NMSetting8021xPrivate));
@ -3859,11 +3860,4 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
/* Initialize crypto lbrary. */
if (!nm_utils_init (&error)) {
g_warning ("Couldn't initilize nm-utils/crypto system: %d %s",
error->code, error->message);
g_error_free (error);
}
} }

View file

@ -244,9 +244,6 @@ nm_utils_init (GError **error)
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
if (!crypto_init (error))
return FALSE;
_nm_dbus_errors_init (); _nm_dbus_errors_init ();
} }
return TRUE; return TRUE;

View file

@ -221,15 +221,14 @@ test_is_pkcs12 (const char *path, gboolean expect_fail)
GError *error = NULL; GError *error = NULL;
is_pkcs12 = crypto_is_pkcs12_file (path, &error); is_pkcs12 = crypto_is_pkcs12_file (path, &error);
/* crypto_is_pkcs12_file() only returns an error if it couldn't read the
* file, which we don't expect to happen here.
*/
g_assert_no_error (error);
if (expect_fail) if (expect_fail) {
g_assert_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERROR_INVALID_DATA);
g_assert (!is_pkcs12); g_assert (!is_pkcs12);
else } else {
g_assert_no_error (error);
g_assert (is_pkcs12); g_assert (is_pkcs12);
}
} }
static void static void