If openvpn server is configured with a non-default key size, clients have to use
the same size too. We add an option to use custom key size in GUI and handle that
in the service and properties code including import/export too.
However, note that using key sizes different from cipher-specific defaults is
not recommended. List available ciphers and default key sizes by
'openvpn --show-ciphers'.
man openvpn: search --keysize
https://bugzilla.gnome.org/show_bug.cgi?id=706775
NM_OPENVPN_KEY_PROXY_RETRY,
NM_OPENVPN_KEY_HTTP_PROXY_USERNAME,
NM_OPENVPN_KEY_CIPHER,
+ NM_OPENVPN_KEY_KEYSIZE,
NM_OPENVPN_KEY_AUTH,
NM_OPENVPN_KEY_TA_DIR,
NM_OPENVPN_KEY_TA,
gtk_widget_set_sensitive (widget, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)));
}
+static void
+keysize_toggled_cb (GtkWidget *check, gpointer user_data)
+{
+ GtkBuilder *builder = (GtkBuilder *) user_data;
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_spinbutton"));
+ gtk_widget_set_sensitive (widget, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)));
+}
+
static const char *
nm_find_openvpn (void)
{
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_CIPHER);
populate_cipher_combo (GTK_COMBO_BOX (widget), value);
+ widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_checkbutton"));
+ g_assert (widget);
+ g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (keysize_toggled_cb), builder);
+
+ value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_KEYSIZE);
+ if (value && strlen (value)) {
+ long int tmp;
+
+ errno = 0;
+ tmp = strtol (value, NULL, 10);
+ if (errno == 0 && tmp > 0 && tmp < 65536) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_spinbutton"));
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), (gdouble) tmp);
+ gtk_widget_set_sensitive (widget, TRUE);
+ }
+ } else {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_spinbutton"));
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), 128.0);
+ gtk_widget_set_sensitive (widget, FALSE);
+ }
+
widget = GTK_WIDGET (gtk_builder_get_object (builder, "hmacauth_combo"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_AUTH);
populate_hmacauth_combo (GTK_COMBO_BOX (widget), value);
}
}
+ widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_checkbutton"));
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
+ int keysize_val;
+
+ widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_spinbutton"));
+ keysize_val = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+ g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_KEYSIZE), g_strdup_printf ("%d", keysize_val));
+ }
+
widget = GTK_WIDGET (gtk_builder_get_object (builder, "hmacauth_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
#define CA_TAG "ca "
#define CERT_TAG "cert "
#define CIPHER_TAG "cipher "
+#define KEYSIZE_TAG "keysize "
#define CLIENT_TAG "client"
#define COMP_TAG "comp-lzo"
#define DEV_TAG "dev "
continue;
}
+ if (!strncmp (*line, KEYSIZE_TAG, strlen (KEYSIZE_TAG))) {
+ items = get_args (*line + strlen (KEYSIZE_TAG), &nitems);
+ if (nitems == 1) {
+ glong key_size;
+
+ errno = 0;
+ key_size = strtol (items[0], NULL, 10);
+ if ((errno == 0) && (key_size > 0) && (key_size <= 65535)) {
+ tmp = g_strdup_printf ("%d", (guint32) key_size);
+ nm_setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_KEYSIZE, tmp);
+ g_free (tmp);
+ } else
+ g_warning ("%s: invalid key size in option '%s'", __func__, *line);
+ } else
+ g_warning ("%s: invalid number of arguments in option '%s'", __func__, *line);
+ g_strfreev (items);
+ continue;
+ }
+
if (!strncmp (*line, TLS_REMOTE_TAG, strlen (TLS_REMOTE_TAG))) {
char *unquoted = unquote (*line + strlen (TLS_REMOTE_TAG), NULL);
gboolean use_lzo = FALSE;
gboolean reneg_exists = FALSE;
guint32 reneg = 0;
+ gboolean keysize_exists = FALSE;
+ guint32 keysize = 0;
const char *proxy_type = NULL;
const char *proxy_server = NULL;
const char *proxy_port = NULL;
if (value && strlen (value))
cipher = value;
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEYSIZE);
+ if (value && strlen (value)) {
+ keysize_exists = TRUE;
+ keysize = strtol (value, NULL, 10);
+ }
+
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_LOCAL_IP);
if (value && strlen (value))
local_ip = value;
if (cipher)
fprintf (f, "cipher %s\n", cipher);
+ if (keysize_exists)
+ fprintf (f, "keysize %d\n", keysize);
+
if (use_lzo)
fprintf (f, "comp-lzo yes\n");
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkAdjustment" id="adjustment6">
+ <property name="lower">1</property>
+ <property name="upper">65535</property>
+ <property name="value">128</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
<object class="GtkListStore" id="liststore1"/>
<object class="GtkListStore" id="liststore2"/>
<object class="GtkListStore" id="model1">
<property name="right_attach">2</property>
</packing>
</child>
+ <child>
+ <object class="GtkCheckButton" id="keysize_checkbutton">
+ <property name="label" translatable="yes">Use custom _size of cipher key:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="tooltip_text" translatable="yes">Set cipher key size to a custom value. If unspecified, it defaults to cipher-specific size.
+config: keysize <n></property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="keysize_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="adjustment">adjustment6</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ <property name="tooltip_text" translatable="yes">Set cipher key size to a custom value. If unspecified, it defaults to cipher-specific size.
+config: keysize <n></property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ <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>
<object class="GtkComboBox" id="hmacauth_combo">
<property name="visible">True</property>
<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="top_attach">2</property>
+ <property name="bottom_attach">3</property>
</packing>
</child>
<child>
<property name="mnemonic_widget">hmacauth_combo</property>
</object>
<packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
</packing>
</child>
</object>
proxy-http.ovpn \
httpauthfile \
proxy-socks.ovpn \
- proxy-http-with-auth.ovpn
+ proxy-http-with-auth.ovpn \
+ keysize.ovpn \
--- /dev/null
+client
+dev tun
+proto tcp
+remote miami.proxpn.com 443
+resolv-retry infinite
+nobind
+persist-key
+persist-tun
+comp-lzo
+tun-mtu 1500
+mssfix 1450
+auth-user-pass
+reneg-sec 0
+
+ca ssl/ca.crt
+cert ssl/client.crt
+key ssl/client.key
+cipher BF-CBC
+keysize 512
+
g_free (path);
}
+static void
+test_keysize_import (NMVpnPluginUiInterface *plugin, const char *dir)
+{
+ NMConnection *connection;
+ NMSettingVPN *s_vpn;
+
+ connection = get_basic_connection ("keysize-import", plugin, dir, "keysize.ovpn");
+ ASSERT (connection != NULL, "keysize-import", "failed to import connection");
+
+ /* VPN setting */
+ s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+ ASSERT (s_vpn != NULL,
+ "keysize-import", "missing 'vpn' setting");
+
+ /* Data items */
+ test_item ("keysize-import-data", s_vpn, NM_OPENVPN_KEY_KEYSIZE, "512");
+
+ g_object_unref (connection);
+}
+
+#define KEYSIZE_EXPORTED_NAME "keysize.ovpntest"
+static void
+test_keysize_export (NMVpnPluginUiInterface *plugin, const char *dir, const char *tmpdir)
+{
+ NMConnection *connection;
+ NMConnection *reimported;
+ char *path;
+ gboolean success;
+ GError *error = NULL;
+
+ connection = get_basic_connection ("keysize-export", plugin, dir, "keysize.ovpn");
+ ASSERT (connection != NULL, "keysize-export", "failed to import connection");
+
+ path = g_build_path ("/", tmpdir, KEYSIZE_EXPORTED_NAME, NULL);
+ success = nm_vpn_plugin_ui_interface_export (plugin, path, connection, &error);
+ if (!success) {
+ if (!error)
+ FAIL ("keysize-export", "export failed with missing error");
+ else
+ FAIL ("keysize-export", "export failed: %s", error->message);
+ }
+
+ /* Now re-import it and compare the connections to ensure they are the same */
+ reimported = get_basic_connection ("keysize-export", plugin, tmpdir, KEYSIZE_EXPORTED_NAME);
+ (void) unlink (path);
+ ASSERT (reimported != NULL, "keysize-export", "failed to re-import connection");
+
+ /* Clear secrets first, since they don't get exported, and thus would
+ * make the connection comparison below fail.
+ */
+ remove_secrets (connection);
+
+ ASSERT (nm_connection_compare (connection, reimported, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
+ "keysize-export", "original and reimported connection differ");
+
+ g_object_unref (reimported);
+ g_object_unref (connection);
+ g_free (path);
+}
+
int main (int argc, char **argv)
{
GError *error = NULL;
test_proxy_socks_import (plugin, test_dir);
test_proxy_socks_export (plugin, test_dir, argv[2]);
+ test_keysize_import (plugin, test_dir);
+ test_keysize_export (plugin, test_dir, argv[2]);
+
g_object_unref (plugin);
basename = g_path_get_basename (argv[0]);
{ NM_OPENVPN_KEY_CA, G_TYPE_STRING, 0, 0, FALSE },
{ NM_OPENVPN_KEY_CERT, G_TYPE_STRING, 0, 0, FALSE },
{ NM_OPENVPN_KEY_CIPHER, G_TYPE_STRING, 0, 0, FALSE },
+ { NM_OPENVPN_KEY_KEYSIZE, G_TYPE_INT, 1, 65535, FALSE },
{ NM_OPENVPN_KEY_COMP_LZO, G_TYPE_BOOLEAN, 0, 0, FALSE },
{ NM_OPENVPN_KEY_CONNECTION_TYPE, G_TYPE_STRING, 0, 0, FALSE },
{ NM_OPENVPN_KEY_FRAGMENT_SIZE, G_TYPE_INT, 0, G_MAXINT, FALSE },
add_openvpn_arg (args, tmp);
}
+ /* Keysize */
+ tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEYSIZE);
+ if (tmp && strlen (tmp)) {
+ add_openvpn_arg (args, "--keysize");
+ if (!add_openvpn_arg_int (args, tmp)) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ _("Invalid keysize '%s'."),
+ tmp);
+ free_openvpn_args (args);
+ return FALSE;
+ }
+ }
+
/* Auth */
if (auth) {
add_openvpn_arg (args, "--auth");
#define NM_OPENVPN_KEY_CA "ca"
#define NM_OPENVPN_KEY_CERT "cert"
#define NM_OPENVPN_KEY_CIPHER "cipher"
+#define NM_OPENVPN_KEY_KEYSIZE "keysize"
#define NM_OPENVPN_KEY_COMP_LZO "comp-lzo"
#define NM_OPENVPN_KEY_CONNECTION_TYPE "connection-type"
#define NM_OPENVPN_KEY_FRAGMENT_SIZE "fragment-size"