NM plugin supports (encrypted) private key files
authorMartin Willi <martin@strongswan.org>
Fri, 5 Sep 2008 13:26:58 +0000 (13:26 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 5 Sep 2008 13:26:58 +0000 (13:26 -0000)
src/charon/plugins/nm/gnome/auth-dialog/main.c
src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade
src/charon/plugins/nm/gnome/properties/nm-strongswan.c
src/charon/plugins/nm/nm_service.c

index ee9ba0b..92356c6 100644 (file)
@@ -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)
index f827ba2..f77eb42 100644 (file)
                     <property name="column_spacing">6</property>
                     <property name="row_spacing">6</property>
                     <child>
-                      <widget class="GtkFileChooserButton" id="certificate-button">
-                        <property name="visible">True</property>
-                        <property name="tooltip_text">Gateway certificate to use for gateway authentication.</property>
-                      </widget>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
-                        <property name="top_attach">1</property>
-                        <property name="bottom_attach">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="certificate-label">
+                      <widget class="GtkLabel" id="address-label">
                         <property name="visible">True</property>
                         <property name="xalign">0</property>
-                        <property name="label" translatable="yes">C_ertificate:</property>
+                        <property name="label" translatable="yes">_Address:</property>
                         <property name="use_underline">True</property>
-                        <property name="mnemonic_widget">certificate-button</property>
+                        <property name="mnemonic_widget">address-entry</property>
                       </widget>
                       <packing>
-                        <property name="top_attach">1</property>
-                        <property name="bottom_attach">2</property>
                         <property name="x_options">GTK_FILL</property>
                         <property name="y_options"></property>
                       </packing>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkLabel" id="address-label">
+                      <widget class="GtkLabel" id="certificate-label">
                         <property name="visible">True</property>
                         <property name="xalign">0</property>
-                        <property name="label" translatable="yes">_Address:</property>
+                        <property name="label" translatable="yes">C_ertificate:</property>
                         <property name="use_underline">True</property>
-                        <property name="mnemonic_widget">address-entry</property>
+                        <property name="mnemonic_widget">certificate-button</property>
                       </widget>
                       <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
                         <property name="x_options">GTK_FILL</property>
                         <property name="y_options"></property>
                       </packing>
                     </child>
+                    <child>
+                      <widget class="GtkFileChooserButton" id="certificate-button">
+                        <property name="visible">True</property>
+                        <property name="tooltip_text">Gateway certificate to use for gateway authentication.</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
                   </widget>
                 </child>
               </widget>
                 <child>
                   <widget class="GtkTable" id="client-table">
                     <property name="visible">True</property>
-                    <property name="n_rows">3</property>
+                    <property name="n_rows">4</property>
                     <property name="n_columns">2</property>
                     <property name="column_spacing">6</property>
                     <property name="row_spacing">6</property>
                     <child>
-                      <widget class="GtkFileChooserButton" id="usercert-button">
+                      <widget class="GtkFileChooserButton" id="userkey-button">
                         <property name="visible">True</property>
-                        <property name="tooltip_text">Client certificate to use for client authentication.</property>
+                        <property name="tooltip_text">Private key to use for client authentication. This key has to match the certificates public key and may be encrypted..</property>
                       </widget>
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">2</property>
-                        <property name="bottom_attach">3</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkLabel" id="usercert-label">
+                      <widget class="GtkLabel" id="userkey-label">
                         <property name="visible">True</property>
                         <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Ce_rtificate:</property>
+                        <property name="label" translatable="yes">Private _key:</property>
                         <property name="use_underline">True</property>
-                        <property name="mnemonic_widget">usercert-button</property>
+                        <property name="mnemonic_widget">userkey-button</property>
                       </widget>
                       <packing>
-                        <property name="top_attach">2</property>
-                        <property name="bottom_attach">3</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
                         <property name="x_options">GTK_FILL</property>
                         <property name="y_options"></property>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkEntry" id="user-entry">
+                      <widget class="GtkComboBox" id="method-combo">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
                         <property name="has_tooltip">True</property>
-                        <property name="tooltip_text">The username (identity) to use for authentication against the gateway.</property>
+                        <property name="tooltip_text">Authentication Method to use for authentication against the Gateway. </property>
+                        <property name="items"></property>
                       </widget>
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">1</property>
-                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="method-label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Au_thentication:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">method-combo</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
                         <property name="y_options"></property>
                       </packing>
                     </child>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkLabel" id="method-label">
+                      <widget class="GtkEntry" id="user-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="has_tooltip">True</property>
+                        <property name="tooltip_text">The username (identity) to use for authentication against the gateway.</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="usercert-label">
                         <property name="visible">True</property>
                         <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Au_thentication:</property>
+                        <property name="label" translatable="yes">Ce_rtificate:</property>
                         <property name="use_underline">True</property>
-                        <property name="mnemonic_widget">method-combo</property>
+                        <property name="mnemonic_widget">usercert-button</property>
                       </widget>
                       <packing>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
                         <property name="x_options">GTK_FILL</property>
                         <property name="y_options"></property>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkComboBox" id="method-combo">
+                      <widget class="GtkFileChooserButton" id="usercert-button">
                         <property name="visible">True</property>
-                        <property name="has_tooltip">True</property>
-                        <property name="tooltip_text">Authentication Method to use for authentication against the Gateway. </property>
-                        <property name="items"></property>
+                        <property name="tooltip_text">Client certificate to use for client authentication.</property>
                       </widget>
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
                       </packing>
                     </child>
                   </widget>
index 8d97a55..24ca150 100644 (file)
@@ -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,16 +313,29 @@ 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 = "agent";
+                       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) {
+                               g_hash_table_insert (settings->data, g_strdup ("usercert"), g_strdup(str));
+                       }
+                       str = "agent";
+                       break;
+               case 2:
                        widget = glade_xml_get_widget (priv->xml, "user-entry");
                        str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
                        if (str && strlen (str)) {
index 049a03c..e9edcf7 100644 (file)
@@ -19,6 +19,7 @@
 #include "nm_service.h"
 
 #include <daemon.h>
+#include <asn1/pem.h>
 #include <utils/host.h>
 #include <utils/identification.h>
 #include <config/peer_cfg.h>
@@ -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
@@ -206,6 +208,11 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
                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;