diff options
Diffstat (limited to 'libnm-util/nm-setting-8021x.c')
| -rw-r--r-- | libnm-util/nm-setting-8021x.c | 1069 |
1 files changed, 367 insertions, 702 deletions
diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c index eea6ba5e..4cd22016 100644 --- a/libnm-util/nm-setting-8021x.c +++ b/libnm-util/nm-setting-8021x.c @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -32,6 +32,7 @@ #include "nm-dbus-glib-types.h" #include "crypto.h" #include "nm-utils-private.h" +#include "nm-setting-private.h" /** * SECTION:nm-setting-8021x @@ -125,12 +126,15 @@ typedef struct { char *phase2_ca_path; GByteArray *phase2_client_cert; char *password; + NMSettingSecretFlags password_flags; char *pin; - char *psk; + NMSettingSecretFlags pin_flags; GByteArray *private_key; char *private_key_password; + NMSettingSecretFlags private_key_password_flags; GByteArray *phase2_private_key; char *phase2_private_key_password; + NMSettingSecretFlags phase2_private_key_password_flags; gboolean system_ca_certs; } NMSetting8021xPrivate; @@ -151,12 +155,15 @@ enum { PROP_PHASE2_CA_PATH, PROP_PHASE2_CLIENT_CERT, PROP_PASSWORD, + PROP_PASSWORD_FLAGS, PROP_PRIVATE_KEY, PROP_PRIVATE_KEY_PASSWORD, + PROP_PRIVATE_KEY_PASSWORD_FLAGS, PROP_PHASE2_PRIVATE_KEY, PROP_PHASE2_PRIVATE_KEY_PASSWORD, + PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, PROP_PIN, - PROP_PSK, + PROP_PIN_FLAGS, PROP_SYSTEM_CA_CERTS, LAST_PROP @@ -424,29 +431,6 @@ nm_setting_802_1x_get_ca_cert_blob (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_ca_cert: - * @setting: the #NMSetting8021x - * - * Returns the CA certificate blob if the CA certificate is stored using the - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. Not all EAP methods use a - * CA certificate (LEAP for example), and those that can take advantage of the - * CA certificate allow it to be unset. Note that lack of a CA certificate - * reduces security by allowing man-in-the-middle attacks, because the identity - * of the network cannot be confirmed by the client. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_ca_cert_blob(). - * - * Returns: the CA certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_ca_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_ca_cert_blob (setting); -} - -/** * nm_setting_802_1x_get_ca_cert_path: * @setting: the #NMSetting8021x * @@ -472,6 +456,22 @@ nm_setting_802_1x_get_ca_cert_path (NMSetting8021x *setting) return (const char *) (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert->data + strlen (SCHEME_PATH)); } +static GByteArray * +path_to_scheme_value (const char *path) +{ + GByteArray *array; + + g_return_val_if_fail (path != NULL, NULL); + + /* Add the path scheme tag to the front, then the fielname */ + array = g_byte_array_sized_new (strlen (path) + strlen (SCHEME_PATH) + 1); + g_assert (array); + g_byte_array_append (array, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); + g_byte_array_append (array, (const guint8 *) path, strlen (path)); + g_byte_array_append (array, (const guint8 *) "\0", 1); + return array; +} + /** * nm_setting_802_1x_set_ca_cert: * @setting: the #NMSetting8021x @@ -546,13 +546,9 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self, if (data) { if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) priv->ca_cert = data; - else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - /* Add the path scheme tag to the front, then the fielname */ - priv->ca_cert = g_byte_array_sized_new (strlen (value) + strlen (SCHEME_PATH) + 1); - g_byte_array_append (priv->ca_cert, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (priv->ca_cert, (const guint8 *) value, strlen (value)); - g_byte_array_append (priv->ca_cert, (const guint8 *) "\0", 1); - } else + else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->ca_cert = path_to_scheme_value (value); + else g_assert_not_reached (); } } @@ -560,61 +556,6 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self, return priv->ca_cert != NULL; } -static NMSetting8021xCKType -ck_format_to_type (NMSetting8021xCKFormat format) -{ - switch (format) { - case NM_SETTING_802_1X_CK_FORMAT_X509: - return NM_SETTING_802_1X_CK_TYPE_X509; - case NM_SETTING_802_1X_CK_FORMAT_RAW_KEY: - return NM_SETTING_802_1X_CK_TYPE_RAW_KEY; - case NM_SETTING_802_1X_CK_FORMAT_PKCS12: - return NM_SETTING_802_1X_CK_TYPE_PKCS12; - default: - break; - } - return NM_SETTING_802_1X_CK_TYPE_UNKNOWN; -} - -/** - * nm_setting_802_1x_set_ca_cert_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the CA certificate file (PEM or DER format). Passing - * NULL clears the CA certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:ca-cert property - * with the raw certificate data using the %NM_SETTING_802_1X_CK_SCHEME_BLOB - * scheme. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_ca_cert() with the - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_ca_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_ca_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - /** * nm_setting_802_1x_get_client_cert_scheme: * @setting: the #NMSetting8021x @@ -657,26 +598,6 @@ nm_setting_802_1x_get_client_cert_blob (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_client_cert: - * @setting: the #NMSetting8021x - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_client_cert_blob(). - * - * Returns: the client certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_client_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_client_cert_blob (setting); -} - -/** * nm_setting_802_1x_get_client_cert_path: * @setting: the #NMSetting8021x * @@ -781,13 +702,9 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *self, if (data) { if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) priv->client_cert = data; - else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - /* Add the path scheme tag to the front, then the fielname */ - priv->client_cert = g_byte_array_sized_new (strlen (value) + strlen (SCHEME_PATH) + 1); - g_byte_array_append (priv->client_cert, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (priv->client_cert, (const guint8 *) value, strlen (value)); - g_byte_array_append (priv->client_cert, (const guint8 *) "\0", 1); - } else + else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->client_cert = path_to_scheme_value (value); + else g_assert_not_reached (); } } @@ -796,48 +713,6 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *self, } /** - * nm_setting_802_1x_set_client_cert_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the client certificate file (PEM, DER, or - * PKCS#12 format). Passing NULL clears the client certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:client-cert - * property with the raw certificate data. - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_client_cert() with the - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_client_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_client_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - -/** * nm_setting_802_1x_get_phase1_peapver: * @setting: the #NMSetting8021x * @@ -983,28 +858,6 @@ nm_setting_802_1x_get_phase2_ca_cert_blob (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_phase2_ca_cert: - * @setting: the #NMSetting8021x - * - * Returns the "phase 2" CA certificate blob. Not all EAP methods use - * a CA certificate (LEAP for example), and those that can take advantage of the - * CA certificate allow it to be unset. Note that lack of a CA certificate - * reduces security by allowing man-in-the-middle attacks, because the identity - * of the network cannot be confirmed by the client. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_phase2_ca_cert_blob(). - * - * Returns: the "phase 2" CA certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_phase2_ca_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_phase2_ca_cert_blob (setting); -} - -/** * nm_setting_802_1x_get_phase2_ca_cert_path: * @setting: the #NMSetting8021x * @@ -1104,13 +957,9 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self, if (data) { if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) priv->phase2_ca_cert = data; - else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - /* Add the path scheme tag to the front, then the fielname */ - priv->phase2_ca_cert = g_byte_array_sized_new (strlen (value) + strlen (SCHEME_PATH) + 1); - g_byte_array_append (priv->phase2_ca_cert, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (priv->phase2_ca_cert, (const guint8 *) value, strlen (value)); - g_byte_array_append (priv->phase2_ca_cert, (const guint8 *) "\0", 1); - } else + else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->phase2_ca_cert = path_to_scheme_value (value); + else g_assert_not_reached (); } } @@ -1119,44 +968,6 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self, } /** - * nm_setting_802_1x_set_phase2_ca_cert_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the "phase2" CA certificate file (PEM or DER format). - * Passing NULL with any @scheme clears the "phase2" CA certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:phase2-ca-cert - * property with the raw certificate data. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_phase2_ca_cert(). - * with the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_phase2_ca_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_phase2_ca_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - -/** * nm_setting_802_1x_get_phase2_client_cert_scheme: * @setting: the #NMSetting8021x * @@ -1200,26 +1011,6 @@ nm_setting_802_1x_get_phase2_client_cert_blob (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_phase2_client_cert: - * @setting: the #NMSetting8021x - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_phase2_client_cert_blob(). - * - * Returns: the "phase 2" client certificate data - **/ -const GByteArray * -nm_setting_802_1x_get_phase2_client_cert (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_phase2_client_cert_blob (setting); -} - -/** * nm_setting_802_1x_get_phase2_client_cert_path: * @setting: the #NMSetting8021x * @@ -1324,13 +1115,9 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self, if (data) { if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) priv->phase2_client_cert = data; - else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - /* Add the path scheme tag to the front, then the fielname */ - priv->phase2_client_cert = g_byte_array_sized_new (strlen (value) + strlen (SCHEME_PATH) + 1); - g_byte_array_append (priv->phase2_client_cert, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (priv->phase2_client_cert, (const guint8 *) value, strlen (value)); - g_byte_array_append (priv->phase2_client_cert, (const guint8 *) "\0", 1); - } else + else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->phase2_client_cert = path_to_scheme_value (value); + else g_assert_not_reached (); } } @@ -1339,60 +1126,32 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self, } /** - * nm_setting_802_1x_set_phase2_client_cert_from_file: + * nm_setting_802_1x_get_password: * @setting: the #NMSetting8021x - * @filename: pass the path of the "phase2" client certificate file (PEM, DER, - * or PKCS#12 format). Passing NULL clears the "phase2" client certificate. - * @out_ck_type: on successful return, the type of the certificate added - * @error: on unsuccessful return, an error - * - * Reads a certificate from disk and sets the #NMSetting8021x:phase2-client-cert - * property with the raw certificate data. - * - * Client certificates are used to identify the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_phase2_client_cert() with the. - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful + * Returns: the password used by the authentication method, if any, as specified + * by the #NMSetting8021x:password property **/ -gboolean -nm_setting_802_1x_set_phase2_client_cert_from_file (NMSetting8021x *setting, - const char *filename, - NMSetting8021xCKType *out_ck_type, - GError **error) +const char * +nm_setting_802_1x_get_password (NMSetting8021x *setting) { - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_phase2_client_cert (setting, - filename, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); - return success; + return NM_SETTING_802_1X_GET_PRIVATE (setting)->password; } /** - * nm_setting_802_1x_get_password: + * nm_setting_802_1x_get_password_flags: * @setting: the #NMSetting8021x * - * Returns: the password used by the authentication method, if any, as specified - * by the #NMSetting8021x:password property + * Returns: the #NMSettingSecretFlags pertaining to the #NMSetting8021x:password **/ -const char * -nm_setting_802_1x_get_password (NMSetting8021x *setting) +NMSettingSecretFlags +nm_setting_802_1x_get_password_flags (NMSetting8021x *setting) { - g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); - return NM_SETTING_802_1X_GET_PRIVATE (setting)->password; + return NM_SETTING_802_1X_GET_PRIVATE (setting)->password_flags; } /** @@ -1411,18 +1170,18 @@ nm_setting_802_1x_get_pin (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_psk: + * nm_setting_802_1x_get_pin_flags: * @setting: the #NMSetting8021x * - * Returns: the Pre-Shared-Key used by the authentication method, if any, as - * specified by the #NMSetting8021x:psk property + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:pin **/ -const char * -nm_setting_802_1x_get_psk (NMSetting8021x *setting) +NMSettingSecretFlags +nm_setting_802_1x_get_pin_flags (NMSetting8021x *setting) { - g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); - return NM_SETTING_802_1X_GET_PRIVATE (setting)->psk; + return NM_SETTING_802_1X_GET_PRIVATE (setting)->pin_flags; } /** @@ -1453,6 +1212,10 @@ nm_setting_802_1x_get_private_key_scheme (NMSetting8021x *setting) * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * WARNING: the private key property is not a "secret" property, and thus + * unencrypted private key data may be readable by unprivileged users. Private + * keys should always be encrypted with a private key password. + * * Returns: the private key data **/ const GByteArray * @@ -1469,26 +1232,6 @@ nm_setting_802_1x_get_private_key_blob (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_private_key: - * @setting: the #NMSetting8021x - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_private_key_blob(). - * - * Returns: the private key data - **/ -const GByteArray * -nm_setting_802_1x_get_private_key (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_private_key_blob (setting); -} - -/** * nm_setting_802_1x_get_private_key_path: * @setting: the #NMSetting8021x * @@ -1511,6 +1254,24 @@ nm_setting_802_1x_get_private_key_path (NMSetting8021x *setting) return (const char *) (NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key->data + strlen (SCHEME_PATH)); } +static GByteArray * +file_to_byte_array (const char *filename) +{ + char *contents; + GByteArray *array = NULL; + gsize length = 0; + + if (g_file_get_contents (filename, &contents, &length, NULL)) { + array = g_byte_array_sized_new (length); + if (array) { + g_byte_array_append (array, (guint8 *) contents, length); + g_assert (array->len == length); + } + g_free (contents); + } + return array; +} + /** * nm_setting_802_1x_set_private_key: * @setting: the #NMSetting8021x @@ -1519,20 +1280,35 @@ nm_setting_802_1x_get_private_key_path (NMSetting8021x *setting) * (PEM, DER, or PKCS#12 format). The path must be UTF-8 encoded; use * g_filename_to_utf8() to convert if needed. Passing NULL with any @scheme * clears the private key. - * @password: password used to decrypt the private key + * @password: password used to decrypt the private key, or %NULL if the password + * is unknown. If the password is given but fails to decrypt the private key, + * an error is returned. * @scheme: desired storage scheme for the private key * @out_format: on successful return, the type of the private key added * @error: on unsuccessful return, an error * - * Reads a private key from disk and sets the #NMSetting8021x:private-key - * property with the raw private key data if using the - * %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the private key - * file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. - * * Private keys are used to authenticate the connecting client to the network * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * This function reads a private key from disk and sets the + * #NMSetting8021x:private-key property with the private key file data if using + * the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the private + * key file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * If @password is given, this function attempts to decrypt the private key to + * verify that @password is correct, and if it is, updates the + * #NMSetting8021x:private-key-password property with the given @password. If + * the decryption is unsuccessful, %FALSE is returned, @error is set, and no + * internal data is changed. If no @password is given, the private key is + * assumed to be valid, no decryption is performed, and the password may be set + * at a later time. + * + * WARNING: the private key property is not a "secret" property, and thus + * unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a private + * key password to prevent unauthorized access to unencrypted private key data. + * * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful **/ gboolean @@ -1545,8 +1321,6 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self, { NMSetting8021xPrivate *priv; NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; - NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN; - GByteArray *data; g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE); @@ -1560,12 +1334,26 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self, if (out_format) g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + /* Ensure the private key is a recognized format and if the password was + * given, that it decrypts the private key. + */ + if (value) { + format = crypto_verify_private_key (value, password, NULL); + if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, + NM_SETTING_802_1X_PRIVATE_KEY); + return FALSE; + } + } + priv = NM_SETTING_802_1X_GET_PRIVATE (self); - /* Clear out any previous private key blob */ + /* Clear out any previous private key data */ if (priv->private_key) { /* Try not to leave the private key around in memory */ - memset (priv->private_key, 0, priv->private_key->len); + memset (priv->private_key->data, 0, priv->private_key->len); g_byte_array_free (priv->private_key, TRUE); priv->private_key = NULL; } @@ -1573,81 +1361,23 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self, g_free (priv->private_key_password); priv->private_key_password = NULL; - if (!value) + if (value == NULL) return TRUE; - /* Verify the key and the private key password */ - data = crypto_get_private_key (value, - password, - &key_type, - &format, - error); - if (!data) { - /* As a special case for private keys, even if the decrypt fails, - * return the key's file type. - */ - if (out_format && crypto_is_pkcs12_file (value, NULL)) - *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12; - - return FALSE; - } - - switch (format) { - case NM_CRYPTO_FILE_FORMAT_RAW_KEY: - if (out_format) - *out_format = NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; - break; - case NM_CRYPTO_FILE_FORMAT_X509: - if (out_format) - *out_format = NM_SETTING_802_1X_CK_FORMAT_X509; - break; - case NM_CRYPTO_FILE_FORMAT_PKCS12: - if (out_format) - *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12; - break; - default: - memset (data->data, 0, data->len); - g_byte_array_free (data, TRUE); - g_set_error (error, - NM_SETTING_802_1X_ERROR, - NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, - NM_SETTING_802_1X_PRIVATE_KEY); - return FALSE; - } - - g_assert (data); + priv->private_key_password = g_strdup (password); if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { - priv->private_key = data; - data = NULL; - - /* Always update the private key for blob + pkcs12 since the - * pkcs12 files are encrypted - */ - if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) - priv->private_key_password = g_strdup (password); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - /* Add the path scheme tag to the front, then the fielname */ - priv->private_key = g_byte_array_sized_new (strlen (value) + strlen (SCHEME_PATH) + 1); - g_byte_array_append (priv->private_key, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (priv->private_key, (const guint8 *) value, strlen (value)); - g_byte_array_append (priv->private_key, (const guint8 *) "\0", 1); - - /* Always update the private key with paths since the key the - * cert refers to is encrypted. - */ - priv->private_key_password = g_strdup (password); - } else + /* Shouldn't fail this since we just verified the private key above */ + priv->private_key = file_to_byte_array (value); + g_assert (priv->private_key); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->private_key = path_to_scheme_value (value); + else g_assert_not_reached (); - /* Clear and free private key data if it's no longer needed */ - if (data) { - memset (data->data, 0, data->len); - g_byte_array_free (data, TRUE); - } - /* As required by NM and wpa_supplicant, set the client-cert * property to the same PKCS#12 data. */ + g_assert (format != NM_CRYPTO_FILE_FORMAT_UNKNOWN); if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) { if (priv->client_cert) g_byte_array_free (priv->client_cert, TRUE); @@ -1656,55 +1386,12 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self, g_byte_array_append (priv->client_cert, priv->private_key->data, priv->private_key->len); } + if (out_format) + *out_format = format; return priv->private_key != NULL; } /** - * nm_setting_802_1x_set_private_key_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the private key file (PEM, DER, or PKCS#12 format). - * Passing NULL clears the private key. - * @password: password used to decrypt the private key - * @out_ck_type: on successful return, the type of the private key added - * @error: on unsuccessful return, an error - * - * Reads a private key from disk and sets the #NMSetting8021x:private-key - * property with the raw private key data. - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_private_key() with. - * the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_private_key_from_file (NMSetting8021x *setting, - const char *filename, - const char *password, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_private_key (setting, - filename, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - -/** * nm_setting_802_1x_get_private_key_password: * @setting: the #NMSetting8021x * @@ -1722,6 +1409,21 @@ nm_setting_802_1x_get_private_key_password (NMSetting8021x *setting) } /** + * nm_setting_802_1x_get_private_key_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:private-key-password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_private_key_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->private_key_password_flags; +} + +/** * nm_setting_802_1x_get_private_key_format: * @setting: the #NMSetting8021x * @@ -1745,7 +1447,7 @@ nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting) case NM_SETTING_802_1X_CK_SCHEME_BLOB: if (crypto_is_pkcs12_data (priv->private_key)) return NM_SETTING_802_1X_CK_FORMAT_PKCS12; - return NM_SETTING_802_1X_CK_FORMAT_X509; + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_private_key_path (setting); if (crypto_is_pkcs12_file (path, &error)) @@ -1755,7 +1457,7 @@ nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting) g_error_free (error); return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; } - return NM_SETTING_802_1X_CK_FORMAT_X509; + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; default: break; } @@ -1764,23 +1466,6 @@ nm_setting_802_1x_get_private_key_format (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_private_key_type: - * @setting: the #NMSetting8021x - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_private_key_format(). - * - * Returns: the data format of the private key data stored in the - * #NMSetting8021x:private-key property - **/ -NMSetting8021xCKType -nm_setting_802_1x_get_private_key_type (NMSetting8021x *setting) -{ - return ck_format_to_type (nm_setting_802_1x_get_private_key_format (setting)); -} - -/** * nm_setting_802_1x_get_phase2_private_key_password: * @setting: the #NMSetting8021x * @@ -1798,6 +1483,21 @@ nm_setting_802_1x_get_phase2_private_key_password (NMSetting8021x *setting) } /** + * nm_setting_802_1x_get_phase2_private_key_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:phase2-private-key-password + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_phase2_private_key_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_private_key_password_flags; +} + +/** * nm_setting_802_1x_get_phase2_private_key_scheme: * @setting: the #NMSetting8021x * @@ -1825,6 +1525,10 @@ nm_setting_802_1x_get_phase2_private_key_scheme (NMSetting8021x *setting) * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * WARNING: the phase2 private key property is not a "secret" property, and thus + * unencrypted private key data may be readable by unprivileged users. Private + * keys should always be encrypted with a private key password. + * * Returns: the "phase 2" private key data **/ const GByteArray * @@ -1841,26 +1545,6 @@ nm_setting_802_1x_get_phase2_private_key_blob (NMSetting8021x *setting) } /** - * nm_setting_802_1x_get_phase2_private_key: - * @setting: the #NMSetting8021x - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_private_key_blob(). - * - * Returns: the "phase 2" private key data - **/ -const GByteArray * -nm_setting_802_1x_get_phase2_private_key (NMSetting8021x *setting) -{ - return nm_setting_802_1x_get_phase2_private_key_blob (setting); -} - -/** * nm_setting_802_1x_get_phase2_private_key_path: * @setting: the #NMSetting8021x * @@ -1887,24 +1571,39 @@ nm_setting_802_1x_get_phase2_private_key_path (NMSetting8021x *setting) * nm_setting_802_1x_set_phase2_private_key: * @setting: the #NMSetting8021x * @value: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or - * %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" private + * %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" private * key file (PEM, DER, or PKCS#12 format). The path must be UTF-8 encoded; * use g_filename_to_utf8() to convert if needed. Passing NULL with any - * @scheme clears the "phase2" private key. - * @password: password used to decrypt the private key + * @scheme clears the private key. + * @password: password used to decrypt the private key, or %NULL if the password + * is unknown. If the password is given but fails to decrypt the private key, + * an error is returned. * @scheme: desired storage scheme for the private key * @out_format: on successful return, the type of the private key added * @error: on unsuccessful return, an error * - * Reads a "phase 2" private key from disk and sets the - * #NMSetting8021x:phase2-private-key property with the raw private key data if - * using the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the - * private key file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. - * * Private keys are used to authenticate the connecting client to the network * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x * authentication method. * + * This function reads a private key from disk and sets the + * #NMSetting8021x:phase2-private-key property with the private key file data if + * using the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme, or with the path to the + * private key file if using the %NM_SETTING_802_1X_CK_SCHEME_PATH scheme. + * + * If @password is given, this function attempts to decrypt the private key to + * verify that @password is correct, and if it is, updates the + * #NMSetting8021x:phase2-private-key-password property with the given + * @password. If the decryption is unsuccessful, %FALSE is returned, @error is + * set, and no internal data is changed. If no @password is given, the private + * key is assumed to be valid, no decryption is performed, and the password may + * be set at a later time. + * + * WARNING: the "phase2" private key property is not a "secret" property, and + * thus unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a private + * key password to prevent unauthorized access to unencrypted private key data. + * * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful **/ gboolean @@ -1917,8 +1616,6 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self, { NMSetting8021xPrivate *priv; NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; - NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN; - GByteArray *data; g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE); @@ -1932,12 +1629,26 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self, if (out_format) g_return_val_if_fail (*out_format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN, FALSE); + /* Ensure the private key is a recognized format and if the password was + * given, that it decrypts the private key. + */ + if (value) { + format = crypto_verify_private_key (value, password, NULL); + if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, + NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return FALSE; + } + } + priv = NM_SETTING_802_1X_GET_PRIVATE (self); - /* Clear out any previous private key blob */ + /* Clear out any previous private key data */ if (priv->phase2_private_key) { /* Try not to leave the private key around in memory */ - memset (priv->phase2_private_key, 0, priv->phase2_private_key->len); + memset (priv->phase2_private_key->data, 0, priv->phase2_private_key->len); g_byte_array_free (priv->phase2_private_key, TRUE); priv->phase2_private_key = NULL; } @@ -1945,81 +1656,23 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self, g_free (priv->phase2_private_key_password); priv->phase2_private_key_password = NULL; - if (!value) + if (value == NULL) return TRUE; - /* Verify the key and the private key password */ - data = crypto_get_private_key (value, - password, - &key_type, - &format, - error); - if (!data) { - /* As a special case for private keys, even if the decrypt fails, - * return the key's file type. - */ - if (out_format && crypto_is_pkcs12_file (value, NULL)) - *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12; - - return FALSE; - } - - switch (format) { - case NM_CRYPTO_FILE_FORMAT_RAW_KEY: - if (out_format) - *out_format = NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; - break; - case NM_CRYPTO_FILE_FORMAT_X509: - if (out_format) - *out_format = NM_SETTING_802_1X_CK_FORMAT_X509; - break; - case NM_CRYPTO_FILE_FORMAT_PKCS12: - if (out_format) - *out_format = NM_SETTING_802_1X_CK_FORMAT_PKCS12; - break; - default: - memset (data->data, 0, data->len); - g_byte_array_free (data, TRUE); - g_set_error (error, - NM_SETTING_802_1X_ERROR, - NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, - NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); - return FALSE; - } - - g_assert (data); + priv->phase2_private_key_password = g_strdup (password); if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { - priv->phase2_private_key = data; - data = NULL; - - /* Always update the private key for blob + pkcs12 since the - * pkcs12 files are encrypted - */ - if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) - priv->phase2_private_key_password = g_strdup (password); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - /* Add the path scheme tag to the front, then the fielname */ - priv->phase2_private_key = g_byte_array_sized_new (strlen (value) + strlen (SCHEME_PATH) + 1); - g_byte_array_append (priv->phase2_private_key, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (priv->phase2_private_key, (const guint8 *) value, strlen (value)); - g_byte_array_append (priv->phase2_private_key, (const guint8 *) "\0", 1); - - /* Always update the private key with paths since the key the - * cert refers to is encrypted. - */ - priv->phase2_private_key_password = g_strdup (password); - } else + /* Shouldn't fail this since we just verified the private key above */ + priv->phase2_private_key = file_to_byte_array (value); + g_assert (priv->phase2_private_key); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + priv->phase2_private_key = path_to_scheme_value (value); + else g_assert_not_reached (); - /* Clear and free private key data if it's no longer needed */ - if (data) { - memset (data->data, 0, data->len); - g_byte_array_free (data, TRUE); - } - /* As required by NM and wpa_supplicant, set the client-cert * property to the same PKCS#12 data. */ + g_assert (format != NM_CRYPTO_FILE_FORMAT_UNKNOWN); if (format == NM_CRYPTO_FILE_FORMAT_PKCS12) { if (priv->phase2_client_cert) g_byte_array_free (priv->phase2_client_cert, TRUE); @@ -2028,55 +1681,12 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self, g_byte_array_append (priv->phase2_client_cert, priv->phase2_private_key->data, priv->phase2_private_key->len); } + if (out_format) + *out_format = format; return priv->phase2_private_key != NULL; } /** - * nm_setting_802_1x_set_phase2_private_key_from_file: - * @setting: the #NMSetting8021x - * @filename: the path of the "phase2" private key file (PEM, DER, or PKCS#12 - * format). Passing NULL clears the "phase2" private key. - * @password: password used to decrypt the private key - * @out_ck_type: on successful return, the type of the private key added - * @error: on unsuccessful return, an error - * - * Reads a "phase 2" private key from disk and sets the - * #NMSetting8021x:phase2-private-key property with the raw private key data. - * - * Private keys are used to authenticate the connecting client to the network - * when EAP-TLS is used as either the "phase 1" or "phase 2" 802.1x - * authentication method. - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_set_phase2_private_key() with - * the %NM_SETTING_802_1X_CK_SCHEME_BLOB scheme. - * - * Returns: TRUE if the operation succeeded, FALSE if it was unsuccessful - **/ -gboolean -nm_setting_802_1x_set_phase2_private_key_from_file (NMSetting8021x *setting, - const char *filename, - const char *password, - NMSetting8021xCKType *out_ck_type, - GError **error) -{ - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - - success = nm_setting_802_1x_set_phase2_private_key (setting, - filename, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - error); - if (success && out_ck_type) - *out_ck_type = ck_format_to_type (format); - - return success; -} - -/** * nm_setting_802_1x_get_phase2_private_key_format: * @setting: the #NMSetting8021x * @@ -2100,7 +1710,7 @@ nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting) case NM_SETTING_802_1X_CK_SCHEME_BLOB: if (crypto_is_pkcs12_data (priv->phase2_private_key)) return NM_SETTING_802_1X_CK_FORMAT_PKCS12; - return NM_SETTING_802_1X_CK_FORMAT_X509; + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_phase2_private_key_path (setting); if (crypto_is_pkcs12_file (path, &error)) @@ -2110,7 +1720,7 @@ nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting) g_error_free (error); return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; } - return NM_SETTING_802_1X_CK_FORMAT_X509; + return NM_SETTING_802_1X_CK_FORMAT_RAW_KEY; default: break; } @@ -2118,23 +1728,6 @@ nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting) return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; } -/** - * nm_setting_802_1x_get_phase2_private_key_type: - * @setting: the #NMSetting8021x - * - * Deprecated: 0.8: This function has been deprecated and should - * not be used in newly written code. Calling this function is - * equivalent to calling nm_setting_802_1x_get_phase2_private_key_format(). - * - * Returns: the data format of the private key data stored in the - * #NMSetting8021x:phase2-private-key property - **/ -NMSetting8021xCKType -nm_setting_802_1x_get_phase2_private_key_type (NMSetting8021x *setting) -{ - return ck_format_to_type (nm_setting_802_1x_get_phase2_private_key_format (setting)); -} - static void need_secrets_password (NMSetting8021x *self, GPtrArray *secrets, @@ -2162,35 +1755,19 @@ need_private_key_password (const GByteArray *blob, const char *path, const char *password) { - /* Private key password is only un-needed if the private key scheme is BLOB, - * because BLOB keys are decrypted by the settings service. A private key - * password is required if the private key is PKCS#12 format, or if the - * private key scheme is PATH. - */ - if (path) { - GByteArray *tmp; - NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_UNKNOWN; - NMCryptoFileFormat key_format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; - - /* check the password */ - tmp = crypto_get_private_key (path, password, &key_type, &key_format, NULL); - if (tmp) { - /* Decrypt/verify successful; password must be OK */ - g_byte_array_free (tmp, TRUE); - return FALSE; - } - } else if (blob) { - /* Non-PKCS#12 blob-scheme keys are already decrypted by their settings - * service, thus if the private key is not PKCS#12 format, a new password - * is not required. If the PKCS#12 key can be decrypted with the given - * password, then we don't need a new password either. - */ - if (!crypto_is_pkcs12_data (blob) || crypto_verify_pkcs12 (blob, password, NULL)) - return FALSE; - } else - g_warning ("%s: unknown private key password scheme", __func__); + NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; - return TRUE; + /* Private key password is required */ + if (password) { + if (path) + format = crypto_verify_private_key (path, password, NULL); + else if (blob) + format = crypto_verify_private_key_data (blob, password, NULL); + else + g_warning ("%s: unknown private key password scheme", __func__); + } + + return (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN); } static void @@ -2204,11 +1781,6 @@ need_secrets_tls (NMSetting8021x *self, const char *path = NULL; if (phase2) { - if (!priv->phase2_private_key || !priv->phase2_private_key->len) { - g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); - return; - } - scheme = nm_setting_802_1x_get_phase2_private_key_scheme (self); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) path = nm_setting_802_1x_get_phase2_private_key_path (self); @@ -2223,11 +1795,6 @@ need_secrets_tls (NMSetting8021x *self, if (need_private_key_password (blob, path, priv->phase2_private_key_password)) g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD); } else { - if (!priv->private_key || !priv->private_key->len) { - g_ptr_array_add (secrets, NM_SETTING_802_1X_PRIVATE_KEY); - return; - } - scheme = nm_setting_802_1x_get_private_key_scheme (self); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) path = nm_setting_802_1x_get_private_key_path (self); @@ -2264,8 +1831,23 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error) return FALSE; } + /* Private key is required for TLS */ + if (!priv->phase2_private_key) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_MISSING_PROPERTY, + NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return FALSE; + } else if (!priv->phase2_private_key->len) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, + NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); + return FALSE; + } + /* If the private key is PKCS#12, check that it matches the client cert */ - if (priv->phase2_private_key && crypto_is_pkcs12_data (priv->phase2_private_key)) { + if (crypto_is_pkcs12_data (priv->phase2_private_key)) { if (priv->phase2_private_key->len != priv->phase2_client_cert->len) { g_set_error (error, NM_SETTING_802_1X_ERROR, @@ -2299,8 +1881,23 @@ verify_tls (NMSetting8021x *self, gboolean phase2, GError **error) return FALSE; } + /* Private key is required for TLS */ + if (!priv->private_key) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_MISSING_PROPERTY, + NM_SETTING_802_1X_PRIVATE_KEY); + return FALSE; + } else if (!priv->private_key->len) { + g_set_error (error, + NM_SETTING_802_1X_ERROR, + NM_SETTING_802_1X_ERROR_INVALID_PROPERTY, + NM_SETTING_802_1X_PRIVATE_KEY); + return FALSE; + } + /* If the private key is PKCS#12, check that it matches the client cert */ - if (priv->private_key && crypto_is_pkcs12_data (priv->private_key)) { + if (crypto_is_pkcs12_data (priv->private_key)) { if (priv->private_key->len != priv->client_cert->len) { g_set_error (error, NM_SETTING_802_1X_ERROR, @@ -2817,6 +2414,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->password); priv->password = g_value_dup_string (value); break; + case PROP_PASSWORD_FLAGS: + priv->password_flags = g_value_get_uint (value); + break; case PROP_PRIVATE_KEY: if (priv->private_key) { g_byte_array_free (priv->private_key, TRUE); @@ -2833,6 +2433,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->private_key_password); priv->private_key_password = g_value_dup_string (value); break; + case PROP_PRIVATE_KEY_PASSWORD_FLAGS: + priv->private_key_password_flags = g_value_get_uint (value); + break; case PROP_PHASE2_PRIVATE_KEY: if (priv->phase2_private_key) { g_byte_array_free (priv->phase2_private_key, TRUE); @@ -2849,6 +2452,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->phase2_private_key_password); priv->phase2_private_key_password = g_value_dup_string (value); break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS: + priv->phase2_private_key_password_flags = g_value_get_uint (value); + break; case PROP_SYSTEM_CA_CERTS: priv->system_ca_certs = g_value_get_boolean (value); break; @@ -2911,18 +2517,27 @@ get_property (GObject *object, guint prop_id, case PROP_PASSWORD: g_value_set_string (value, priv->password); break; + case PROP_PASSWORD_FLAGS: + g_value_set_uint (value, priv->password_flags); + break; case PROP_PRIVATE_KEY: g_value_set_boxed (value, priv->private_key); break; case PROP_PRIVATE_KEY_PASSWORD: g_value_set_string (value, priv->private_key_password); break; + case PROP_PRIVATE_KEY_PASSWORD_FLAGS: + g_value_set_uint (value, priv->private_key_password_flags); + break; case PROP_PHASE2_PRIVATE_KEY: g_value_set_boxed (value, priv->phase2_private_key); break; case PROP_PHASE2_PRIVATE_KEY_PASSWORD: g_value_set_string (value, priv->phase2_private_key_password); break; + case PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS: + g_value_set_uint (value, priv->phase2_private_key_password_flags); + break; case PROP_SYSTEM_CA_CERTS: g_value_set_boolean (value, priv->system_ca_certs); break; @@ -3098,7 +2713,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) "Sometimes when using older RADIUS servers, it is " "necessary to force the client to use a particular " "PEAP version. To do so, this property may be set to " - "'0' or '1; to force that specific PEAP version.", + "'0' or '1' to force that specific PEAP version.", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); @@ -3286,11 +2901,31 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); /** + * NMSetting8021x:password-flags: + * + * Flags indicating how to handle #NMSetting8021x:password:. + **/ + g_object_class_install_property (object_class, PROP_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_802_1X_PASSWORD_FLAGS, + "Password Flags", + "Flags indicating how to handle the 802.1x password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** * NMSetting8021x:private-key: * * Contains the private key if the #NMSetting8021x:eap property is set to * 'tls'. Setting this property directly is discouraged; use the * nm_setting_802_1x_set_private_key() function instead. + * + * WARNING: #NMSetting8021x:private-key is not a "secret" property, and thus + * unencrypted private key data using the BLOB scheme may be readable by + * unprivileged users. Private keys should always be encrypted with a + * private key password to prevent unauthorized access to unencrypted + * private key data. **/ g_object_class_install_property (object_class, PROP_PRIVATE_KEY, @@ -3299,28 +2934,28 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) "Contains the private key when the 'eap' property " "is set to 'tls'. Key data is specified using a " "'scheme'; two are currently supported: blob and " - "path. When using the blob scheme and X.509 private " - "keys, this property should be set to the keys's " - "decrypted DER encoded data. When using X.509 " - "private keys with the path scheme, this property " - "should be set to the full UTF-8 encoded path of " - "the key, prefixed with the string 'file://' and " - "and ending with a terminating NULL byte. When " - "using PKCS#12 format private keys and the blob " + "path. When using the blob scheme and private " + "keys, this property should be set to the key's " + "encrypted PEM encoded data. When using private " + "keys with the path scheme, this property should " + "be set to the full UTF-8 encoded path of the key, " + "prefixed with the string 'file://' and ending " + "with a terminating NULL byte. When using " + "PKCS#12 format private keys and the blob " "scheme, this property should be set to the " - "PKCS#12 data (which is encrypted) and the " + "PKCS#12 data and the 'private-key-password' " + "property must be set to password used to " + "decrypt the PKCS#12 certificate and key. When " + "using PKCS#12 files and the path scheme, this " + "property should be set to the full UTF-8 encoded " + "path of the key, prefixed with the string " + "'file://' and and ending with a terminating NULL " + "byte, and as with the blob scheme the " "'private-key-password' property must be set to " - "password used to decrypt the PKCS#12 certificate " - "and key. When using PKCS#12 files and the path " - "scheme, this property should be set to the full " - "UTF-8 encoded path of the key, prefixed with the " - "string 'file://' and and ending with a " - "terminating NULL byte, and as with the blob " - "scheme the 'private-key-password' property must " - "be set to the password used to decode the PKCS#12 " - "private key and certificate.", + "the password used to decode the PKCS#12 private " + "key and certificate.", DBUS_TYPE_G_UCHAR_ARRAY, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); /** * NMSetting8021x:private-key-password: @@ -3344,6 +2979,21 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); /** + * NMSetting8021x:private-key-password-flags: + * + * Flags indicating how to handle #NMSetting8021x:private-key-password:. + **/ + g_object_class_install_property (object_class, PROP_PRIVATE_KEY_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, + "Private Key Password Flags", + "Flags indicating how to handle the 802.1x private " + "key password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** * NMSetting8021x:phase2-private-key: * * Private key data used by "phase 2" inner authentication methods. @@ -3361,28 +3011,28 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) "the 'phase2-eap' or 'phase2-autheap' property " "is set to 'tls'. Key data is specified using a " "'scheme'; two are currently supported: blob and " - "path. When using the blob scheme and X.509 private " - "keys, this property should be set to the keys's " - "decrypted DER encoded data. When using X.509 " - "private keys with the path scheme, this property " - "should be set to the full UTF-8 encoded path of " - "the key, prefixed with the string 'file://' and " - "and ending with a terminating NULL byte. When " - "using PKCS#12 format private keys and the blob " + "path. When using the blob scheme and private " + "keys, this property should be set to the key's " + "encrypted PEM encoded data. When using private " + "keys with the path scheme, this property should " + "be set to the full UTF-8 encoded path of the key, " + "prefixed with the string 'file://' and ending " + "with a terminating NULL byte. When using " + "PKCS#12 format private keys and the blob " "scheme, this property should be set to the " - "PKCS#12 data (which is encrypted) and the " - "'private-key-password' property must be set to " - "password used to decrypt the PKCS#12 certificate " - "and key. When using PKCS#12 files and the path " - "scheme, this property should be set to the full " - "UTF-8 encoded path of the key, prefixed with the " - "string 'file://' and and ending with a " - "terminating NULL byte, and as with the blob " - "scheme the 'private-key-password' property must " - "be set to the password used to decode the PKCS#12 " + "PKCS#12 data and the 'phase2-private-key-password' " + "property must be set to password used to " + "decrypt the PKCS#12 certificate and key. When " + "using PKCS#12 files and the path scheme, this " + "property should be set to the full UTF-8 encoded " + "path of the key, prefixed with the string " + "'file://' and and ending with a terminating NULL " + "byte, and as with the blob scheme the " + "'phase2-private-key-password' property must be " + "set to the password used to decode the PKCS#12 " "private key and certificate.", DBUS_TYPE_G_UCHAR_ARRAY, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); /** * NMSetting8021x:phase2-private-key-password: @@ -3406,6 +3056,21 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET)); /** + * NMSetting8021x:phase2-private-key-password-flags: + * + * Flags indicating how to handle #NMSetting8021x:phase2-private-key-password:. + **/ + g_object_class_install_property (object_class, PROP_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, + g_param_spec_uint (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS, + "Phase2 Private Key Password Flags", + "Flags indicating how to handle the 802.1x phase2 " + "private key password.", + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_SECRET_FLAGS_ALL, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** * NMSetting8021x:system-ca-certs: * * When TRUE, overrides #NMSetting8021x:ca-path and |