From 1d03954aadf49d863b0b47cab09cb7d571d7a2d4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 5 Sep 2008 13:26:58 +0000 Subject: [PATCH] NM plugin supports (encrypted) private key files --- .../plugins/nm/gnome/auth-dialog/main.c | 37 +++-- .../properties/nm-strongswan-dialog.glade | 131 +++++++++++------- .../nm/gnome/properties/nm-strongswan.c | 98 ++++++++----- src/charon/plugins/nm/nm_service.c | 53 ++++++- 4 files changed, 220 insertions(+), 99 deletions(-) diff --git a/src/charon/plugins/nm/gnome/auth-dialog/main.c b/src/charon/plugins/nm/gnome/auth-dialog/main.c index ee9ba0bb9..92356c6ba 100644 --- a/src/charon/plugins/nm/gnome/auth-dialog/main.c +++ b/src/charon/plugins/nm/gnome/auth-dialog/main.c @@ -63,9 +63,9 @@ static char *lookup_password(char *name, char *service) } /** - * check if this connection needs a password + * get the connection type */ -static gboolean need_password(char *id) +static char* get_connection_type(char *id) { GConfClient *client; char *key, *str; @@ -75,14 +75,9 @@ static gboolean need_password(char *id) key = g_strdup_printf("/system/networking/connections/%s/%s/%s", id, NM_SETTING_VPN_SETTING_NAME, "method"); str = gconf_client_get_string(client, key, NULL); - if (str && !strcmp(str, "eap")) - { - need_password = TRUE; - } - g_free(str); g_free(key); g_object_unref(client); - return need_password; + return str; } int main (int argc, char *argv[]) @@ -92,7 +87,7 @@ int main (int argc, char *argv[]) GOptionContext *context; GnomeProgram *program = NULL; int exit_status = 1; - char buf, *agent; + char buf, *agent, *type; guint32 itemid; GtkWidget *dialog; GOptionEntry entries[] = { @@ -131,14 +126,30 @@ int main (int argc, char *argv[]) return 1; } - if (need_password(id)) + type = get_connection_type(id); + if (!type) + { + fprintf(stderr, "Connection lookup failed\n"); + g_object_unref (program); + return 1; + } + if (!strcmp(type, "eap") || !strcmp(type, "key")) { pass = lookup_password(name, service); if (!pass || retry) { - dialog = gnome_password_dialog_new(_("VPN password required"), - _("Password required to establish VPN connection:"), - NULL, NULL, TRUE); + if (!strcmp(type, "eap")) + { + dialog = gnome_password_dialog_new(_("VPN password required"), + _("EAP password required to establish VPN connection:"), + NULL, NULL, TRUE); + } + else + { + dialog = gnome_password_dialog_new(_("VPN password required"), + _("Private key decryption password required to establish VPN connection:"), + NULL, NULL, TRUE); + } gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE); gnome_password_dialog_set_show_username(GNOME_PASSWORD_DIALOG(dialog), FALSE); if (pass) diff --git a/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade b/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade index f827ba2b3..f77eb42e7 100644 --- a/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade +++ b/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade @@ -37,28 +37,14 @@ 6 6 - - True - Gateway certificate to use for gateway authentication. - - - 1 - 2 - 1 - 2 - - - - + True 0 - C_ertificate: + _Address: True - certificate-button + address-entry - 1 - 2 GTK_FILL @@ -77,18 +63,32 @@ - + True 0 - _Address: + C_ertificate: True - address-entry + certificate-button + 1 + 2 GTK_FILL + + + True + Gateway certificate to use for gateway authentication. + + + 1 + 2 + 1 + 2 + + @@ -124,33 +124,73 @@ True - 3 + 4 2 6 6 - + True - Client certificate to use for client authentication. + Private key to use for client authentication. This key has to match the certificates public key and may be encrypted.. 1 2 - 2 - 3 + 3 + 4 - + True 0 - Ce_rtificate: + Private _key: True - usercert-button + userkey-button - 2 - 3 + 3 + 4 + GTK_FILL + + + + + + True + True + Authentication Method to use for authentication against the Gateway. + + + + 1 + 2 + + + + + True + 0 + Au_thentication: + True + method-combo + + + GTK_FILL + + + + + + True + 0 + _Username: + True + user-entry + + + 1 + 2 GTK_FILL @@ -171,43 +211,30 @@ - + True 0 - _Username: + Ce_rtificate: True - user-entry + usercert-button - 1 - 2 + 2 + 3 GTK_FILL - + True - 0 - Au_thentication: - True - method-combo - - - GTK_FILL - - - - - - True - True - Authentication Method to use for authentication against the Gateway. - + Client certificate to use for client authentication. 1 2 + 2 + 3 diff --git a/src/charon/plugins/nm/gnome/properties/nm-strongswan.c b/src/charon/plugins/nm/gnome/properties/nm-strongswan.c index 8d97a5560..24ca1502b 100644 --- a/src/charon/plugins/nm/gnome/properties/nm-strongswan.c +++ b/src/charon/plugins/nm/gnome/properties/nm-strongswan.c @@ -122,31 +122,50 @@ check_validity (StrongswanPluginUiWidget *self, GError **error) return TRUE; } -static void -settings_changed_cb (GtkWidget *widget, gpointer user_data) +static void update_layout (GtkWidget *widget, StrongswanPluginUiWidgetPrivate *priv) { - g_signal_emit_by_name (STRONGSWAN_PLUGIN_UI_WIDGET (user_data), "changed"); + switch (gtk_combo_box_get_active (GTK_COMBO_BOX (widget))) + { + default: + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + /* FALL */ + case 0: + gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-label")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-button")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "userkey-label")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "userkey-button")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry")); + break; + case 1: + gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-label")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-button")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-button")); + break; + case 2: + gtk_widget_show (glade_xml_get_widget (priv->xml, "user-label")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "user-entry")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-button")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "userkey-button")); + break; + } + } static void -method_changed_cb (GtkWidget *widget, gpointer user_data) +settings_changed_cb (GtkWidget *widget, gpointer user_data) { StrongswanPluginUiWidget *self = STRONGSWAN_PLUGIN_UI_WIDGET (user_data); StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self); - if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == 0) + if (widget == glade_xml_get_widget (priv->xml, "method-combo")) { - gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-label")); - gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-button")); - gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label")); - gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry")); - } - else - { - gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-label")); - gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-button")); - gtk_widget_show (glade_xml_get_widget (priv->xml, "user-label")); - gtk_widget_show (glade_xml_get_widget (priv->xml, "user-entry")); + update_layout(glade_xml_get_widget (priv->xml, "method-combo"), priv); } g_signal_emit_by_name (STRONGSWAN_PLUGIN_UI_WIDGET (user_data), "changed"); } @@ -183,32 +202,27 @@ init_plugin_ui (StrongswanPluginUiWidget *self, NMConnection *connection, GError g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self); widget = glade_xml_get_widget (priv->xml, "method-combo"); + gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Certificate/private key")); gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Certificate/ssh-agent")); gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("EAP")); value = g_hash_table_lookup (settings->data, "method"); if (value) { - if (g_strcasecmp (value, "agent") == 0) { + if (g_strcasecmp (value, "key") == 0) { gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); } - if (g_strcasecmp (value, "eap") == 0) { + if (g_strcasecmp (value, "agent") == 0) { gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1); } + if (g_strcasecmp (value, "eap") == 0) { + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2); + } } - g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (method_changed_cb), self); if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == -1) { gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); } - if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) != 0) - { - gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-label")); - gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-button")); - } - else - { - gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label")); - gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry")); - } + update_layout (widget, priv); + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self); widget = glade_xml_get_widget (priv->xml, "usercert-label"); gtk_widget_set_no_show_all (widget, TRUE); @@ -219,6 +233,15 @@ init_plugin_ui (StrongswanPluginUiWidget *self, NMConnection *connection, GError gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value); g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (settings_changed_cb), self); + widget = glade_xml_get_widget (priv->xml, "userkey-label"); + gtk_widget_set_no_show_all (widget, TRUE); + widget = glade_xml_get_widget (priv->xml, "userkey-button"); + gtk_widget_set_no_show_all (widget, TRUE); + value = g_hash_table_lookup (settings->data, "userkey"); + if (value) + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value); + g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (settings_changed_cb), self); + widget = glade_xml_get_widget (priv->xml, "virtual-check"); value = g_hash_table_lookup (settings->data, "virtual"); if (value && strcmp(value, "yes") == 0) @@ -290,8 +313,21 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, widget = glade_xml_get_widget (priv->xml, "method-combo"); switch (gtk_combo_box_get_active (GTK_COMBO_BOX (widget))) { - case 0: default: + case 0: + widget = glade_xml_get_widget (priv->xml, "userkey-button"); + str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)); + if (str) { + g_hash_table_insert (settings->data, g_strdup ("userkey"), g_strdup(str)); + } + widget = glade_xml_get_widget (priv->xml, "usercert-button"); + str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)); + if (str) { + g_hash_table_insert (settings->data, g_strdup ("usercert"), g_strdup(str)); + } + str = "key"; + break; + case 1: widget = glade_xml_get_widget (priv->xml, "usercert-button"); str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)); if (str) { @@ -299,7 +335,7 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, } str = "agent"; break; - case 1: + case 2: widget = glade_xml_get_widget (priv->xml, "user-entry"); str = (char *) gtk_entry_get_text (GTK_ENTRY (widget)); if (str && strlen (str)) { diff --git a/src/charon/plugins/nm/nm_service.c b/src/charon/plugins/nm/nm_service.c index 049a03ccb..e9edcf751 100644 --- a/src/charon/plugins/nm/nm_service.c +++ b/src/charon/plugins/nm/nm_service.c @@ -19,6 +19,7 @@ #include "nm_service.h" #include +#include #include #include #include @@ -174,6 +175,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, auth_info_t *auth; auth_class_t auth_class = AUTH_CLASS_EAP; certificate_t *cert = NULL; + bool agent = FALSE; /** * Read parameters @@ -204,6 +206,11 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, auth_class = AUTH_CLASS_PSK; } else if (streq(str, "agent")) + { + auth_class = AUTH_CLASS_PUBKEY; + agent = TRUE; + } + else if (streq(str, "key")) { auth_class = AUTH_CLASS_PUBKEY; } @@ -253,9 +260,11 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, private_key_t *private = NULL; cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, - BUILD_FROM_FILE, str, BUILD_END); + BUILD_FROM_FILE, str, BUILD_END); + + /* try agent */ str = g_hash_table_lookup(settings->data, "agent"); - if (str && cert) + if (agent && str && cert) { public = cert->get_public_key(cert); if (public) @@ -268,6 +277,25 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, public->destroy(public); } } + /* ... or key file */ + str = g_hash_table_lookup(settings->data, "userkey"); + if (!agent && str && cert) + { + chunk_t secret, chunk; + bool pgp = FALSE; + + secret.ptr = g_hash_table_lookup(settings->data, "password"); + if (secret.ptr) + { + secret.len = strlen(secret.ptr); + } + if (pem_asn1_load_file(str, &secret, &chunk, &pgp)) + { + private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + KEY_RSA, BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + free(chunk.ptr); + } + } if (private) { user = cert->get_subject(cert); @@ -359,7 +387,9 @@ static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection, char **setting_name, GError **error) { NMSettingVPN *settings; - char *method; + char *method, *path; + chunk_t secret = chunk_empty, key; + bool pgp = FALSE; settings = NM_SETTING_VPN(nm_connection_get_setting(connection, NM_TYPE_SETTING_VPN)); @@ -380,6 +410,23 @@ static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection, return FALSE; } } + else if (streq(method, "key")) + { + path = g_hash_table_lookup(settings->data, "userkey"); + if (path) + { + secret.ptr = g_hash_table_lookup(settings->data, "password"); + if (secret.ptr) + { + secret.len = strlen(secret.ptr); + } + if (pem_asn1_load_file(path, &secret, &key, &pgp)) + { + free(key.ptr); + return FALSE; + } + } + } } *setting_name = NM_SETTING_VPN_SETTING_NAME; return TRUE;