Merge branch 'android-proposals'
authorTobias Brunner <tobias@strongswan.org>
Tue, 28 Nov 2017 15:23:41 +0000 (16:23 +0100)
committerTobias Brunner <tobias@strongswan.org>
Tue, 28 Nov 2017 15:23:41 +0000 (16:23 +0100)
Makes IKE and ESP proposals configurable.

47 files changed:
src/charon-tkm/tests/keymat_tests.c
src/conftest/hooks/custom_proposal.c
src/frontends/android/app/build.gradle
src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfile.java
src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileDataSource.java
src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java
src/frontends/android/app/src/main/java/org/strongswan/android/logic/StrongSwanApplication.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/utils/Utils.java
src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_service.c
src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c
src/frontends/android/app/src/main/res/layout/profile_detail_view.xml
src/frontends/android/app/src/main/res/values-de/strings.xml
src/frontends/android/app/src/main/res/values-pl/strings.xml
src/frontends/android/app/src/main/res/values-ru/strings.xml
src/frontends/android/app/src/main/res/values-ua/strings.xml
src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml
src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml
src/frontends/android/app/src/main/res/values/strings.xml
src/libcharon/Android.mk
src/libcharon/Makefile.am
src/libcharon/config/child_cfg.h
src/libcharon/config/ike_cfg.h
src/libcharon/config/peer_cfg.h
src/libcharon/config/proposal.c [deleted file]
src/libcharon/config/proposal.h [deleted file]
src/libcharon/daemon.c
src/libcharon/encoding/payloads/proposal_substructure.h
src/libcharon/encoding/payloads/transform_substructure.h
src/libcharon/processing/jobs/delete_child_sa_job.h
src/libcharon/processing/jobs/rekey_child_sa_job.h
src/libcharon/processing/jobs/update_sa_job.h
src/libcharon/sa/child_sa.h
src/libcharon/sa/keymat.h
src/libcharon/tests/Makefile.am
src/libcharon/tests/libcharon_tests.h
src/libcharon/tests/suites/test_proposal.c [deleted file]
src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/crypto/proposal/proposal.c [new file with mode: 0644]
src/libstrongswan/crypto/proposal/proposal.h [new file with mode: 0644]
src/libstrongswan/crypto/proposal/proposal_keywords.h
src/libstrongswan/library.c
src/libstrongswan/tests/Makefile.am
src/libstrongswan/tests/suites/test_proposal.c [new file with mode: 0644]
src/libstrongswan/tests/tests.h

index 8bba1f9..d4751f7 100644 (file)
@@ -17,7 +17,7 @@
 #include <tests/test_suite.h>
 
 #include <daemon.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <encoding/payloads/ike_header.h>
 #include <tkm/client.h>
 
index c4f8385..5e1cec0 100644 (file)
@@ -18,7 +18,7 @@
 #include <errno.h>
 
 #include <encoding/payloads/sa_payload.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 typedef struct private_custom_proposal_t private_custom_proposal_t;
 
index ca11abe..bc26c33 100644 (file)
@@ -8,8 +8,8 @@ android {
         applicationId "org.strongswan.android"
         minSdkVersion 15
         targetSdkVersion 22
-        versionCode 48
-        versionName "1.9.4"
+        versionCode 49
+        versionName "1.9.5"
     }
 
     sourceSets.main {
index 8288684..00cd393 100644 (file)
@@ -34,6 +34,7 @@ public class VpnProfile implements Cloneable
 
        private String mName, mGateway, mUsername, mPassword, mCertificate, mUserCertificate;
        private String mRemoteId, mLocalId, mExcludedSubnets, mIncludedSubnets, mSelectedApps;
+       private String mIkeProposal, mEspProposal;
        private Integer mMTU, mPort, mSplitTunneling, mNATKeepAlive, mFlags;
        private SelectedAppsHandling mSelectedAppsHandling = SelectedAppsHandling.SELECTED_APPS_DISABLE;
        private VpnType mVpnType;
@@ -114,6 +115,26 @@ public class VpnProfile implements Cloneable
                this.mVpnType = type;
        }
 
+       public String getIkeProposal()
+       {
+               return mIkeProposal;
+       }
+
+       public void setIkeProposal(String proposal)
+       {
+               this.mIkeProposal = proposal;
+       }
+
+       public String getEspProposal()
+       {
+               return mEspProposal;
+       }
+
+       public void setEspProposal(String proposal)
+       {
+               this.mEspProposal = proposal;
+       }
+
        public String getUsername()
        {
                return mUsername;
index d31ad3c..2fef577 100644 (file)
@@ -53,6 +53,8 @@ public class VpnProfileDataSource
        public static final String KEY_SELECTED_APPS_LIST = "selected_apps_list";
        public static final String KEY_NAT_KEEPALIVE = "nat_keepalive";
        public static final String KEY_FLAGS = "flags";
+       public static final String KEY_IKE_PROPOSAL = "ike_proposal";
+       public static final String KEY_ESP_PROPOSAL = "esp_proposal";
 
        private DatabaseHelper mDbHelper;
        private SQLiteDatabase mDatabase;
@@ -61,7 +63,7 @@ public class VpnProfileDataSource
        private static final String DATABASE_NAME = "strongswan.db";
        private static final String TABLE_VPNPROFILE = "vpnprofile";
 
-       private static final int DATABASE_VERSION = 14;
+       private static final int DATABASE_VERSION = 15;
 
        public static final DbColumn[] COLUMNS = new DbColumn[] {
                                                                new DbColumn(KEY_ID, "INTEGER PRIMARY KEY AUTOINCREMENT", 1),
@@ -84,6 +86,8 @@ public class VpnProfileDataSource
                                                                new DbColumn(KEY_SELECTED_APPS_LIST, "TEXT", 12),
                                                                new DbColumn(KEY_NAT_KEEPALIVE, "INTEGER", 13),
                                                                new DbColumn(KEY_FLAGS, "INTEGER", 14),
+                                                               new DbColumn(KEY_IKE_PROPOSAL, "TEXT", 15),
+                                                               new DbColumn(KEY_ESP_PROPOSAL, "TEXT", 15),
                                                        };
 
        private static final String[] ALL_COLUMNS = getColumns(DATABASE_VERSION);
@@ -212,6 +216,13 @@ public class VpnProfileDataSource
                                db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_FLAGS +
                                                   " INTEGER;");
                        }
+                       if (oldVersion < 15)
+                       {
+                               db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_IKE_PROPOSAL +
+                                                  " TEXT;");
+                               db.execSQL("ALTER TABLE " + TABLE_VPNPROFILE + " ADD " + KEY_ESP_PROPOSAL +
+                                                  " TEXT;");
+                       }
                }
 
                private void updateColumns(SQLiteDatabase db, int version)
@@ -393,6 +404,8 @@ public class VpnProfileDataSource
                profile.setSelectedApps(cursor.getString(cursor.getColumnIndex(KEY_SELECTED_APPS_LIST)));
                profile.setNATKeepAlive(getInt(cursor, cursor.getColumnIndex(KEY_NAT_KEEPALIVE)));
                profile.setFlags(getInt(cursor, cursor.getColumnIndex(KEY_FLAGS)));
+               profile.setIkeProposal(cursor.getString(cursor.getColumnIndex(KEY_IKE_PROPOSAL)));
+               profile.setEspProposal(cursor.getString(cursor.getColumnIndex(KEY_ESP_PROPOSAL)));
                return profile;
        }
 
@@ -418,6 +431,8 @@ public class VpnProfileDataSource
                values.put(KEY_SELECTED_APPS_LIST, profile.getSelectedApps());
                values.put(KEY_NAT_KEEPALIVE, profile.getNATKeepAlive());
                values.put(KEY_FLAGS, profile.getFlags());
+               values.put(KEY_IKE_PROPOSAL, profile.getIkeProposal());
+               values.put(KEY_ESP_PROPOSAL, profile.getEspProposal());
                return values;
        }
 
index 61535ff..b6e7e2d 100644 (file)
@@ -261,6 +261,8 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
                                                        writer.setValue("connection.local_id", mCurrentProfile.getLocalId());
                                                        writer.setValue("connection.remote_id", mCurrentProfile.getRemoteId());
                                                        writer.setValue("connection.certreq", (mCurrentProfile.getFlags() & VpnProfile.FLAGS_SUPPRESS_CERT_REQS) == 0);
+                                                       writer.setValue("connection.ike_proposal", mCurrentProfile.getIkeProposal());
+                                                       writer.setValue("connection.esp_proposal", mCurrentProfile.getEspProposal());
                                                        initiate(writer.serialize());
                                                }
                                                else
@@ -1071,28 +1073,4 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
        {
                return Build.MODEL + " - " + Build.BRAND + "/" + Build.PRODUCT + "/" + Build.MANUFACTURER;
        }
-
-       /*
-        * The libraries are extracted to /data/data/org.strongswan.android/...
-        * during installation.  On newer releases most are loaded in JNI_OnLoad.
-        */
-       static
-       {
-               if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2)
-               {
-                       System.loadLibrary("strongswan");
-
-                       if (MainActivity.USE_BYOD)
-                       {
-                               System.loadLibrary("tpmtss");
-                               System.loadLibrary("tncif");
-                               System.loadLibrary("tnccs");
-                               System.loadLibrary("imcv");
-                       }
-
-                       System.loadLibrary("charon");
-                       System.loadLibrary("ipsec");
-               }
-               System.loadLibrary("androidbridge");
-       }
 }
index d642b67..19711e4 100644 (file)
@@ -18,9 +18,11 @@ package org.strongswan.android.logic;
 import java.security.Security;
 
 import org.strongswan.android.security.LocalCertificateKeyStoreProvider;
+import org.strongswan.android.ui.MainActivity;
 
 import android.app.Application;
 import android.content.Context;
+import android.os.Build;
 
 public class StrongSwanApplication extends Application
 {
@@ -45,4 +47,28 @@ public class StrongSwanApplication extends Application
        {
                return StrongSwanApplication.mContext;
        }
+
+       /*
+        * The libraries are extracted to /data/data/org.strongswan.android/...
+        * during installation.  On newer releases most are loaded in JNI_OnLoad.
+        */
+       static
+       {
+               if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2)
+               {
+                       System.loadLibrary("strongswan");
+
+                       if (MainActivity.USE_BYOD)
+                       {
+                               System.loadLibrary("tpmtss");
+                               System.loadLibrary("tncif");
+                               System.loadLibrary("tnccs");
+                               System.loadLibrary("imcv");
+                       }
+
+                       System.loadLibrary("charon");
+                       System.loadLibrary("ipsec");
+               }
+               System.loadLibrary("androidbridge");
+       }
 }
index 8792fd7..37c5b33 100644 (file)
@@ -37,6 +37,7 @@ import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.text.method.LinkMovementMethod;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -69,6 +70,7 @@ import org.strongswan.android.ui.adapter.CertificateIdentitiesAdapter;
 import org.strongswan.android.ui.widget.TextInputLayoutHelper;
 import org.strongswan.android.utils.Constants;
 import org.strongswan.android.utils.IPRangeSet;
+import org.strongswan.android.utils.Utils;
 
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
@@ -126,6 +128,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity
        private CheckBox mBlockIPv6;
        private Spinner mSelectSelectedAppsHandling;
        private RelativeLayout mSelectApps;
+       private TextInputLayoutHelper mIkeProposalWrap;
+       private EditText mIkeProposal;
+       private TextInputLayoutHelper mEspProposalWrap;
+       private EditText mEspProposal;
 
        @Override
        public void onCreate(Bundle savedInstanceState)
@@ -181,6 +187,13 @@ public class VpnProfileDetailActivity extends AppCompatActivity
                mSelectSelectedAppsHandling = (Spinner)findViewById(R.id.apps_handling);
                mSelectApps = (RelativeLayout)findViewById(R.id.select_applications);
 
+               mIkeProposal = (EditText)findViewById(R.id.ike_proposal);
+               mIkeProposalWrap = (TextInputLayoutHelper)findViewById(R.id.ike_proposal_wrap);
+               mEspProposal = (EditText)findViewById(R.id.esp_proposal);
+               mEspProposalWrap = (TextInputLayoutHelper)findViewById(R.id.esp_proposal_wrap);
+               /* make the link clickable */
+               ((TextView)findViewById(R.id.proposal_intro)).setMovementMethod(LinkMovementMethod.getInstance());
+
                final SpaceTokenizer spaceTokenizer = new SpaceTokenizer();
                mName.setTokenizer(spaceTokenizer);
                mRemoteId.setTokenizer(spaceTokenizer);
@@ -546,7 +559,8 @@ public class VpnProfileDetailActivity extends AppCompatActivity
                                   mProfile.getPort() != null || mProfile.getNATKeepAlive() != null ||
                                   (flags != null && flags != 0) || (st != null && st != 0) ||
                                   mProfile.getIncludedSubnets() != null || mProfile.getExcludedSubnets() != null ||
-                                  mProfile.getSelectedAppsHandling() != SelectedAppsHandling.SELECTED_APPS_DISABLE;
+                                  mProfile.getSelectedAppsHandling() != SelectedAppsHandling.SELECTED_APPS_DISABLE ||
+                                  mProfile.getIkeProposal() != null || mProfile.getEspProposal() != null;
                }
                mShowAdvanced.setVisibility(!show ? View.VISIBLE : View.GONE);
                mAdvancedSettings.setVisibility(show ? View.VISIBLE : View.GONE);
@@ -640,6 +654,16 @@ public class VpnProfileDetailActivity extends AppCompatActivity
                                                                                                         Constants.NAT_KEEPALIVE_MIN, Constants.NAT_KEEPALIVE_MAX));
                        valid = false;
                }
+               if (!validateProposal(mIkeProposal, true))
+               {
+                       mIkeProposalWrap.setError(getString(R.string.alert_text_no_proposal));
+                       valid = false;
+               }
+               if (!validateProposal(mEspProposal, false))
+               {
+                       mEspProposalWrap.setError(getString(R.string.alert_text_no_proposal));
+                       valid = false;
+               }
                return valid;
        }
 
@@ -686,6 +710,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity
                mProfile.setSplitTunneling(st == 0 ? null : st);
                mProfile.setSelectedAppsHandling(mSelectedAppsHandling);
                mProfile.setSelectedApps(mSelectedApps);
+               String ike = mIkeProposal.getText().toString().trim();
+               mProfile.setIkeProposal(ike.isEmpty() ? null : ike);
+               String esp = mEspProposal.getText().toString().trim();
+               mProfile.setEspProposal(esp.isEmpty() ? null : esp);
        }
 
        /**
@@ -719,6 +747,8 @@ public class VpnProfileDetailActivity extends AppCompatActivity
                                mBlockIPv6.setChecked(mProfile.getSplitTunneling() != null && (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6) != 0);
                                mSelectedAppsHandling = mProfile.getSelectedAppsHandling();
                                mSelectedApps = mProfile.getSelectedAppsSet();
+                               mIkeProposal.setText(mProfile.getIkeProposal());
+                               mEspProposal.setText(mProfile.getEspProposal());
                                flags = mProfile.getFlags();
                                useralias = mProfile.getUserCertificateAlias();
                                local_id = mProfile.getLocalId();
@@ -826,6 +856,17 @@ public class VpnProfileDetailActivity extends AppCompatActivity
                return value.isEmpty() || IPRangeSet.fromString(value) != null;
        }
 
+       /**
+        * Check that the value in the given text box is a valid proposal
+        *
+        * @param view text box
+        */
+       private boolean validateProposal(EditText view, boolean ike)
+       {
+               String value = view.getText().toString().trim();
+               return value.isEmpty() || Utils.isProposalValid(ike, value);
+       }
+
        private class SelectUserCertOnClickListener implements OnClickListener, KeyChainAliasCallback
        {
                @Override
index cee95c3..43c0035 100644 (file)
@@ -59,6 +59,7 @@ import org.strongswan.android.security.TrustedCertificateEntry;
 import org.strongswan.android.ui.widget.TextInputLayoutHelper;
 import org.strongswan.android.utils.Constants;
 import org.strongswan.android.utils.IPRangeSet;
+import org.strongswan.android.utils.Utils;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -497,6 +498,8 @@ public class VpnProfileImportActivity extends AppCompatActivity
                        }
                }
 
+               profile.setIkeProposal(getProposal(obj, "ike-proposal", true));
+               profile.setEspProposal(getProposal(obj, "esp-proposal", false));
                profile.setMTU(getInteger(obj, "mtu", Constants.MTU_MIN, Constants.MTU_MAX));
                profile.setNATKeepAlive(getInteger(obj, "nat-keepalive", Constants.NAT_KEEPALIVE_MIN, Constants.NAT_KEEPALIVE_MAX));
                JSONObject split = obj.optJSONObject("split-tunneling");
@@ -534,6 +537,19 @@ public class VpnProfileImportActivity extends AppCompatActivity
                return res < min || res > max ? null : res;
        }
 
+       private String getProposal(JSONObject obj, String key, boolean ike) throws JSONException
+       {
+               String value = obj.optString(key, null);
+               if (!TextUtils.isEmpty(value))
+               {
+                       if (!Utils.isProposalValid(ike, value))
+                       {
+                               throw new JSONException(getString(R.string.profile_import_failed_value, key));
+                       }
+               }
+               return value;
+       }
+
        private String getSubnets(JSONObject split, String key) throws JSONException
        {
                ArrayList<String> subnets = new ArrayList<>();
index b5c447f..f2e8e00 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2014-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -37,4 +37,13 @@ public class Utils
                }
                return new String(hex);
        }
+
+       /**
+        * Validate the given proposal string
+        *
+        * @param ike true for IKE, false for ESP
+        * @param proposal proposal string
+        * @return true if valid
+        */
+       public native static boolean isProposalValid(boolean ike, String proposal);
 }
index cbf36da..986854c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2016 Tobias Brunner
+ * Copyright (C) 2010-2017 Tobias Brunner
  * Copyright (C) 2012 Giuliano Grassi
  * Copyright (C) 2012 Ralf Sager
  * HSR Hochschule fuer Technik Rapperswil
@@ -707,6 +707,27 @@ static bool add_auth_cfg_cert(private_android_service_t *this,
        return TRUE;
 }
 
+static proposal_t *parse_proposal(private_android_service_t *this,
+                                                                 protocol_id_t proto, char *opt)
+{
+       proposal_t *proposal = NULL;
+       char *prop;
+
+       prop = this->settings->get_str(this->settings, opt, NULL);
+       if (!prop || !strlen(prop))
+       {
+               return NULL;
+       }
+
+       proposal = proposal_create_from_string(proto, prop);
+       if (!proposal)
+       {
+               DBG1(DBG_CFG, "invalid %N proposal '%s', falling back to defaults",
+                        protocol_id_names, proto, prop);
+       }
+       return proposal;
+}
+
 static job_requeue_t initiate(private_android_service_t *this)
 {
        identification_t *gateway = NULL;
@@ -714,6 +735,7 @@ static job_requeue_t initiate(private_android_service_t *this)
        peer_cfg_t *peer_cfg;
        child_cfg_t *child_cfg;
        traffic_selector_t *ts;
+       proposal_t *proposal;
        ike_sa_t *ike_sa;
        auth_cfg_t *auth;
        peer_cfg_create_t peer = {
@@ -747,8 +769,16 @@ static job_requeue_t initiate(private_android_service_t *this)
        ike_cfg = ike_cfg_create(IKEV2, certreq, TRUE, "0.0.0.0",
                                                         charon->socket->get_port(charon->socket, FALSE),
                                                         server, port, FRAGMENTATION_YES, 0);
-       ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
-       ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
+       proposal = parse_proposal(this, PROTO_IKE, "connection.ike_proposal");
+       if (proposal)
+       {
+               ike_cfg->add_proposal(ike_cfg, proposal);
+       }
+       else
+       {
+               ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+               ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
+       }
 
        peer_cfg = peer_cfg_create("android", ike_cfg, &peer);
        peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
@@ -795,27 +825,34 @@ static job_requeue_t initiate(private_android_service_t *this)
        peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
 
        child_cfg = child_cfg_create("android", &child);
-       /* create ESP proposals with and without DH groups, let responder decide
-        * if PFS is used */
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes128gcm16-aes256gcm16-chacha20poly1305-"
-                                                       "curve25519-ecp256-modp3072"));
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes128-sha256-curve25519-ecp256-modp3072"));
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes256-sha384-ecp521-modp8192"));
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes128-aes192-aes256-sha1-sha256-sha384-sha512-"
-                                                       "curve25519-ecp256-ecp384-ecp521-"
-                                                       "modp2048-modp3072-modp4096"));
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes128gcm16-aes256gcm16-chacha20poly1305"));
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes128-sha256"));
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes256-sha384"));
-       child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
-                                                       "aes128-aes192-aes256-sha1-sha256-sha384-sha512"));
+       proposal = parse_proposal(this, PROTO_ESP, "connection.esp_proposal");
+       if (proposal)
+       {
+               child_cfg->add_proposal(child_cfg, proposal);
+       }
+       else
+       {       /* create ESP proposals with and without DH groups, let responder decide
+                * if PFS is used */
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes128gcm16-aes256gcm16-chacha20poly1305-"
+                                                               "curve25519-ecp256-modp3072"));
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes128-sha256-curve25519-ecp256-modp3072"));
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes256-sha384-ecp521-modp8192"));
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes128-aes192-aes256-sha1-sha256-sha384-sha512-"
+                                                               "curve25519-ecp256-ecp384-ecp521-"
+                                                               "modp2048-modp3072-modp4096"));
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes128gcm16-aes256gcm16-chacha20poly1305"));
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes128-sha256"));
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes256-sha384"));
+               child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
+                                                               "aes128-aes192-aes256-sha1-sha256-sha384-sha512"));
+       }
        ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
        child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
        ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
index 6242733..06c5cad 100644 (file)
@@ -712,5 +712,33 @@ JNI_METHOD(CharonVpnService, initiate, void,
 
        config = androidjni_convert_jstring(env, jconfig);
        settings = settings_create_string(config);
+       free(config);
+
        initiate(settings);
 }
+
+/**
+ * Utility function to verify proposal strings (static, so `this` is the class)
+ */
+JNI_METHOD_P(org_strongswan_android_utils, Utils, isProposalValid, jboolean,
+       jboolean ike, jstring proposal)
+{
+       proposal_t *prop;
+       char *str;
+       bool valid;
+
+       dbg = dbg_android;
+
+       if (!library_init(NULL, "charon"))
+       {
+               library_deinit();
+               return FALSE;
+       }
+       str = androidjni_convert_jstring(env, proposal);
+       prop = proposal_create_from_string(ike ? PROTO_IKE : PROTO_ESP, str);
+       valid = prop != NULL;
+       DESTROY_IF(prop);
+       free(str);
+       library_deinit();
+       return valid;
+}
index f765dbc..d4d8831 100644 (file)
                 android:id="@+id/select_applications"
                 layout="@layout/two_line_button" />
 
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:layout_marginBottom="10dp"
+                android:layout_marginLeft="4dp"
+                android:layout_marginStart="4dp"
+                android:textSize="20sp"
+                android:text="@string/profile_proposals_label" />
+
+            <TextView
+                android:id="@+id/proposal_intro"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                android:layout_marginBottom="10dp"
+                android:layout_marginLeft="4dp"
+                android:textSize="12sp"
+                android:text="@string/profile_proposals_intro" />
+
+            <org.strongswan.android.ui.widget.TextInputLayoutHelper
+                android:id="@+id/ike_proposal_wrap"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                app:helper_text="@string/profile_proposals_ike_hint" >
+
+                <android.support.design.widget.TextInputEditText
+                    android:id="@+id/ike_proposal"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:inputType="textNoSuggestions"
+                    android:hint="@string/profile_proposals_ike_label" />
+
+            </org.strongswan.android.ui.widget.TextInputLayoutHelper>
+
+            <org.strongswan.android.ui.widget.TextInputLayoutHelper
+                android:id="@+id/esp_proposal_wrap"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                app:helper_text="@string/profile_proposals_esp_hint" >
+
+                <android.support.design.widget.TextInputEditText
+                    android:id="@+id/esp_proposal"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:inputType="textNoSuggestions"
+                    android:hint="@string/profile_proposals_esp_label" />
+
+            </org.strongswan.android.ui.widget.TextInputLayoutHelper>
+
         </LinearLayout>
 
     </LinearLayout>
index 84d6bcd..49a0ab4 100644 (file)
     <string name="profile_select_no_apps">Keine Apps ausgewählt</string>
     <string name="profile_select_one_app">Eine App ausgewählt</string>
     <string name="profile_select_x_apps">%1$d Apps ausgewählt</string>
+    <string name="profile_proposals_label">Algorithmen</string>
+    <string name="profile_proposals_intro">Optionale spezifische Algorithmen für IKEv2 und/oder IPsec/ESP die statt der Standardwerte verwendet werden sollen. Eine <a href="https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites">Liste gültiger Algorithmen</a> kann unserem Wiki entnommen werden (nicht alle werden von dieser App unterstützt). Beide Felder erwarten eine Liste von Algorithmen, jeweils mit einem Bindestrich getrennt.</string>
+    <string name="profile_proposals_ike_label">IKEv2 Algorithmen</string>
+    <string name="profile_proposals_ike_hint">Für non-AEAD/klassische Verschlüsselungsalgorithmen wird ein Integritätsalgorithmus, eine pseudozufällige Funktion (PRF, optional, ansonsten wird eine auf dem Integritätsalgorithmus basierende verwendet) und eine Diffie-Hellman Gruppe benötigt (z.B. aes256-sha256-ecp256). Für kombinierte/AEAD Algorithmen wird der Integritätsalgorithmus weggelassen aber eine PRF wird benötigt (z.B. aes256gcm16-prfsha256-ecp256).</string>
+    <string name="profile_proposals_esp_label">IPsec/ESP Algorithmen</string>
+    <string name="profile_proposals_esp_hint">Für non-AEAD/klassische Verschlüsselungsalgorithmen wird ein Integritätsalgorithmus benötigt, eine Diffie-Hellman Gruppe ist optional (z.B. aes256-sha256 oder aes256-sha256-ecp256). Für kombinierte/AEAD Algorithmen wird der Integritätsalgorithmus weggelassen (z.B. aes256gcm16 oder aes256gcm16-ecp256). Falls eine DH Gruppe angegeben wird, kommt während dem IPsec SA Rekeying ein DH Schlüsselaustausch zur Anwendung. Beim initialen Verbindungsaufbau hat eine DH Gruppe hier keinen Einfluss, weil die Schlüssel dort von der IKE SA abgeleitet werden. Deshalb wird eine Fehlkonfiguration mit dem Server erst später während dem Rekeying zu einem Fehler führen.</string>
     <string name="profile_import">VPN Profile importieren</string>
     <string name="profile_import_failed">VPN Profil-Import fehlgeschlagen</string>
     <string name="profile_import_failed_detail">VPN Profil-Import fehlgeschlagen: %1$s</string>
     <string name="alert_text_nocertfound">Bitte wählen Sie eines aus oder aktivieren Sie <i>Automatisch wählen</i></string>
     <string name="alert_text_out_of_range">Bitte geben Sie eine Nummer von %1$d - %2$d ein</string>
     <string name="alert_text_no_subnets">Bitte geben Sie mit Leerzeichen getrennte, gültige Subnetzte und/oder IP-Adressen ein</string>
+    <string name="alert_text_no_proposal">Bitte geben Sie eine mit Bindestrichen getrennte, gültige Liste von Algorithmen ein</string>
     <string name="tnc_notice_title">EAP-TNC kann Ihre Privatsphäre beeinträchtigen</string>
     <string name="tnc_notice_subtitle">Gerätedaten werden an den Server-Betreiber gesendet</string>
     <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) erlaubt Server-Betreibern den Gesundheitszustand von Endgeräten zu prüfen.</p><p>Dazu kann der Betreiber Daten verlangen, wie etwa eine eindeutige Identifikationsnummer, eine Liste der installierten Pakete, Systemeinstellungen oder kryptografische Prüfsummen von Dateien.</p><b>Solche Daten werden nur übermittelt nachdem die Identität des Servers geprüft wurde.</b>]]></string>
index c6a8b53..61fd3f0 100644 (file)
     <string name="profile_select_no_apps">No applications selected</string>
     <string name="profile_select_one_app">One application selected</string>
     <string name="profile_select_x_apps">%1$d applications selected</string>
+    <string name="profile_proposals_label">Algorithms</string>
+    <string name="profile_proposals_intro">Optionally configure specific algorithms to use for IKEv2 and/or IPsec/ESP instead of the defaults. Refer to our wiki for a <a href="https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites">list of algorithm identifiers</a> (note that not all are supported by this app). Both fields take a list of algorithms, each separated by a hyphen.</string>
+    <string name="profile_proposals_ike_label">IKEv2 Algorithms</string>
+    <string name="profile_proposals_ike_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm, a pseudo random function (optional, defaults to one based on the integrity algorithm) and a Diffie-Hellman group are required (e.g. aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted but a PRF is required (e.g. aes256gcm16-prfsha256-ecp256).</string>
+    <string name="profile_proposals_esp_label">IPsec/ESP Algorithms</string>
+    <string name="profile_proposals_esp_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm is required, a Diffie-Hellman group is optional (e.g. aes256-sha256 or aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted (e.g. aes256gcm16 or aes256gcm16-ecp256). If a DH group is specified IPsec SA rekeying will use a DH key exchange. However, DH groups specified here are not used when the connection is established initially because the keys there are derived from the IKE SA key material. Therefore, any configuration mismatch with the server will only cause errors later during rekeying.</string>
     <string name="profile_import">Import VPN profile</string>
     <string name="profile_import_failed">Failed to import VPN profile</string>
     <string name="profile_import_failed_detail">Failed to import VPN profile: %1$s</string>
     <string name="alert_text_nocertfound">Wybierz lub uaktywnij jeden <i>Wybierz automatycznie</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="alert_text_no_subnets">Please enter valid subnets and/or IP addresses, separated by spaces</string>
+    <string name="alert_text_no_proposal">Please enter a valid list of algorithms, separated by hyphens</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
     <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
     <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.</p><p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.</p><b>Any data will be sent only after verifying the server\'s identity.</b>]]></string>
index b47c499..a2b3ada 100644 (file)
     <string name="profile_select_no_apps">No applications selected</string>
     <string name="profile_select_one_app">One application selected</string>
     <string name="profile_select_x_apps">%1$d applications selected</string>
+    <string name="profile_proposals_label">Algorithms</string>
+    <string name="profile_proposals_intro">Optionally configure specific algorithms to use for IKEv2 and/or IPsec/ESP instead of the defaults. Refer to our wiki for a <a href="https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites">list of algorithm identifiers</a> (note that not all are supported by this app). Both fields take a list of algorithms, each separated by a hyphen.</string>
+    <string name="profile_proposals_ike_label">IKEv2 Algorithms</string>
+    <string name="profile_proposals_ike_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm, a pseudo random function (optional, defaults to one based on the integrity algorithm) and a Diffie-Hellman group are required (e.g. aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted but a PRF is required (e.g. aes256gcm16-prfsha256-ecp256).</string>
+    <string name="profile_proposals_esp_label">IPsec/ESP Algorithms</string>
+    <string name="profile_proposals_esp_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm is required, a Diffie-Hellman group is optional (e.g. aes256-sha256 or aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted (e.g. aes256gcm16 or aes256gcm16-ecp256). If a DH group is specified IPsec SA rekeying will use a DH key exchange. However, DH groups specified here are not used when the connection is established initially because the keys there are derived from the IKE SA key material. Therefore, any configuration mismatch with the server will only cause errors later during rekeying.</string>
     <string name="profile_import">Import VPN profile</string>
     <string name="profile_import_failed">Failed to import VPN profile</string>
     <string name="profile_import_failed_detail">Failed to import VPN profile: %1$s</string>
     <string name="alert_text_nocertfound">Пожалуйста выберите один <i>Выбрать автоматически</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="alert_text_no_subnets">Please enter valid subnets and/or IP addresses, separated by spaces</string>
+    <string name="alert_text_no_proposal">Please enter a valid list of algorithms, separated by hyphens</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
     <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
     <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.</p><p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.</p><b>Any data will be sent only after verifying the server\'s identity.</b>]]></string>
index 69258b0..bfe4719 100644 (file)
     <string name="profile_select_no_apps">No applications selected</string>
     <string name="profile_select_one_app">One application selected</string>
     <string name="profile_select_x_apps">%1$d applications selected</string>
+    <string name="profile_proposals_label">Algorithms</string>
+    <string name="profile_proposals_intro">Optionally configure specific algorithms to use for IKEv2 and/or IPsec/ESP instead of the defaults. Refer to our wiki for a <a href="https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites">list of algorithm identifiers</a> (note that not all are supported by this app). Both fields take a list of algorithms, each separated by a hyphen.</string>
+    <string name="profile_proposals_ike_label">IKEv2 Algorithms</string>
+    <string name="profile_proposals_ike_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm, a pseudo random function (optional, defaults to one based on the integrity algorithm) and a Diffie-Hellman group are required (e.g. aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted but a PRF is required (e.g. aes256gcm16-prfsha256-ecp256).</string>
+    <string name="profile_proposals_esp_label">IPsec/ESP Algorithms</string>
+    <string name="profile_proposals_esp_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm is required, a Diffie-Hellman group is optional (e.g. aes256-sha256 or aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted (e.g. aes256gcm16 or aes256gcm16-ecp256). If a DH group is specified IPsec SA rekeying will use a DH key exchange. However, DH groups specified here are not used when the connection is established initially because the keys there are derived from the IKE SA key material. Therefore, any configuration mismatch with the server will only cause errors later during rekeying.</string>
     <string name="profile_import">Import VPN profile</string>
     <string name="profile_import_failed">Failed to import VPN profile</string>
     <string name="profile_import_failed_detail">Failed to import VPN profile: %1$s</string>
     <string name="alert_text_nocertfound">Будь ласка виберіть один <i>Вибрати автоматично</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="alert_text_no_subnets">Please enter valid subnets and/or IP addresses, separated by spaces</string>
+    <string name="alert_text_no_proposal">Please enter a valid list of algorithms, separated by hyphens</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
     <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
     <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.</p><p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.</p><b>Any data will be sent only after verifying the server\'s identity.</b>]]></string>
index a88e7aa..bda7324 100644 (file)
     <string name="profile_select_no_apps">No applications selected</string>
     <string name="profile_select_one_app">One application selected</string>
     <string name="profile_select_x_apps">%1$d applications selected</string>
+    <string name="profile_proposals_label">Algorithms</string>
+    <string name="profile_proposals_intro">Optionally configure specific algorithms to use for IKEv2 and/or IPsec/ESP instead of the defaults. Refer to our wiki for a <a href="https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites">list of algorithm identifiers</a> (note that not all are supported by this app). Both fields take a list of algorithms, each separated by a hyphen.</string>
+    <string name="profile_proposals_ike_label">IKEv2 Algorithms</string>
+    <string name="profile_proposals_ike_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm, a pseudo random function (optional, defaults to one based on the integrity algorithm) and a Diffie-Hellman group are required (e.g. aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted but a PRF is required (e.g. aes256gcm16-prfsha256-ecp256).</string>
+    <string name="profile_proposals_esp_label">IPsec/ESP Algorithms</string>
+    <string name="profile_proposals_esp_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm is required, a Diffie-Hellman group is optional (e.g. aes256-sha256 or aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted (e.g. aes256gcm16 or aes256gcm16-ecp256). If a DH group is specified IPsec SA rekeying will use a DH key exchange. However, DH groups specified here are not used when the connection is established initially because the keys there are derived from the IKE SA key material. Therefore, any configuration mismatch with the server will only cause errors later during rekeying.</string>
     <string name="profile_import">导入VPN配置</string>
     <string name="profile_import_failed">导入VPN配置失败</string>
     <string name="profile_import_failed_detail">导入VPN配置失败: %1$s</string>
     <string name="alert_text_nocertfound">请选择一项或激活 <i>自动选择</i></string>
     <string name="alert_text_out_of_range">请输入一个数字范围从%1$d到%2$d</string>
     <string name="alert_text_no_subnets">Please enter valid subnets and/or IP addresses, separated by spaces</string>
+    <string name="alert_text_no_proposal">Please enter a valid list of algorithms, separated by hyphens</string>
     <string name="tnc_notice_title">EAP-TNC可能会影响您的隐私</string>
     <string name="tnc_notice_subtitle">设备数据已被发送至服务器管理员</string>
     <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) 允许服务器管理员评定一个用户设备的状况。</p><p>出于此目的,服务器管理员可能要求以下数据如独立ID、已安装软件列表、系统设置、或加密过的文件校验值。</p><b>任何数据都仅将在验证过服务器的身份ID之后被发出。</b>]]></string>
index 8ef0feb..2d49923 100644 (file)
     <string name="profile_select_no_apps">No applications selected</string>
     <string name="profile_select_one_app">One application selected</string>
     <string name="profile_select_x_apps">%1$d applications selected</string>
+    <string name="profile_proposals_label">Algorithms</string>
+    <string name="profile_proposals_intro">Optionally configure specific algorithms to use for IKEv2 and/or IPsec/ESP instead of the defaults. Refer to our wiki for a <a href="https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites">list of algorithm identifiers</a> (note that not all are supported by this app). Both fields take a list of algorithms, each separated by a hyphen.</string>
+    <string name="profile_proposals_ike_label">IKEv2 Algorithms</string>
+    <string name="profile_proposals_ike_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm, a pseudo random function (optional, defaults to one based on the integrity algorithm) and a Diffie-Hellman group are required (e.g. aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted but a PRF is required (e.g. aes256gcm16-prfsha256-ecp256).</string>
+    <string name="profile_proposals_esp_label">IPsec/ESP Algorithms</string>
+    <string name="profile_proposals_esp_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm is required, a Diffie-Hellman group is optional (e.g. aes256-sha256 or aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted (e.g. aes256gcm16 or aes256gcm16-ecp256). If a DH group is specified IPsec SA rekeying will use a DH key exchange. However, DH groups specified here are not used when the connection is established initially because the keys there are derived from the IKE SA key material. Therefore, any configuration mismatch with the server will only cause errors later during rekeying.</string>
     <string name="profile_import">匯入VPN設定檔</string>
     <string name="profile_import_failed">匯入VPN設定檔失敗</string>
     <string name="profile_import_failed_detail">匯入VPN設定檔失敗: %1$s</string>
     <string name="alert_text_nocertfound">請選擇一項或啟動 <i>自動選擇</i></string>
     <string name="alert_text_out_of_range">請輸入一個數字範圍從%1$d到%2$d</string>
     <string name="alert_text_no_subnets">Please enter valid subnets and/or IP addresses, separated by spaces</string>
+    <string name="alert_text_no_proposal">Please enter a valid list of algorithms, separated by hyphens</string>
     <string name="tnc_notice_title">EAP-TNC可能會影響您的隱私安全</string>
     <string name="tnc_notice_subtitle">裝置資料已經發送給伺服器管理者</string>
     <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) 可以讓伺服器管理者評估用戶裝置的狀況。</p><p>在這個目的下,伺服器管理者可能會要求以下資料,例如ID、已安裝的App項目、系統設定、或加密檔案驗證值。</p><b>任何資料都只有在驗證伺服器的身分ID之後才會被送出。</b>]]></string>
index a02de6b..dd22d3b 100644 (file)
     <string name="profile_select_no_apps">No applications selected</string>
     <string name="profile_select_one_app">One application selected</string>
     <string name="profile_select_x_apps">%1$d applications selected</string>
+    <string name="profile_proposals_label">Algorithms</string>
+    <string name="profile_proposals_intro">Optionally configure specific algorithms to use for IKEv2 and/or IPsec/ESP instead of the defaults. Refer to our wiki for a <a href="https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites">list of algorithm identifiers</a> (note that not all are supported by this app). Both fields take a list of algorithms, each separated by a hyphen.</string>
+    <string name="profile_proposals_ike_label">IKEv2 Algorithms</string>
+    <string name="profile_proposals_ike_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm, a pseudo random function (optional, defaults to one based on the integrity algorithm) and a Diffie-Hellman group are required (e.g. aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted but a PRF is required (e.g. aes256gcm16-prfsha256-ecp256).</string>
+    <string name="profile_proposals_esp_label">IPsec/ESP Algorithms</string>
+    <string name="profile_proposals_esp_hint">For non-AEAD/classic encryption algorithms, an integrity algorithm is required, a Diffie-Hellman group is optional (e.g. aes256-sha256 or aes256-sha256-ecp256). For combined-mode/AEAD algorithms, the integrity algorithm is omitted (e.g. aes256gcm16 or aes256gcm16-ecp256). If a DH group is specified IPsec SA rekeying will use a DH key exchange. However, DH groups specified here are not used when the connection is established initially because the keys there are derived from the IKE SA key material. Therefore, any configuration mismatch with the server will only cause errors later during rekeying.</string>
     <string name="profile_import">Import VPN profile</string>
     <string name="profile_import_failed">Failed to import VPN profile</string>
     <string name="profile_import_failed_detail">Failed to import VPN profile: %1$s</string>
     <string name="alert_text_nocertfound">Please select one or activate <i>Select automatically</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="alert_text_no_subnets">Please enter valid subnets and/or IP addresses, separated by spaces</string>
+    <string name="alert_text_no_proposal">Please enter a valid list of algorithms, separated by hyphens</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
     <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
     <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.</p><p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.</p><b>Any data will be sent only after verifying the server\'s identity.</b>]]></string>
index f381860..d1fb337 100644 (file)
@@ -16,7 +16,6 @@ config/backend_manager.c config/backend_manager.h config/backend.h \
 config/child_cfg.c config/child_cfg.h \
 config/ike_cfg.c config/ike_cfg.h \
 config/peer_cfg.c config/peer_cfg.h \
-config/proposal.c config/proposal.h \
 control/controller.c control/controller.h \
 daemon.c daemon.h \
 encoding/generator.c encoding/generator.h \
index 964a19e..fe28f1e 100644 (file)
@@ -14,7 +14,6 @@ config/backend_manager.c config/backend_manager.h config/backend.h \
 config/child_cfg.c config/child_cfg.h \
 config/ike_cfg.c config/ike_cfg.h \
 config/peer_cfg.c config/peer_cfg.h \
-config/proposal.c config/proposal.h \
 control/controller.c control/controller.h \
 daemon.c daemon.h \
 encoding/generator.c encoding/generator.h \
index 93904ec..e2834fa 100644 (file)
@@ -31,7 +31,7 @@ typedef struct child_cfg_create_t child_cfg_create_t;
 
 #include <library.h>
 #include <selectors/traffic_selector.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <kernel/kernel_ipsec.h>
 
 /**
index 034996f..3020244 100644 (file)
@@ -31,7 +31,7 @@ typedef struct ike_cfg_t ike_cfg_t;
 #include <networking/host.h>
 #include <collections/linked_list.h>
 #include <utils/identification.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <crypto/diffie_hellman.h>
 
 /**
index b294ae7..6074a7c 100644 (file)
@@ -32,7 +32,7 @@ typedef struct peer_cfg_create_t peer_cfg_create_t;
 #include <utils/identification.h>
 #include <collections/enumerator.h>
 #include <selectors/traffic_selector.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <config/ike_cfg.h>
 #include <config/child_cfg.h>
 #include <credentials/auth_cfg.h>
diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c
deleted file mode 100644 (file)
index 46c3c94..0000000
+++ /dev/null
@@ -1,1103 +0,0 @@
-/*
- * Copyright (C) 2008-2016 Tobias Brunner
- * Copyright (C) 2006-2010 Martin Willi
- * Copyright (C) 2013-2015 Andreas Steffen
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include <string.h>
-
-#include "proposal.h"
-
-#include <daemon.h>
-#include <collections/array.h>
-#include <utils/identification.h>
-
-#include <crypto/transform.h>
-#include <crypto/prfs/prf.h>
-#include <crypto/crypters/crypter.h>
-#include <crypto/signers/signer.h>
-
-ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
-       "PROTO_NONE",
-       "IKE",
-       "AH",
-       "ESP",
-       "IPCOMP",
-);
-
-typedef struct private_proposal_t private_proposal_t;
-
-/**
- * Private data of an proposal_t object
- */
-struct private_proposal_t {
-
-       /**
-        * Public part
-        */
-       proposal_t public;
-
-       /**
-        * protocol (ESP or AH)
-        */
-       protocol_id_t protocol;
-
-       /**
-        * Priority ordered list of transforms, as entry_t
-        */
-       array_t *transforms;
-
-       /**
-        * senders SPI
-        */
-       uint64_t spi;
-
-       /**
-        * Proposal number
-        */
-       u_int number;
-};
-
-/**
- * Struct used to store different kinds of algorithms.
- */
-typedef struct {
-       /** Type of the transform */
-       transform_type_t type;
-       /** algorithm identifier */
-       uint16_t alg;
-       /** key size in bits, or zero if not needed */
-       uint16_t key_size;
-} entry_t;
-
-METHOD(proposal_t, add_algorithm, void,
-       private_proposal_t *this, transform_type_t type,
-       uint16_t alg, uint16_t key_size)
-{
-       entry_t entry = {
-               .type = type,
-               .alg = alg,
-               .key_size = key_size,
-       };
-
-       array_insert(this->transforms, ARRAY_TAIL, &entry);
-}
-
-CALLBACK(alg_filter, bool,
-       uintptr_t type, enumerator_t *orig, va_list args)
-{
-       entry_t *entry;
-       uint16_t *alg, *key_size;
-
-       VA_ARGS_VGET(args, alg, key_size);
-
-       while (orig->enumerate(orig, &entry))
-       {
-               if (entry->type != type)
-               {
-                       continue;
-               }
-               if (alg)
-               {
-                       *alg = entry->alg;
-               }
-               if (key_size)
-               {
-                       *key_size = entry->key_size;
-               }
-               return TRUE;
-       }
-       return FALSE;
-}
-
-METHOD(proposal_t, create_enumerator, enumerator_t*,
-       private_proposal_t *this, transform_type_t type)
-{
-       return enumerator_create_filter(
-                                               array_create_enumerator(this->transforms),
-                                               alg_filter, (void*)(uintptr_t)type, NULL);
-}
-
-METHOD(proposal_t, get_algorithm, bool,
-       private_proposal_t *this, transform_type_t type,
-       uint16_t *alg, uint16_t *key_size)
-{
-       enumerator_t *enumerator;
-       bool found = FALSE;
-
-       enumerator = create_enumerator(this, type);
-       if (enumerator->enumerate(enumerator, alg, key_size))
-       {
-               found = TRUE;
-       }
-       enumerator->destroy(enumerator);
-
-       return found;
-}
-
-METHOD(proposal_t, has_dh_group, bool,
-       private_proposal_t *this, diffie_hellman_group_t group)
-{
-       bool found = FALSE, any = FALSE;
-       enumerator_t *enumerator;
-       uint16_t current;
-
-       enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
-       while (enumerator->enumerate(enumerator, &current, NULL))
-       {
-               any = TRUE;
-               if (current == group)
-               {
-                       found = TRUE;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       if (!any && group == MODP_NONE)
-       {
-               found = TRUE;
-       }
-       return found;
-}
-
-METHOD(proposal_t, strip_dh, void,
-       private_proposal_t *this, diffie_hellman_group_t keep)
-{
-       enumerator_t *enumerator;
-       entry_t *entry;
-
-       enumerator = array_create_enumerator(this->transforms);
-       while (enumerator->enumerate(enumerator, &entry))
-       {
-               if (entry->type == DIFFIE_HELLMAN_GROUP &&
-                       entry->alg != keep)
-               {
-                       array_remove_at(this->transforms, enumerator);
-               }
-       }
-       enumerator->destroy(enumerator);
-}
-
-/**
- * Select a matching proposal from this and other, insert into selected.
- */
-static bool select_algo(private_proposal_t *this, proposal_t *other,
-                                               proposal_t *selected, transform_type_t type, bool priv)
-{
-       enumerator_t *e1, *e2;
-       uint16_t alg1, alg2, ks1, ks2;
-       bool found = FALSE, optional = FALSE;
-
-       if (type == INTEGRITY_ALGORITHM &&
-               selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
-               encryption_algorithm_is_aead(alg1))
-       {
-               /* no integrity algorithm required, we have an AEAD */
-               return TRUE;
-       }
-       if (type == DIFFIE_HELLMAN_GROUP)
-       {
-               optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
-       }
-
-       e1 = create_enumerator(this, type);
-       e2 = other->create_enumerator(other, type);
-       if (!e1->enumerate(e1, &alg1, NULL))
-       {
-               if (!e2->enumerate(e2, &alg2, NULL))
-               {
-                       found = TRUE;
-               }
-               else if (optional)
-               {
-                       do
-                       {       /* if NONE is proposed, we accept the proposal */
-                               found = !alg2;
-                       }
-                       while (!found && e2->enumerate(e2, &alg2, NULL));
-               }
-       }
-       else if (!e2->enumerate(e2, NULL, NULL))
-       {
-               if (optional)
-               {
-                       do
-                       {       /* if NONE is proposed, we accept the proposal */
-                               found = !alg1;
-                       }
-                       while (!found && e1->enumerate(e1, &alg1, NULL));
-               }
-       }
-
-       e1->destroy(e1);
-       e1 = create_enumerator(this, type);
-       /* compare algs, order of algs in "first" is preferred */
-       while (!found && e1->enumerate(e1, &alg1, &ks1))
-       {
-               e2->destroy(e2);
-               e2 = other->create_enumerator(other, type);
-               while (e2->enumerate(e2, &alg2, &ks2))
-               {
-                       if (alg1 == alg2 && ks1 == ks2)
-                       {
-                               if (!priv && alg1 >= 1024)
-                               {
-                                       /* accept private use algorithms only if requested */
-                                       DBG1(DBG_CFG, "an algorithm from private space would match, "
-                                                "but peer implementation is unknown, skipped");
-                                       continue;
-                               }
-                               selected->add_algorithm(selected, type, alg1, ks1);
-                               found = TRUE;
-                               break;
-                       }
-               }
-       }
-       /* no match in all comparisons */
-       e1->destroy(e1);
-       e2->destroy(e2);
-
-       if (!found)
-       {
-               DBG2(DBG_CFG, "  no acceptable %N found", transform_type_names, type);
-       }
-       return found;
-}
-
-METHOD(proposal_t, select_proposal, proposal_t*,
-       private_proposal_t *this, proposal_t *other, bool other_remote,
-       bool private)
-{
-       proposal_t *selected;
-
-       DBG2(DBG_CFG, "selecting proposal:");
-
-       if (this->protocol != other->get_protocol(other))
-       {
-               DBG2(DBG_CFG, "  protocol mismatch, skipping");
-               return NULL;
-       }
-
-       if (other_remote)
-       {
-               selected = proposal_create(this->protocol, other->get_number(other));
-               selected->set_spi(selected, other->get_spi(other));
-       }
-       else
-       {
-               selected = proposal_create(this->protocol, this->number);
-               selected->set_spi(selected, this->spi);
-
-       }
-
-       if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
-               !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
-               !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
-               !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
-               !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
-       {
-               selected->destroy(selected);
-               return NULL;
-       }
-
-       DBG2(DBG_CFG, "  proposal matches");
-       return selected;
-}
-
-METHOD(proposal_t, get_protocol, protocol_id_t,
-       private_proposal_t *this)
-{
-       return this->protocol;
-}
-
-METHOD(proposal_t, set_spi, void,
-       private_proposal_t *this, uint64_t spi)
-{
-       this->spi = spi;
-}
-
-METHOD(proposal_t, get_spi, uint64_t,
-       private_proposal_t *this)
-{
-       return this->spi;
-}
-
-/**
- * Check if two proposals have the same algorithms for a given transform type
- */
-static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
-                                                        transform_type_t type)
-{
-       enumerator_t *e1, *e2;
-       uint16_t alg1, alg2, ks1, ks2;
-       bool equals = TRUE;
-
-       e1 = create_enumerator(this, type);
-       e2 = other->create_enumerator(other, type);
-       while (e1->enumerate(e1, &alg1, &ks1))
-       {
-               if (!e2->enumerate(e2, &alg2, &ks2))
-               {
-                       /* this has more algs */
-                       equals = FALSE;
-                       break;
-               }
-               if (alg1 != alg2 || ks1 != ks2)
-               {
-                       equals = FALSE;
-                       break;
-               }
-       }
-       if (e2->enumerate(e2, &alg2, &ks2))
-       {
-               /* other has more algs */
-               equals = FALSE;
-       }
-       e1->destroy(e1);
-       e2->destroy(e2);
-
-       return equals;
-}
-
-METHOD(proposal_t, get_number, u_int,
-       private_proposal_t *this)
-{
-       return this->number;
-}
-
-METHOD(proposal_t, equals, bool,
-       private_proposal_t *this, proposal_t *other)
-{
-       if (&this->public == other)
-       {
-               return TRUE;
-       }
-       return (
-               algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
-               algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
-               algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
-               algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
-               algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
-}
-
-METHOD(proposal_t, clone_, proposal_t*,
-       private_proposal_t *this)
-{
-       private_proposal_t *clone;
-       enumerator_t *enumerator;
-       entry_t *entry;
-
-       clone = (private_proposal_t*)proposal_create(this->protocol, 0);
-
-       enumerator = array_create_enumerator(this->transforms);
-       while (enumerator->enumerate(enumerator, &entry))
-       {
-               array_insert(clone->transforms, ARRAY_TAIL, entry);
-       }
-       enumerator->destroy(enumerator);
-
-       clone->spi = this->spi;
-       clone->number = this->number;
-
-       return &clone->public;
-}
-
-/**
- * Map integrity algorithms to the PRF functions using the same algorithm.
- */
-static const struct {
-       integrity_algorithm_t integ;
-       pseudo_random_function_t prf;
-} integ_prf_map[] = {
-       {AUTH_HMAC_SHA1_96,                                     PRF_HMAC_SHA1                                   },
-       {AUTH_HMAC_SHA1_160,                            PRF_HMAC_SHA1                                   },
-       {AUTH_HMAC_SHA2_256_128,                        PRF_HMAC_SHA2_256                               },
-       {AUTH_HMAC_SHA2_384_192,                        PRF_HMAC_SHA2_384                               },
-       {AUTH_HMAC_SHA2_512_256,                        PRF_HMAC_SHA2_512                               },
-       {AUTH_HMAC_MD5_96,                                      PRF_HMAC_MD5                                    },
-       {AUTH_HMAC_MD5_128,                                     PRF_HMAC_MD5                                    },
-       {AUTH_AES_XCBC_96,                                      PRF_AES128_XCBC                                 },
-       {AUTH_CAMELLIA_XCBC_96,                         PRF_CAMELLIA128_XCBC                    },
-       {AUTH_AES_CMAC_96,                                      PRF_AES128_CMAC                                 },
-};
-
-/**
- * Remove all entries of the given transform type
- */
-static void remove_transform(private_proposal_t *this, transform_type_t type)
-{
-       enumerator_t *e;
-       entry_t *entry;
-
-       e = array_create_enumerator(this->transforms);
-       while (e->enumerate(e, &entry))
-       {
-               if (entry->type == type)
-               {
-                       array_remove_at(this->transforms, e);
-               }
-       }
-       e->destroy(e);
-}
-
-/**
- * Checks the proposal read from a string.
- */
-static bool check_proposal(private_proposal_t *this)
-{
-       enumerator_t *e;
-       entry_t *entry;
-       uint16_t alg, ks;
-       bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
-       int i;
-
-       if (this->protocol == PROTO_IKE)
-       {
-               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
-               {       /* No explicit PRF found. We assume the same algorithm as used
-                        * for integrity checking. */
-                       e = create_enumerator(this, INTEGRITY_ALGORITHM);
-                       while (e->enumerate(e, &alg, &ks))
-                       {
-                               for (i = 0; i < countof(integ_prf_map); i++)
-                               {
-                                       if (alg == integ_prf_map[i].integ)
-                                       {
-                                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
-                                                                         integ_prf_map[i].prf, 0);
-                                               break;
-                                       }
-                               }
-                       }
-                       e->destroy(e);
-               }
-               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
-               {
-                       DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
-                       return FALSE;
-               }
-               /* remove MODP_NONE from IKE proposal */
-               e = array_create_enumerator(this->transforms);
-               while (e->enumerate(e, &entry))
-               {
-                       if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
-                       {
-                               array_remove_at(this->transforms, e);
-                       }
-               }
-               e->destroy(e);
-               if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
-               {
-                       DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
-                       return FALSE;
-               }
-       }
-       else
-       {       /* remove PRFs from ESP/AH proposals */
-               remove_transform(this, PSEUDO_RANDOM_FUNCTION);
-       }
-
-       if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
-       {
-               e = create_enumerator(this, ENCRYPTION_ALGORITHM);
-               while (e->enumerate(e, &alg, &ks))
-               {
-                       any_enc = TRUE;
-                       if (encryption_algorithm_is_aead(alg))
-                       {
-                               any_aead = TRUE;
-                               continue;
-                       }
-                       all_aead = FALSE;
-               }
-               e->destroy(e);
-
-               if (!any_enc)
-               {
-                       DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
-                                protocol_id_names, this->protocol);
-                       return FALSE;
-               }
-               else if (any_aead && !all_aead)
-               {
-                       DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
-                                "algorithms can't be contained in the same %N proposal",
-                                protocol_id_names, this->protocol);
-                       return FALSE;
-               }
-               else if (all_aead)
-               {       /* if all encryption algorithms in the proposal are AEADs,
-                        * we MUST NOT propose any integrity algorithms */
-                       remove_transform(this, INTEGRITY_ALGORITHM);
-               }
-       }
-       else
-       {       /* AES-GMAC is parsed as encryption algorithm, so we map that to the
-                * proper integrity algorithm */
-               e = array_create_enumerator(this->transforms);
-               while (e->enumerate(e, &entry))
-               {
-                       if (entry->type == ENCRYPTION_ALGORITHM)
-                       {
-                               if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
-                               {
-                                       entry->type = INTEGRITY_ALGORITHM;
-                                       ks = entry->key_size;
-                                       entry->key_size = 0;
-                                       switch (ks)
-                                       {
-                                               case 128:
-                                                       entry->alg = AUTH_AES_128_GMAC;
-                                                       continue;
-                                               case 192:
-                                                       entry->alg = AUTH_AES_192_GMAC;
-                                                       continue;
-                                               case 256:
-                                                       entry->alg = AUTH_AES_256_GMAC;
-                                                       continue;
-                                               default:
-                                                       break;
-                                       }
-                               }
-                               /* remove all other encryption algorithms */
-                               array_remove_at(this->transforms, e);
-                       }
-               }
-               e->destroy(e);
-
-               if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
-               {
-                       DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
-                                "proposals");
-                       return FALSE;
-               }
-       }
-
-       if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
-       {
-               if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
-               {       /* ESN not specified, assume not supported */
-                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
-               }
-       }
-
-       array_compress(this->transforms);
-       return TRUE;
-}
-
-/**
- * add a algorithm identified by a string to the proposal.
- */
-static bool add_string_algo(private_proposal_t *this, const char *alg)
-{
-       const proposal_token_t *token;
-
-       token = lib->proposal->get_token(lib->proposal, alg);
-       if (token == NULL)
-       {
-               DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
-               return FALSE;
-       }
-
-       add_algorithm(this, token->type, token->algorithm, token->keysize);
-
-       return TRUE;
-}
-
-/**
- * print all algorithms of a kind to buffer
- */
-static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
-                                        u_int kind, void *names, bool *first)
-{
-       enumerator_t *enumerator;
-       size_t written = 0;
-       uint16_t alg, size;
-
-       enumerator = create_enumerator(this, kind);
-       while (enumerator->enumerate(enumerator, &alg, &size))
-       {
-               if (*first)
-               {
-                       written += print_in_hook(data, "%N", names, alg);
-                       *first = FALSE;
-               }
-               else
-               {
-                       written += print_in_hook(data, "/%N", names, alg);
-               }
-               if (size)
-               {
-                       written += print_in_hook(data, "_%u", size);
-               }
-       }
-       enumerator->destroy(enumerator);
-       return written;
-}
-
-/**
- * Described in header.
- */
-int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
-                                                const void *const *args)
-{
-       private_proposal_t *this = *((private_proposal_t**)(args[0]));
-       linked_list_t *list = *((linked_list_t**)(args[0]));
-       enumerator_t *enumerator;
-       size_t written = 0;
-       bool first = TRUE;
-
-       if (this == NULL)
-       {
-               return print_in_hook(data, "(null)");
-       }
-
-       if (spec->hash)
-       {
-               enumerator = list->create_enumerator(list);
-               while (enumerator->enumerate(enumerator, &this))
-               {       /* call recursivly */
-                       if (first)
-                       {
-                               written += print_in_hook(data, "%P", this);
-                               first = FALSE;
-                       }
-                       else
-                       {
-                               written += print_in_hook(data, ", %P", this);
-                       }
-               }
-               enumerator->destroy(enumerator);
-               return written;
-       }
-
-       written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
-       written += print_alg(this, data, ENCRYPTION_ALGORITHM,
-                                                encryption_algorithm_names, &first);
-       written += print_alg(this, data, INTEGRITY_ALGORITHM,
-                                                integrity_algorithm_names, &first);
-       written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION,
-                                                pseudo_random_function_names, &first);
-       written += print_alg(this, data, DIFFIE_HELLMAN_GROUP,
-                                                diffie_hellman_group_names, &first);
-       written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS,
-                                                extended_sequence_numbers_names, &first);
-       return written;
-}
-
-METHOD(proposal_t, destroy, void,
-       private_proposal_t *this)
-{
-       array_destroy(this->transforms);
-       free(this);
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create(protocol_id_t protocol, u_int number)
-{
-       private_proposal_t *this;
-
-       INIT(this,
-               .public = {
-                       .add_algorithm = _add_algorithm,
-                       .create_enumerator = _create_enumerator,
-                       .get_algorithm = _get_algorithm,
-                       .has_dh_group = _has_dh_group,
-                       .strip_dh = _strip_dh,
-                       .select = _select_proposal,
-                       .get_protocol = _get_protocol,
-                       .set_spi = _set_spi,
-                       .get_spi = _get_spi,
-                       .get_number = _get_number,
-                       .equals = _equals,
-                       .clone = _clone_,
-                       .destroy = _destroy,
-               },
-               .protocol = protocol,
-               .number = number,
-               .transforms = array_create(sizeof(entry_t), 0),
-       );
-
-       return &this->public;
-}
-
-/**
- * Add supported IKE algorithms to proposal
- */
-static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
-{
-       enumerator_t *enumerator;
-       encryption_algorithm_t encryption;
-       integrity_algorithm_t integrity;
-       pseudo_random_function_t prf;
-       diffie_hellman_group_t group;
-       const char *plugin_name;
-
-       if (aead)
-       {
-               /* Round 1 adds algorithms with at least 128 bit security strength */
-               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_AES_GCM_ICV16:
-                               case ENCR_AES_CCM_ICV16:
-                               case ENCR_CAMELLIA_CCM_ICV16:
-                                       /* we assume that we support all AES/Camellia sizes */
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               case ENCR_CHACHA20_POLY1305:
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               /* Round 2 adds algorithms with less than 128 bit security strength */
-               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_AES_GCM_ICV12:
-                               case ENCR_AES_GCM_ICV8:
-                               case ENCR_AES_CCM_ICV12:
-                               case ENCR_AES_CCM_ICV8:
-                               case ENCR_CAMELLIA_CCM_ICV12:
-                               case ENCR_CAMELLIA_CCM_ICV8:
-                                       /* we assume that we support all AES/Camellia sizes */
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               if (!array_count(this->transforms))
-               {
-                       return FALSE;
-               }
-       }
-       else
-       {
-               /* Round 1 adds algorithms with at least 128 bit security strength */
-               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_AES_CBC:
-                               case ENCR_AES_CTR:
-                               case ENCR_CAMELLIA_CBC:
-                               case ENCR_CAMELLIA_CTR:
-                                       /* we assume that we support all AES/Camellia sizes */
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               /* Round 2 adds algorithms with less than 128 bit security strength */
-               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
-               {
-                       switch (encryption)
-                       {
-                               case ENCR_3DES:
-                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
-                                       break;
-                               case ENCR_DES:
-                                       /* no, thanks */
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               if (!array_count(this->transforms))
-               {
-                       return FALSE;
-               }
-
-               /* Round 1 adds algorithms with at least 128 bit security strength */
-               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
-               {
-                       switch (integrity)
-                       {
-                               case AUTH_HMAC_SHA2_256_128:
-                               case AUTH_HMAC_SHA2_384_192:
-                               case AUTH_HMAC_SHA2_512_256:
-                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               /* Round 2 adds algorithms with less than 128 bit security strength */
-               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
-               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
-               {
-                       switch (integrity)
-                       {
-                               case AUTH_AES_XCBC_96:
-                               case AUTH_AES_CMAC_96:
-                               case AUTH_HMAC_SHA1_96:
-                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
-                                       break;
-                               case AUTH_HMAC_MD5_96:
-                                       /* no, thanks */
-                               default:
-                                       break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-       }
-
-       /* Round 1 adds algorithms with at least 128 bit security strength */
-       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
-       {
-               switch (prf)
-               {
-                       case PRF_HMAC_SHA2_256:
-                       case PRF_HMAC_SHA2_384:
-                       case PRF_HMAC_SHA2_512:
-                       case PRF_AES128_XCBC:
-                       case PRF_AES128_CMAC:
-                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 2 adds algorithms with less than 128 bit security strength */
-       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
-       {
-               switch (prf)
-               {
-                       case PRF_HMAC_SHA1:
-                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
-                               break;
-                       case PRF_HMAC_MD5:
-                               /* no, thanks */
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
-       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &group, &plugin_name))
-       {
-               switch (group)
-               {
-                       case ECP_256_BIT:
-                       case ECP_384_BIT:
-                       case ECP_521_BIT:
-                       case ECP_256_BP:
-                       case ECP_384_BP:
-                       case ECP_512_BP:
-                       case CURVE_25519:
-                       case CURVE_448:
-                       case NTRU_128_BIT:
-                       case NTRU_192_BIT:
-                       case NTRU_256_BIT:
-                       case NH_128_BIT:
-                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 2 adds other algorithms with at least 128 bit security strength */
-       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &group, &plugin_name))
-       {
-               switch (group)
-               {
-                       case MODP_3072_BIT:
-                       case MODP_4096_BIT:
-                       case MODP_8192_BIT:
-                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* Round 3 adds algorithms with less than 128 bit security strength */
-       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
-       while (enumerator->enumerate(enumerator, &group, &plugin_name))
-       {
-               switch (group)
-               {
-                       case MODP_NULL:
-                               /* only for testing purposes */
-                               break;
-                       case MODP_768_BIT:
-                       case MODP_1024_BIT:
-                       case MODP_1536_BIT:
-                               /* weak */
-                               break;
-                       case MODP_1024_160:
-                       case MODP_2048_224:
-                       case MODP_2048_256:
-                               /* RFC 5114 primes are of questionable source */
-                               break;
-                       case ECP_224_BIT:
-                       case ECP_224_BP:
-                       case ECP_192_BIT:
-                       case NTRU_112_BIT:
-                               /* rarely used */
-                               break;
-                       case MODP_2048_BIT:
-                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
-                               break;
-                       default:
-                               break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       return TRUE;
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create_default(protocol_id_t protocol)
-{
-       private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
-
-       switch (protocol)
-       {
-               case PROTO_IKE:
-                       if (!proposal_add_supported_ike(this, FALSE))
-                       {
-                               destroy(this);
-                               return NULL;
-                       }
-                       break;
-               case PROTO_ESP:
-                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          128);
-                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          192);
-                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          256);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
-                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
-                       break;
-               case PROTO_AH:
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
-                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
-                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
-                       break;
-               default:
-                       break;
-       }
-       return &this->public;
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create_default_aead(protocol_id_t protocol)
-{
-       private_proposal_t *this;
-
-       switch (protocol)
-       {
-               case PROTO_IKE:
-                       this = (private_proposal_t*)proposal_create(protocol, 0);
-                       if (!proposal_add_supported_ike(this, TRUE))
-                       {
-                               destroy(this);
-                               return NULL;
-                       }
-                       return &this->public;
-               case PROTO_ESP:
-                       /* we currently don't include any AEAD proposal for ESP, as we
-                        * don't know if our kernel backend actually supports it. */
-                       return NULL;
-               case PROTO_AH:
-               default:
-                       return NULL;
-       }
-}
-
-/*
- * Described in header
- */
-proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
-{
-       private_proposal_t *this;
-       enumerator_t *enumerator;
-       bool failed = TRUE;
-       char *alg;
-
-       this = (private_proposal_t*)proposal_create(protocol, 0);
-
-       /* get all tokens, separated by '-' */
-       enumerator = enumerator_create_token(algs, "-", " ");
-       while (enumerator->enumerate(enumerator, &alg))
-       {
-               if (!add_string_algo(this, alg))
-               {
-                       failed = TRUE;
-                       break;
-               }
-               failed = FALSE;
-       }
-       enumerator->destroy(enumerator);
-
-       if (failed || !check_proposal(this))
-       {
-               destroy(this);
-               return NULL;
-       }
-
-       return &this->public;
-}
diff --git a/src/libcharon/config/proposal.h b/src/libcharon/config/proposal.h
deleted file mode 100644 (file)
index 0dc70f4..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2009-2016 Tobias Brunner
- * Copyright (C) 2006 Martin Willi
- * HSR Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup proposal proposal
- * @{ @ingroup config
- */
-
-#ifndef PROPOSAL_H_
-#define PROPOSAL_H_
-
-typedef enum protocol_id_t protocol_id_t;
-typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
-typedef struct proposal_t proposal_t;
-
-#include <library.h>
-#include <utils/identification.h>
-#include <collections/linked_list.h>
-#include <networking/host.h>
-#include <crypto/transform.h>
-#include <crypto/crypters/crypter.h>
-#include <crypto/signers/signer.h>
-#include <crypto/diffie_hellman.h>
-#include <selectors/traffic_selector.h>
-
-/**
- * Protocol ID of a proposal.
- */
-enum protocol_id_t {
-       PROTO_NONE = 0,
-       PROTO_IKE = 1,
-       PROTO_AH = 2,
-       PROTO_ESP = 3,
-       PROTO_IPCOMP = 4, /* IKEv1 only */
-};
-
-/**
- * enum names for protocol_id_t
- */
-extern enum_name_t *protocol_id_names;
-
-/**
- * Stores a set of algorithms used for an SA.
- *
- * A proposal stores algorithms for a specific
- * protocol. It can store algorithms for one protocol.
- * Proposals with multiple protocols are not supported,
- * as it's not specified in RFC4301 anymore.
- */
-struct proposal_t {
-
-       /**
-        * Add an algorithm to the proposal.
-        *
-        * The algorithms are stored by priority, first added
-        * is the most preferred.
-        * Key size is only needed for encryption algorithms
-        * with variable key size (such as AES). Must be set
-        * to zero if key size is not specified.
-        * The alg parameter accepts encryption_algorithm_t,
-        * integrity_algorithm_t, dh_group_number_t and
-        * extended_sequence_numbers_t.
-        *
-        * @param type                  kind of algorithm
-        * @param alg                   identifier for algorithm
-        * @param key_size              key size to use
-        */
-       void (*add_algorithm) (proposal_t *this, transform_type_t type,
-                                                  uint16_t alg, uint16_t key_size);
-
-       /**
-        * Get an enumerator over algorithms for a specific algo type.
-        *
-        * @param type                  kind of algorithm
-        * @return                              enumerator over uint16_t alg, uint16_t key_size
-        */
-       enumerator_t *(*create_enumerator) (proposal_t *this, transform_type_t type);
-
-       /**
-        * Get the algorithm for a type to use.
-        *
-        * If there are multiple algorithms, only the first is returned.
-        *
-        * @param type                  kind of algorithm
-        * @param alg                   pointer which receives algorithm
-        * @param key_size              pointer which receives the key size
-        * @return                              TRUE if algorithm of this kind available
-        */
-       bool (*get_algorithm) (proposal_t *this, transform_type_t type,
-                                                  uint16_t *alg, uint16_t *key_size);
-
-       /**
-        * Check if the proposal has a specific DH group.
-        *
-        * @param group                 group to check for
-        * @return                              TRUE if algorithm included
-        */
-       bool (*has_dh_group) (proposal_t *this, diffie_hellman_group_t group);
-
-       /**
-        * Strip DH groups from proposal to use it without PFS.
-        *
-        * @param keep                  group to keep (MODP_NONE to remove all)
-        */
-       void (*strip_dh)(proposal_t *this, diffie_hellman_group_t keep);
-
-       /**
-        * Compare two proposal, and select a matching subset.
-        *
-        * If the proposals are for the same protocols (AH/ESP), they are
-        * compared. If they have at least one algorithm of each type
-        * in common, a resulting proposal of this kind is created.
-        *
-        * @param other                 proposal to compare against
-        * @param other_remote  whether other is the remote proposal from which to
-        *                                              copy SPI and proposal number to the result,
-        *                                              otherwise copy from this proposal
-        * @param private               accepts algorithms allocated in a private range
-        * @return                              selected proposal, NULL if proposals don't match
-        */
-       proposal_t *(*select)(proposal_t *this, proposal_t *other,
-                                                 bool other_remote, bool private);
-
-       /**
-        * Get the protocol ID of the proposal.
-        *
-        * @return                              protocol of the proposal
-        */
-       protocol_id_t (*get_protocol) (proposal_t *this);
-
-       /**
-        * Get the SPI of the proposal.
-        *
-        * @return                              spi for proto
-        */
-       uint64_t (*get_spi) (proposal_t *this);
-
-       /**
-        * Set the SPI of the proposal.
-        *
-        * @param spi                   spi to set for proto
-        */
-       void (*set_spi) (proposal_t *this, uint64_t spi);
-
-       /**
-        * Get the proposal number, as encoded in SA payload
-        *
-        * @return                              proposal number
-        */
-       u_int (*get_number)(proposal_t *this);
-
-       /**
-        * Check for the eqality of two proposals.
-        *
-        * @param other                 other proposal to check for equality
-        * @return                              TRUE if other equal to this
-        */
-       bool (*equals)(proposal_t *this, proposal_t *other);
-
-       /**
-        * Clone a proposal.
-        *
-        * @return                              clone of proposal
-        */
-       proposal_t *(*clone) (proposal_t *this);
-
-       /**
-        * Destroys the proposal object.
-        */
-       void (*destroy) (proposal_t *this);
-};
-
-/**
- * Create a child proposal for AH, ESP or IKE.
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @param number                       proposal number, as encoded in SA payload
- * @return                                     proposal_t object
- */
-proposal_t *proposal_create(protocol_id_t protocol, u_int number);
-
-/**
- * Create a default proposal if nothing further specified.
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @return                                     proposal_t object
- */
-proposal_t *proposal_create_default(protocol_id_t protocol);
-
-/**
- * Create a default proposal for supported AEAD algorithms
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @return                                     proposal_t object, NULL if none supported
- */
-proposal_t *proposal_create_default_aead(protocol_id_t protocol);
-
-/**
- * Create a proposal from a string identifying the algorithms.
- *
- * The string is in the same form as a in the ipsec.conf file.
- * E.g.:       aes128-sha2_256-modp2048
- *               3des-md5
- * An additional '!' at the end of the string forces this proposal,
- * without it the peer may choose another algorithm we support.
- *
- * @param protocol                     protocol, such as PROTO_ESP
- * @param algs                         algorithms as string
- * @return                                     proposal_t object
- */
-proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs);
-
-/**
- * printf hook function for proposal_t.
- *
- * Arguments are:
- *     proposal_t *proposal
- * With the #-specifier, arguments are:
- *     linked_list_t *list containing proposal_t*
- */
-int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
-                                                const void *const *args);
-
-#endif /** PROPOSAL_H_ @}*/
index 7c9f83d..e4b8197 100644 (file)
@@ -55,7 +55,6 @@
 #include <bus/listeners/sys_logger.h>
 #include <bus/listeners/file_logger.h>
 #include <collections/array.h>
-#include <config/proposal.h>
 #include <plugins/plugin_feature.h>
 #include <kernel/kernel_handler.h>
 #include <processing/jobs/start_action_job.h>
@@ -989,11 +988,6 @@ bool libcharon_init()
        dbg_old = dbg;
        dbg = dbg_bus;
 
-       lib->printf_hook->add_handler(lib->printf_hook, 'P',
-                                                                 proposal_printf_hook,
-                                                                 PRINTF_HOOK_ARGTYPE_POINTER,
-                                                                 PRINTF_HOOK_ARGTYPE_END);
-
        if (lib->integrity &&
                !lib->integrity->check(lib->integrity, "libcharon", libcharon_init))
        {
index 796c108..cad597e 100644 (file)
@@ -29,7 +29,7 @@ typedef struct proposal_substructure_t proposal_substructure_t;
 #include <library.h>
 #include <encoding/payloads/payload.h>
 #include <encoding/payloads/transform_substructure.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <collections/linked_list.h>
 #include <kernel/kernel_ipsec.h>
 #include <sa/authenticator.h>
index cb75f1e..a9d4f9f 100644 (file)
@@ -32,7 +32,7 @@ typedef struct transform_substructure_t transform_substructure_t;
 #include <crypto/signers/signer.h>
 #include <crypto/prfs/prf.h>
 #include <crypto/crypters/crypter.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 /**
  * IKEv1 Value for a transform payload.
index b2d5a11..b33ea61 100644 (file)
@@ -27,7 +27,7 @@ typedef struct delete_child_sa_job_t delete_child_sa_job_t;
 #include <library.h>
 #include <sa/ike_sa_id.h>
 #include <processing/jobs/job.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 
 /**
index 1de06fd..1c9d9b4 100644 (file)
@@ -26,7 +26,7 @@ typedef struct rekey_child_sa_job_t rekey_child_sa_job_t;
 #include <library.h>
 #include <sa/ike_sa_id.h>
 #include <processing/jobs/job.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 /**
  * Class representing an REKEY_CHILD_SA Job.
@@ -50,4 +50,5 @@ struct rekey_child_sa_job_t {
  */
 rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol,
                                                                                                uint32_t spi, host_t *dst);
+
 #endif /** REKEY_CHILD_SA_JOB_H_ @}*/
index ed978dc..17beb68 100644 (file)
@@ -26,7 +26,7 @@ typedef struct update_sa_job_t update_sa_job_t;
 #include <library.h>
 #include <networking/host.h>
 #include <processing/jobs/job.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 
 /**
  * Update the addresses of an IKE and its CHILD_SAs.
index 082404d..85c1a42 100644 (file)
@@ -30,7 +30,7 @@ typedef struct child_sa_t child_sa_t;
 #include <library.h>
 #include <crypto/prf_plus.h>
 #include <encoding/payloads/proposal_substructure.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <config/child_cfg.h>
 
 /**
index bc40b3d..17d2efe 100644 (file)
@@ -27,7 +27,7 @@ typedef struct keymat_t keymat_t;
 #include <utils/identification.h>
 #include <crypto/prfs/prf.h>
 #include <crypto/aead.h>
-#include <config/proposal.h>
+#include <crypto/proposal/proposal.h>
 #include <config/peer_cfg.h>
 #include <sa/ike_sa_id.h>
 
index 8f762a2..5ebd045 100644 (file)
@@ -3,7 +3,6 @@ TESTS = libcharon_tests exchange_tests
 check_PROGRAMS = $(TESTS)
 
 libcharon_tests_SOURCES = \
-  suites/test_proposal.c \
   suites/test_ike_cfg.c \
   suites/test_mem_pool.c \
   suites/test_message_chapoly.c \
index f770f46..d17ea04 100644 (file)
@@ -24,7 +24,6 @@
  * @ingroup libcharon-tests
  */
 
-TEST_SUITE(proposal_suite_create)
 TEST_SUITE(ike_cfg_suite_create)
 TEST_SUITE(mem_pool_suite_create)
 TEST_SUITE_DEPEND(message_chapoly_suite_create, AEAD, ENCR_CHACHA20_POLY1305, 32)
diff --git a/src/libcharon/tests/suites/test_proposal.c b/src/libcharon/tests/suites/test_proposal.c
deleted file mode 100644 (file)
index f159179..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2016 Tobias Brunner
- * HSR Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include "test_suite.h"
-
-#include <config/proposal.h>
-
-static struct {
-       protocol_id_t proto;
-       char *proposal;
-       char *expected;
-} create_data[] = {
-       { PROTO_IKE, "", NULL },
-       { PROTO_IKE, "sha256", NULL },
-       { PROTO_IKE, "sha256-modp3072", NULL },
-       { PROTO_IKE, "null-sha256-modp3072", "IKE:NULL/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128", NULL },
-       { PROTO_IKE, "aes128-sha256", NULL },
-       { PROTO_IKE, "aes128-sha256-modpnone", NULL },
-       { PROTO_IKE, "aes128-sha256-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128-sha256-prfsha384-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_384/MODP_3072" },
-       { PROTO_IKE, "aes128gcm16-modp3072", NULL },
-       { PROTO_IKE, "aes128gcm16-prfsha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128gcm16-sha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
-       { PROTO_IKE, "aes128gcm16-aes128-modp3072", NULL },
-       { PROTO_IKE, "aes128gcm16-aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "", NULL },
-       { PROTO_ESP, "sha256", NULL },
-       { PROTO_ESP, "aes128-sha256", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-esn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-esn-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128-sha256-prfsha256-modp3072", "ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_3072/NO_EXT_SEQ" },
-       { PROTO_ESP, "aes128gcm16-aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "aes128gmac", "ESP:NULL_AES_GMAC_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "", NULL },
-       { PROTO_AH,  "aes128", NULL },
-       { PROTO_AH,  "aes128-sha256", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "sha256-sha1", "AH:HMAC_SHA2_256_128/HMAC_SHA1_96/NO_EXT_SEQ" },
-       { PROTO_AH,  "aes128gmac-sha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "aes128gmac-sha256-prfsha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "aes128gmac-aes256gmac-aes128-sha256", "AH:AES_128_GMAC/AES_256_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "sha256-esn", "AH:HMAC_SHA2_256_128/EXT_SEQ" },
-       { PROTO_AH,  "sha256-noesn", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
-       { PROTO_AH,  "sha256-esn-noesn", "AH:HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
-};
-
-START_TEST(test_create_from_string)
-{
-       proposal_t *proposal;
-       char str[BUF_LEN];
-
-       proposal = proposal_create_from_string(create_data[_i].proto,
-                                                                                  create_data[_i].proposal);
-       if (!create_data[_i].expected)
-       {
-               ck_assert(!proposal);
-               return;
-       }
-       snprintf(str, sizeof(str), "%P", proposal);
-       ck_assert_str_eq(create_data[_i].expected, str);
-       proposal->destroy(proposal);
-}
-END_TEST
-
-static struct {
-       protocol_id_t proto;
-       char *self;
-       char *other;
-       char *expected;
-} select_data[] = {
-       { PROTO_ESP, "aes128", "aes128", "aes128" },
-       { PROTO_ESP, "aes128", "aes256", NULL },
-       { PROTO_ESP, "aes128-aes256", "aes256-aes128", "aes128" },
-       { PROTO_ESP, "aes256-aes128", "aes128-aes256", "aes256" },
-       { PROTO_ESP, "aes128-aes256-sha1-sha256", "aes256-aes128-sha256-sha1", "aes128-sha1" },
-       { PROTO_ESP, "aes256-aes128-sha256-sha1", "aes128-aes256-sha1-sha256", "aes256-sha256" },
-       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256", NULL },
-       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256-modpnone", NULL },
-       { PROTO_ESP, "aes128-sha256-modpnone", "aes128-sha256-modp3072", NULL },
-       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256", "aes128-sha256" },
-       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
-       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072" },
-       { PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone" },
-       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
-       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072" },
-       { PROTO_IKE, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
-};
-
-START_TEST(test_select)
-{
-       proposal_t *self, *other, *selected, *expected;
-
-       self = proposal_create_from_string(select_data[_i].proto,
-                                                                          select_data[_i].self);
-       other = proposal_create_from_string(select_data[_i].proto,
-                                                                               select_data[_i].other);
-       selected = self->select(self, other, TRUE, FALSE);
-       if (select_data[_i].expected)
-       {
-               expected = proposal_create_from_string(select_data[_i].proto,
-                                                                                          select_data[_i].expected);
-               ck_assert(selected);
-               ck_assert_msg(expected->equals(expected, selected), "proposal %P does "
-                                         "not match expected %P", selected, expected);
-               expected->destroy(expected);
-       }
-       else
-       {
-               ck_assert(!selected);
-       }
-       DESTROY_IF(selected);
-       other->destroy(other);
-       self->destroy(self);
-}
-END_TEST
-
-START_TEST(test_select_spi)
-{
-       proposal_t *self, *other, *selected;
-
-       self = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
-       other = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
-       other->set_spi(other, 0x12345678);
-
-       selected = self->select(self, other, TRUE, FALSE);
-       ck_assert(selected);
-       ck_assert_int_eq(selected->get_spi(selected), other->get_spi(other));
-       selected->destroy(selected);
-
-       selected = self->select(self, other, FALSE, FALSE);
-       ck_assert(selected);
-       ck_assert_int_eq(selected->get_spi(selected), self->get_spi(self));
-       selected->destroy(selected);
-
-       other->destroy(other);
-       self->destroy(self);
-}
-END_TEST
-
-Suite *proposal_suite_create()
-{
-       Suite *s;
-       TCase *tc;
-
-       s = suite_create("proposal");
-
-       tc = tcase_create("create_from_string");
-       tcase_add_loop_test(tc, test_create_from_string, 0, countof(create_data));
-       suite_add_tcase(s, tc);
-
-       tc = tcase_create("select");
-       tcase_add_loop_test(tc, test_select, 0, countof(select_data));
-       tcase_add_test(tc, test_select_spi);
-       suite_add_tcase(s, tc);
-
-       return s;
-}
index 0247add..fb7c62a 100644 (file)
@@ -8,7 +8,7 @@ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
 collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
 collections/array.c \
 collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
-crypto/hashers/hash_algorithm_set.c \
+crypto/hashers/hash_algorithm_set.c crypto/proposal/proposal.c \
 crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
 crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
 crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \
index a9759ae..66539a8 100644 (file)
@@ -6,7 +6,7 @@ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
 collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
 collections/array.c \
 collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
-crypto/hashers/hash_algorithm_set.c \
+crypto/hashers/hash_algorithm_set.c crypto/proposal/proposal.c \
 crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
 crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
 crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \
@@ -69,7 +69,7 @@ asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \
 collections/blocking_queue.h collections/enumerator.h collections/hashtable.h \
 collections/linked_list.h collections/array.h collections/dictionary.h \
 crypto/crypters/crypter.h crypto/hashers/hasher.h \
-crypto/hashers/hash_algorithm_set.h crypto/mac.h \
+crypto/hashers/hash_algorithm_set.h crypto/mac.h crypto/proposal/proposal.h \
 crypto/proposal/proposal_keywords.h crypto/proposal/proposal_keywords_static.h \
 crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \
 crypto/prf_plus.h crypto/signers/signer.h crypto/signers/mac_signer.h \
diff --git a/src/libstrongswan/crypto/proposal/proposal.c b/src/libstrongswan/crypto/proposal/proposal.c
new file mode 100644 (file)
index 0000000..221375f
--- /dev/null
@@ -0,0 +1,1102 @@
+/*
+ * Copyright (C) 2008-2016 Tobias Brunner
+ * Copyright (C) 2006-2010 Martin Willi
+ * Copyright (C) 2013-2015 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <string.h>
+
+#include "proposal.h"
+
+#include <collections/array.h>
+#include <utils/identification.h>
+
+#include <crypto/transform.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+
+ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
+       "PROTO_NONE",
+       "IKE",
+       "AH",
+       "ESP",
+       "IPCOMP",
+);
+
+typedef struct private_proposal_t private_proposal_t;
+
+/**
+ * Private data of an proposal_t object
+ */
+struct private_proposal_t {
+
+       /**
+        * Public part
+        */
+       proposal_t public;
+
+       /**
+        * protocol (ESP or AH)
+        */
+       protocol_id_t protocol;
+
+       /**
+        * Priority ordered list of transforms, as entry_t
+        */
+       array_t *transforms;
+
+       /**
+        * senders SPI
+        */
+       uint64_t spi;
+
+       /**
+        * Proposal number
+        */
+       u_int number;
+};
+
+/**
+ * Struct used to store different kinds of algorithms.
+ */
+typedef struct {
+       /** Type of the transform */
+       transform_type_t type;
+       /** algorithm identifier */
+       uint16_t alg;
+       /** key size in bits, or zero if not needed */
+       uint16_t key_size;
+} entry_t;
+
+METHOD(proposal_t, add_algorithm, void,
+       private_proposal_t *this, transform_type_t type,
+       uint16_t alg, uint16_t key_size)
+{
+       entry_t entry = {
+               .type = type,
+               .alg = alg,
+               .key_size = key_size,
+       };
+
+       array_insert(this->transforms, ARRAY_TAIL, &entry);
+}
+
+CALLBACK(alg_filter, bool,
+       uintptr_t type, enumerator_t *orig, va_list args)
+{
+       entry_t *entry;
+       uint16_t *alg, *key_size;
+
+       VA_ARGS_VGET(args, alg, key_size);
+
+       while (orig->enumerate(orig, &entry))
+       {
+               if (entry->type != type)
+               {
+                       continue;
+               }
+               if (alg)
+               {
+                       *alg = entry->alg;
+               }
+               if (key_size)
+               {
+                       *key_size = entry->key_size;
+               }
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(proposal_t, create_enumerator, enumerator_t*,
+       private_proposal_t *this, transform_type_t type)
+{
+       return enumerator_create_filter(
+                                               array_create_enumerator(this->transforms),
+                                               alg_filter, (void*)(uintptr_t)type, NULL);
+}
+
+METHOD(proposal_t, get_algorithm, bool,
+       private_proposal_t *this, transform_type_t type,
+       uint16_t *alg, uint16_t *key_size)
+{
+       enumerator_t *enumerator;
+       bool found = FALSE;
+
+       enumerator = create_enumerator(this, type);
+       if (enumerator->enumerate(enumerator, alg, key_size))
+       {
+               found = TRUE;
+       }
+       enumerator->destroy(enumerator);
+
+       return found;
+}
+
+METHOD(proposal_t, has_dh_group, bool,
+       private_proposal_t *this, diffie_hellman_group_t group)
+{
+       bool found = FALSE, any = FALSE;
+       enumerator_t *enumerator;
+       uint16_t current;
+
+       enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
+       while (enumerator->enumerate(enumerator, &current, NULL))
+       {
+               any = TRUE;
+               if (current == group)
+               {
+                       found = TRUE;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (!any && group == MODP_NONE)
+       {
+               found = TRUE;
+       }
+       return found;
+}
+
+METHOD(proposal_t, strip_dh, void,
+       private_proposal_t *this, diffie_hellman_group_t keep)
+{
+       enumerator_t *enumerator;
+       entry_t *entry;
+
+       enumerator = array_create_enumerator(this->transforms);
+       while (enumerator->enumerate(enumerator, &entry))
+       {
+               if (entry->type == DIFFIE_HELLMAN_GROUP &&
+                       entry->alg != keep)
+               {
+                       array_remove_at(this->transforms, enumerator);
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * Select a matching proposal from this and other, insert into selected.
+ */
+static bool select_algo(private_proposal_t *this, proposal_t *other,
+                                               proposal_t *selected, transform_type_t type, bool priv)
+{
+       enumerator_t *e1, *e2;
+       uint16_t alg1, alg2, ks1, ks2;
+       bool found = FALSE, optional = FALSE;
+
+       if (type == INTEGRITY_ALGORITHM &&
+               selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
+               encryption_algorithm_is_aead(alg1))
+       {
+               /* no integrity algorithm required, we have an AEAD */
+               return TRUE;
+       }
+       if (type == DIFFIE_HELLMAN_GROUP)
+       {
+               optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
+       }
+
+       e1 = create_enumerator(this, type);
+       e2 = other->create_enumerator(other, type);
+       if (!e1->enumerate(e1, &alg1, NULL))
+       {
+               if (!e2->enumerate(e2, &alg2, NULL))
+               {
+                       found = TRUE;
+               }
+               else if (optional)
+               {
+                       do
+                       {       /* if NONE is proposed, we accept the proposal */
+                               found = !alg2;
+                       }
+                       while (!found && e2->enumerate(e2, &alg2, NULL));
+               }
+       }
+       else if (!e2->enumerate(e2, NULL, NULL))
+       {
+               if (optional)
+               {
+                       do
+                       {       /* if NONE is proposed, we accept the proposal */
+                               found = !alg1;
+                       }
+                       while (!found && e1->enumerate(e1, &alg1, NULL));
+               }
+       }
+
+       e1->destroy(e1);
+       e1 = create_enumerator(this, type);
+       /* compare algs, order of algs in "first" is preferred */
+       while (!found && e1->enumerate(e1, &alg1, &ks1))
+       {
+               e2->destroy(e2);
+               e2 = other->create_enumerator(other, type);
+               while (e2->enumerate(e2, &alg2, &ks2))
+               {
+                       if (alg1 == alg2 && ks1 == ks2)
+                       {
+                               if (!priv && alg1 >= 1024)
+                               {
+                                       /* accept private use algorithms only if requested */
+                                       DBG1(DBG_CFG, "an algorithm from private space would match, "
+                                                "but peer implementation is unknown, skipped");
+                                       continue;
+                               }
+                               selected->add_algorithm(selected, type, alg1, ks1);
+                               found = TRUE;
+                               break;
+                       }
+               }
+       }
+       /* no match in all comparisons */
+       e1->destroy(e1);
+       e2->destroy(e2);
+
+       if (!found)
+       {
+               DBG2(DBG_CFG, "  no acceptable %N found", transform_type_names, type);
+       }
+       return found;
+}
+
+METHOD(proposal_t, select_proposal, proposal_t*,
+       private_proposal_t *this, proposal_t *other, bool other_remote,
+       bool private)
+{
+       proposal_t *selected;
+
+       DBG2(DBG_CFG, "selecting proposal:");
+
+       if (this->protocol != other->get_protocol(other))
+       {
+               DBG2(DBG_CFG, "  protocol mismatch, skipping");
+               return NULL;
+       }
+
+       if (other_remote)
+       {
+               selected = proposal_create(this->protocol, other->get_number(other));
+               selected->set_spi(selected, other->get_spi(other));
+       }
+       else
+       {
+               selected = proposal_create(this->protocol, this->number);
+               selected->set_spi(selected, this->spi);
+
+       }
+
+       if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
+               !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
+               !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
+               !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
+               !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
+       {
+               selected->destroy(selected);
+               return NULL;
+       }
+
+       DBG2(DBG_CFG, "  proposal matches");
+       return selected;
+}
+
+METHOD(proposal_t, get_protocol, protocol_id_t,
+       private_proposal_t *this)
+{
+       return this->protocol;
+}
+
+METHOD(proposal_t, set_spi, void,
+       private_proposal_t *this, uint64_t spi)
+{
+       this->spi = spi;
+}
+
+METHOD(proposal_t, get_spi, uint64_t,
+       private_proposal_t *this)
+{
+       return this->spi;
+}
+
+/**
+ * Check if two proposals have the same algorithms for a given transform type
+ */
+static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
+                                                        transform_type_t type)
+{
+       enumerator_t *e1, *e2;
+       uint16_t alg1, alg2, ks1, ks2;
+       bool equals = TRUE;
+
+       e1 = create_enumerator(this, type);
+       e2 = other->create_enumerator(other, type);
+       while (e1->enumerate(e1, &alg1, &ks1))
+       {
+               if (!e2->enumerate(e2, &alg2, &ks2))
+               {
+                       /* this has more algs */
+                       equals = FALSE;
+                       break;
+               }
+               if (alg1 != alg2 || ks1 != ks2)
+               {
+                       equals = FALSE;
+                       break;
+               }
+       }
+       if (e2->enumerate(e2, &alg2, &ks2))
+       {
+               /* other has more algs */
+               equals = FALSE;
+       }
+       e1->destroy(e1);
+       e2->destroy(e2);
+
+       return equals;
+}
+
+METHOD(proposal_t, get_number, u_int,
+       private_proposal_t *this)
+{
+       return this->number;
+}
+
+METHOD(proposal_t, equals, bool,
+       private_proposal_t *this, proposal_t *other)
+{
+       if (&this->public == other)
+       {
+               return TRUE;
+       }
+       return (
+               algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
+               algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
+               algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
+               algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
+               algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
+}
+
+METHOD(proposal_t, clone_, proposal_t*,
+       private_proposal_t *this)
+{
+       private_proposal_t *clone;
+       enumerator_t *enumerator;
+       entry_t *entry;
+
+       clone = (private_proposal_t*)proposal_create(this->protocol, 0);
+
+       enumerator = array_create_enumerator(this->transforms);
+       while (enumerator->enumerate(enumerator, &entry))
+       {
+               array_insert(clone->transforms, ARRAY_TAIL, entry);
+       }
+       enumerator->destroy(enumerator);
+
+       clone->spi = this->spi;
+       clone->number = this->number;
+
+       return &clone->public;
+}
+
+/**
+ * Map integrity algorithms to the PRF functions using the same algorithm.
+ */
+static const struct {
+       integrity_algorithm_t integ;
+       pseudo_random_function_t prf;
+} integ_prf_map[] = {
+       {AUTH_HMAC_SHA1_96,                                     PRF_HMAC_SHA1                                   },
+       {AUTH_HMAC_SHA1_160,                            PRF_HMAC_SHA1                                   },
+       {AUTH_HMAC_SHA2_256_128,                        PRF_HMAC_SHA2_256                               },
+       {AUTH_HMAC_SHA2_384_192,                        PRF_HMAC_SHA2_384                               },
+       {AUTH_HMAC_SHA2_512_256,                        PRF_HMAC_SHA2_512                               },
+       {AUTH_HMAC_MD5_96,                                      PRF_HMAC_MD5                                    },
+       {AUTH_HMAC_MD5_128,                                     PRF_HMAC_MD5                                    },
+       {AUTH_AES_XCBC_96,                                      PRF_AES128_XCBC                                 },
+       {AUTH_CAMELLIA_XCBC_96,                         PRF_CAMELLIA128_XCBC                    },
+       {AUTH_AES_CMAC_96,                                      PRF_AES128_CMAC                                 },
+};
+
+/**
+ * Remove all entries of the given transform type
+ */
+static void remove_transform(private_proposal_t *this, transform_type_t type)
+{
+       enumerator_t *e;
+       entry_t *entry;
+
+       e = array_create_enumerator(this->transforms);
+       while (e->enumerate(e, &entry))
+       {
+               if (entry->type == type)
+               {
+                       array_remove_at(this->transforms, e);
+               }
+       }
+       e->destroy(e);
+}
+
+/**
+ * Checks the proposal read from a string.
+ */
+static bool check_proposal(private_proposal_t *this)
+{
+       enumerator_t *e;
+       entry_t *entry;
+       uint16_t alg, ks;
+       bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
+       int i;
+
+       if (this->protocol == PROTO_IKE)
+       {
+               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
+               {       /* No explicit PRF found. We assume the same algorithm as used
+                        * for integrity checking. */
+                       e = create_enumerator(this, INTEGRITY_ALGORITHM);
+                       while (e->enumerate(e, &alg, &ks))
+                       {
+                               for (i = 0; i < countof(integ_prf_map); i++)
+                               {
+                                       if (alg == integ_prf_map[i].integ)
+                                       {
+                                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
+                                                                         integ_prf_map[i].prf, 0);
+                                               break;
+                                       }
+                               }
+                       }
+                       e->destroy(e);
+               }
+               if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
+               {
+                       DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
+                       return FALSE;
+               }
+               /* remove MODP_NONE from IKE proposal */
+               e = array_create_enumerator(this->transforms);
+               while (e->enumerate(e, &entry))
+               {
+                       if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
+                       {
+                               array_remove_at(this->transforms, e);
+                       }
+               }
+               e->destroy(e);
+               if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
+               {
+                       DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
+                       return FALSE;
+               }
+       }
+       else
+       {       /* remove PRFs from ESP/AH proposals */
+               remove_transform(this, PSEUDO_RANDOM_FUNCTION);
+       }
+
+       if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
+       {
+               e = create_enumerator(this, ENCRYPTION_ALGORITHM);
+               while (e->enumerate(e, &alg, &ks))
+               {
+                       any_enc = TRUE;
+                       if (encryption_algorithm_is_aead(alg))
+                       {
+                               any_aead = TRUE;
+                               continue;
+                       }
+                       all_aead = FALSE;
+               }
+               e->destroy(e);
+
+               if (!any_enc)
+               {
+                       DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
+                                protocol_id_names, this->protocol);
+                       return FALSE;
+               }
+               else if (any_aead && !all_aead)
+               {
+                       DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
+                                "algorithms can't be contained in the same %N proposal",
+                                protocol_id_names, this->protocol);
+                       return FALSE;
+               }
+               else if (all_aead)
+               {       /* if all encryption algorithms in the proposal are AEADs,
+                        * we MUST NOT propose any integrity algorithms */
+                       remove_transform(this, INTEGRITY_ALGORITHM);
+               }
+       }
+       else
+       {       /* AES-GMAC is parsed as encryption algorithm, so we map that to the
+                * proper integrity algorithm */
+               e = array_create_enumerator(this->transforms);
+               while (e->enumerate(e, &entry))
+               {
+                       if (entry->type == ENCRYPTION_ALGORITHM)
+                       {
+                               if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
+                               {
+                                       entry->type = INTEGRITY_ALGORITHM;
+                                       ks = entry->key_size;
+                                       entry->key_size = 0;
+                                       switch (ks)
+                                       {
+                                               case 128:
+                                                       entry->alg = AUTH_AES_128_GMAC;
+                                                       continue;
+                                               case 192:
+                                                       entry->alg = AUTH_AES_192_GMAC;
+                                                       continue;
+                                               case 256:
+                                                       entry->alg = AUTH_AES_256_GMAC;
+                                                       continue;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                               /* remove all other encryption algorithms */
+                               array_remove_at(this->transforms, e);
+                       }
+               }
+               e->destroy(e);
+
+               if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
+               {
+                       DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
+                                "proposals");
+                       return FALSE;
+               }
+       }
+
+       if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
+       {
+               if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
+               {       /* ESN not specified, assume not supported */
+                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+               }
+       }
+
+       array_compress(this->transforms);
+       return TRUE;
+}
+
+/**
+ * add a algorithm identified by a string to the proposal.
+ */
+static bool add_string_algo(private_proposal_t *this, const char *alg)
+{
+       const proposal_token_t *token;
+
+       token = lib->proposal->get_token(lib->proposal, alg);
+       if (token == NULL)
+       {
+               DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
+               return FALSE;
+       }
+
+       add_algorithm(this, token->type, token->algorithm, token->keysize);
+
+       return TRUE;
+}
+
+/**
+ * print all algorithms of a kind to buffer
+ */
+static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
+                                        u_int kind, void *names, bool *first)
+{
+       enumerator_t *enumerator;
+       size_t written = 0;
+       uint16_t alg, size;
+
+       enumerator = create_enumerator(this, kind);
+       while (enumerator->enumerate(enumerator, &alg, &size))
+       {
+               if (*first)
+               {
+                       written += print_in_hook(data, "%N", names, alg);
+                       *first = FALSE;
+               }
+               else
+               {
+                       written += print_in_hook(data, "/%N", names, alg);
+               }
+               if (size)
+               {
+                       written += print_in_hook(data, "_%u", size);
+               }
+       }
+       enumerator->destroy(enumerator);
+       return written;
+}
+
+/**
+ * Described in header.
+ */
+int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+                                                const void *const *args)
+{
+       private_proposal_t *this = *((private_proposal_t**)(args[0]));
+       linked_list_t *list = *((linked_list_t**)(args[0]));
+       enumerator_t *enumerator;
+       size_t written = 0;
+       bool first = TRUE;
+
+       if (this == NULL)
+       {
+               return print_in_hook(data, "(null)");
+       }
+
+       if (spec->hash)
+       {
+               enumerator = list->create_enumerator(list);
+               while (enumerator->enumerate(enumerator, &this))
+               {       /* call recursivly */
+                       if (first)
+                       {
+                               written += print_in_hook(data, "%P", this);
+                               first = FALSE;
+                       }
+                       else
+                       {
+                               written += print_in_hook(data, ", %P", this);
+                       }
+               }
+               enumerator->destroy(enumerator);
+               return written;
+       }
+
+       written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
+       written += print_alg(this, data, ENCRYPTION_ALGORITHM,
+                                                encryption_algorithm_names, &first);
+       written += print_alg(this, data, INTEGRITY_ALGORITHM,
+                                                integrity_algorithm_names, &first);
+       written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION,
+                                                pseudo_random_function_names, &first);
+       written += print_alg(this, data, DIFFIE_HELLMAN_GROUP,
+                                                diffie_hellman_group_names, &first);
+       written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS,
+                                                extended_sequence_numbers_names, &first);
+       return written;
+}
+
+METHOD(proposal_t, destroy, void,
+       private_proposal_t *this)
+{
+       array_destroy(this->transforms);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create(protocol_id_t protocol, u_int number)
+{
+       private_proposal_t *this;
+
+       INIT(this,
+               .public = {
+                       .add_algorithm = _add_algorithm,
+                       .create_enumerator = _create_enumerator,
+                       .get_algorithm = _get_algorithm,
+                       .has_dh_group = _has_dh_group,
+                       .strip_dh = _strip_dh,
+                       .select = _select_proposal,
+                       .get_protocol = _get_protocol,
+                       .set_spi = _set_spi,
+                       .get_spi = _get_spi,
+                       .get_number = _get_number,
+                       .equals = _equals,
+                       .clone = _clone_,
+                       .destroy = _destroy,
+               },
+               .protocol = protocol,
+               .number = number,
+               .transforms = array_create(sizeof(entry_t), 0),
+       );
+
+       return &this->public;
+}
+
+/**
+ * Add supported IKE algorithms to proposal
+ */
+static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
+{
+       enumerator_t *enumerator;
+       encryption_algorithm_t encryption;
+       integrity_algorithm_t integrity;
+       pseudo_random_function_t prf;
+       diffie_hellman_group_t group;
+       const char *plugin_name;
+
+       if (aead)
+       {
+               /* Round 1 adds algorithms with at least 128 bit security strength */
+               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_AES_GCM_ICV16:
+                               case ENCR_AES_CCM_ICV16:
+                               case ENCR_CAMELLIA_CCM_ICV16:
+                                       /* we assume that we support all AES/Camellia sizes */
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               case ENCR_CHACHA20_POLY1305:
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               /* Round 2 adds algorithms with less than 128 bit security strength */
+               enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_AES_GCM_ICV12:
+                               case ENCR_AES_GCM_ICV8:
+                               case ENCR_AES_CCM_ICV12:
+                               case ENCR_AES_CCM_ICV8:
+                               case ENCR_CAMELLIA_CCM_ICV12:
+                               case ENCR_CAMELLIA_CCM_ICV8:
+                                       /* we assume that we support all AES/Camellia sizes */
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (!array_count(this->transforms))
+               {
+                       return FALSE;
+               }
+       }
+       else
+       {
+               /* Round 1 adds algorithms with at least 128 bit security strength */
+               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_AES_CBC:
+                               case ENCR_AES_CTR:
+                               case ENCR_CAMELLIA_CBC:
+                               case ENCR_CAMELLIA_CTR:
+                                       /* we assume that we support all AES/Camellia sizes */
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               /* Round 2 adds algorithms with less than 128 bit security strength */
+               enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+               {
+                       switch (encryption)
+                       {
+                               case ENCR_3DES:
+                                       add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
+                                       break;
+                               case ENCR_DES:
+                                       /* no, thanks */
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (!array_count(this->transforms))
+               {
+                       return FALSE;
+               }
+
+               /* Round 1 adds algorithms with at least 128 bit security strength */
+               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
+               {
+                       switch (integrity)
+                       {
+                               case AUTH_HMAC_SHA2_256_128:
+                               case AUTH_HMAC_SHA2_384_192:
+                               case AUTH_HMAC_SHA2_512_256:
+                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               /* Round 2 adds algorithms with less than 128 bit security strength */
+               enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
+               while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
+               {
+                       switch (integrity)
+                       {
+                               case AUTH_AES_XCBC_96:
+                               case AUTH_AES_CMAC_96:
+                               case AUTH_HMAC_SHA1_96:
+                                       add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
+                                       break;
+                               case AUTH_HMAC_MD5_96:
+                                       /* no, thanks */
+                               default:
+                                       break;
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+
+       /* Round 1 adds algorithms with at least 128 bit security strength */
+       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
+       {
+               switch (prf)
+               {
+                       case PRF_HMAC_SHA2_256:
+                       case PRF_HMAC_SHA2_384:
+                       case PRF_HMAC_SHA2_512:
+                       case PRF_AES128_XCBC:
+                       case PRF_AES128_CMAC:
+                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 2 adds algorithms with less than 128 bit security strength */
+       enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &prf, &plugin_name))
+       {
+               switch (prf)
+               {
+                       case PRF_HMAC_SHA1:
+                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
+                               break;
+                       case PRF_HMAC_MD5:
+                               /* no, thanks */
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
+       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &group, &plugin_name))
+       {
+               switch (group)
+               {
+                       case ECP_256_BIT:
+                       case ECP_384_BIT:
+                       case ECP_521_BIT:
+                       case ECP_256_BP:
+                       case ECP_384_BP:
+                       case ECP_512_BP:
+                       case CURVE_25519:
+                       case CURVE_448:
+                       case NTRU_128_BIT:
+                       case NTRU_192_BIT:
+                       case NTRU_256_BIT:
+                       case NH_128_BIT:
+                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 2 adds other algorithms with at least 128 bit security strength */
+       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &group, &plugin_name))
+       {
+               switch (group)
+               {
+                       case MODP_3072_BIT:
+                       case MODP_4096_BIT:
+                       case MODP_8192_BIT:
+                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       /* Round 3 adds algorithms with less than 128 bit security strength */
+       enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+       while (enumerator->enumerate(enumerator, &group, &plugin_name))
+       {
+               switch (group)
+               {
+                       case MODP_NULL:
+                               /* only for testing purposes */
+                               break;
+                       case MODP_768_BIT:
+                       case MODP_1024_BIT:
+                       case MODP_1536_BIT:
+                               /* weak */
+                               break;
+                       case MODP_1024_160:
+                       case MODP_2048_224:
+                       case MODP_2048_256:
+                               /* RFC 5114 primes are of questionable source */
+                               break;
+                       case ECP_224_BIT:
+                       case ECP_224_BP:
+                       case ECP_192_BIT:
+                       case NTRU_112_BIT:
+                               /* rarely used */
+                               break;
+                       case MODP_2048_BIT:
+                               add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       return TRUE;
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create_default(protocol_id_t protocol)
+{
+       private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
+
+       switch (protocol)
+       {
+               case PROTO_IKE:
+                       if (!proposal_add_supported_ike(this, FALSE))
+                       {
+                               destroy(this);
+                               return NULL;
+                       }
+                       break;
+               case PROTO_ESP:
+                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          128);
+                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          192);
+                       add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC,          256);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
+                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+                       break;
+               case PROTO_AH:
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,  0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,       0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,        0);
+                       add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
+                       break;
+               default:
+                       break;
+       }
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create_default_aead(protocol_id_t protocol)
+{
+       private_proposal_t *this;
+
+       switch (protocol)
+       {
+               case PROTO_IKE:
+                       this = (private_proposal_t*)proposal_create(protocol, 0);
+                       if (!proposal_add_supported_ike(this, TRUE))
+                       {
+                               destroy(this);
+                               return NULL;
+                       }
+                       return &this->public;
+               case PROTO_ESP:
+                       /* we currently don't include any AEAD proposal for ESP, as we
+                        * don't know if our kernel backend actually supports it. */
+                       return NULL;
+               case PROTO_AH:
+               default:
+                       return NULL;
+       }
+}
+
+/*
+ * Described in header
+ */
+proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
+{
+       private_proposal_t *this;
+       enumerator_t *enumerator;
+       bool failed = TRUE;
+       char *alg;
+
+       this = (private_proposal_t*)proposal_create(protocol, 0);
+
+       /* get all tokens, separated by '-' */
+       enumerator = enumerator_create_token(algs, "-", " ");
+       while (enumerator->enumerate(enumerator, &alg))
+       {
+               if (!add_string_algo(this, alg))
+               {
+                       failed = TRUE;
+                       break;
+               }
+               failed = FALSE;
+       }
+       enumerator->destroy(enumerator);
+
+       if (failed || !check_proposal(this))
+       {
+               destroy(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
diff --git a/src/libstrongswan/crypto/proposal/proposal.h b/src/libstrongswan/crypto/proposal/proposal.h
new file mode 100644 (file)
index 0000000..d9a2af7
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2009-2016 Tobias Brunner
+ * Copyright (C) 2006 Martin Willi
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup proposal proposal
+ * @{ @ingroup crypto
+ */
+
+#ifndef PROPOSAL_H_
+#define PROPOSAL_H_
+
+typedef enum protocol_id_t protocol_id_t;
+typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
+typedef struct proposal_t proposal_t;
+
+#include <library.h>
+#include <utils/identification.h>
+#include <collections/linked_list.h>
+#include <networking/host.h>
+#include <crypto/transform.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+#include <crypto/diffie_hellman.h>
+#include <selectors/traffic_selector.h>
+
+/**
+ * Protocol ID of a proposal.
+ */
+enum protocol_id_t {
+       PROTO_NONE = 0,
+       PROTO_IKE = 1,
+       PROTO_AH = 2,
+       PROTO_ESP = 3,
+       PROTO_IPCOMP = 4, /* IKEv1 only */
+};
+
+/**
+ * enum names for protocol_id_t
+ */
+extern enum_name_t *protocol_id_names;
+
+/**
+ * Stores a set of algorithms used for an SA.
+ *
+ * A proposal stores algorithms for a specific
+ * protocol. It can store algorithms for one protocol.
+ * Proposals with multiple protocols are not supported,
+ * as it's not specified in RFC4301 anymore.
+ */
+struct proposal_t {
+
+       /**
+        * Add an algorithm to the proposal.
+        *
+        * The algorithms are stored by priority, first added
+        * is the most preferred.
+        * Key size is only needed for encryption algorithms
+        * with variable key size (such as AES). Must be set
+        * to zero if key size is not specified.
+        * The alg parameter accepts encryption_algorithm_t,
+        * integrity_algorithm_t, dh_group_number_t and
+        * extended_sequence_numbers_t.
+        *
+        * @param type                  kind of algorithm
+        * @param alg                   identifier for algorithm
+        * @param key_size              key size to use
+        */
+       void (*add_algorithm) (proposal_t *this, transform_type_t type,
+                                                  uint16_t alg, uint16_t key_size);
+
+       /**
+        * Get an enumerator over algorithms for a specific algo type.
+        *
+        * @param type                  kind of algorithm
+        * @return                              enumerator over uint16_t alg, uint16_t key_size
+        */
+       enumerator_t *(*create_enumerator) (proposal_t *this, transform_type_t type);
+
+       /**
+        * Get the algorithm for a type to use.
+        *
+        * If there are multiple algorithms, only the first is returned.
+        *
+        * @param type                  kind of algorithm
+        * @param alg                   pointer which receives algorithm
+        * @param key_size              pointer which receives the key size
+        * @return                              TRUE if algorithm of this kind available
+        */
+       bool (*get_algorithm) (proposal_t *this, transform_type_t type,
+                                                  uint16_t *alg, uint16_t *key_size);
+
+       /**
+        * Check if the proposal has a specific DH group.
+        *
+        * @param group                 group to check for
+        * @return                              TRUE if algorithm included
+        */
+       bool (*has_dh_group) (proposal_t *this, diffie_hellman_group_t group);
+
+       /**
+        * Strip DH groups from proposal to use it without PFS.
+        *
+        * @param keep                  group to keep (MODP_NONE to remove all)
+        */
+       void (*strip_dh)(proposal_t *this, diffie_hellman_group_t keep);
+
+       /**
+        * Compare two proposal, and select a matching subset.
+        *
+        * If the proposals are for the same protocols (AH/ESP), they are
+        * compared. If they have at least one algorithm of each type
+        * in common, a resulting proposal of this kind is created.
+        *
+        * @param other                 proposal to compare against
+        * @param other_remote  whether other is the remote proposal from which to
+        *                                              copy SPI and proposal number to the result,
+        *                                              otherwise copy from this proposal
+        * @param private               accepts algorithms allocated in a private range
+        * @return                              selected proposal, NULL if proposals don't match
+        */
+       proposal_t *(*select)(proposal_t *this, proposal_t *other,
+                                                 bool other_remote, bool private);
+
+       /**
+        * Get the protocol ID of the proposal.
+        *
+        * @return                              protocol of the proposal
+        */
+       protocol_id_t (*get_protocol) (proposal_t *this);
+
+       /**
+        * Get the SPI of the proposal.
+        *
+        * @return                              spi for proto
+        */
+       uint64_t (*get_spi) (proposal_t *this);
+
+       /**
+        * Set the SPI of the proposal.
+        *
+        * @param spi                   spi to set for proto
+        */
+       void (*set_spi) (proposal_t *this, uint64_t spi);
+
+       /**
+        * Get the proposal number, as encoded in SA payload
+        *
+        * @return                              proposal number
+        */
+       u_int (*get_number)(proposal_t *this);
+
+       /**
+        * Check for the eqality of two proposals.
+        *
+        * @param other                 other proposal to check for equality
+        * @return                              TRUE if other equal to this
+        */
+       bool (*equals)(proposal_t *this, proposal_t *other);
+
+       /**
+        * Clone a proposal.
+        *
+        * @return                              clone of proposal
+        */
+       proposal_t *(*clone) (proposal_t *this);
+
+       /**
+        * Destroys the proposal object.
+        */
+       void (*destroy) (proposal_t *this);
+};
+
+/**
+ * Create a child proposal for AH, ESP or IKE.
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @param number                       proposal number, as encoded in SA payload
+ * @return                                     proposal_t object
+ */
+proposal_t *proposal_create(protocol_id_t protocol, u_int number);
+
+/**
+ * Create a default proposal if nothing further specified.
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @return                                     proposal_t object
+ */
+proposal_t *proposal_create_default(protocol_id_t protocol);
+
+/**
+ * Create a default proposal for supported AEAD algorithms
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @return                                     proposal_t object, NULL if none supported
+ */
+proposal_t *proposal_create_default_aead(protocol_id_t protocol);
+
+/**
+ * Create a proposal from a string identifying the algorithms.
+ *
+ * The string is in the same form as a in the ipsec.conf file.
+ * E.g.:       aes128-sha2_256-modp2048
+ *               3des-md5
+ * An additional '!' at the end of the string forces this proposal,
+ * without it the peer may choose another algorithm we support.
+ *
+ * @param protocol                     protocol, such as PROTO_ESP
+ * @param algs                         algorithms as string
+ * @return                                     proposal_t object
+ */
+proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs);
+
+/**
+ * printf hook function for proposal_t.
+ *
+ * Arguments are:
+ *     proposal_t *proposal
+ * With the #-specifier, arguments are:
+ *     linked_list_t *list containing proposal_t*
+ */
+int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
+                                                const void *const *args);
+
+#endif /** PROPOSAL_H_ @}*/
index 856abdc..b062221 100644 (file)
@@ -37,7 +37,7 @@
 
 /**
  * @defgroup proposal_keywords proposal_keywords
- * @{ @ingroup crypto
+ * @{ @ingroup proposal
  */
 
 #ifndef PROPOSAL_KEYWORDS_H_
index 7944b93..dbdf5cf 100644 (file)
@@ -26,6 +26,7 @@
 #include <collections/hashtable.h>
 #include <utils/backtrace.h>
 #include <selectors/traffic_selector.h>
+#include <crypto/proposal/proposal.h>
 
 #define CHECKSUM_LIBRARY IPSEC_LIB_DIR"/libchecksum.so"
 
@@ -369,6 +370,8 @@ bool library_init(char *settings, const char *namespace)
                                         PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
        pfh->add_handler(pfh, 'R', traffic_selector_printf_hook,
                                         PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
+       pfh->add_handler(pfh, 'P', proposal_printf_hook,
+                                        PRINTF_HOOK_ARGTYPE_POINTER, PRINTF_HOOK_ARGTYPE_END);
 
        this->objects = hashtable_create((hashtable_hash_t)hash,
                                                                         (hashtable_equals_t)equals, 4);
index 07f5eb5..5737e7a 100644 (file)
@@ -47,6 +47,7 @@ libstrongswan_tests_SOURCES = tests.h tests.c \
   suites/test_auth_cfg.c \
   suites/test_hasher.c \
   suites/test_crypter.c \
+  suites/test_proposal.c \
   suites/test_crypto_factory.c \
   suites/test_iv_gen.c \
   suites/test_pen.c \
diff --git a/src/libstrongswan/tests/suites/test_proposal.c b/src/libstrongswan/tests/suites/test_proposal.c
new file mode 100644 (file)
index 0000000..9176626
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "test_suite.h"
+
+#include <crypto/proposal/proposal.h>
+
+static struct {
+       protocol_id_t proto;
+       char *proposal;
+       char *expected;
+} create_data[] = {
+       { PROTO_IKE, "", NULL },
+       { PROTO_IKE, "sha256", NULL },
+       { PROTO_IKE, "sha256-modp3072", NULL },
+       { PROTO_IKE, "null-sha256-modp3072", "IKE:NULL/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128", NULL },
+       { PROTO_IKE, "aes128-sha256", NULL },
+       { PROTO_IKE, "aes128-sha256-modpnone", NULL },
+       { PROTO_IKE, "aes128-sha256-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128-sha256-prfsha384-modp3072", "IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_384/MODP_3072" },
+       { PROTO_IKE, "aes128gcm16-modp3072", NULL },
+       { PROTO_IKE, "aes128gcm16-prfsha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128gcm16-sha256-modp3072", "IKE:AES_GCM_16_128/PRF_HMAC_SHA2_256/MODP_3072" },
+       { PROTO_IKE, "aes128gcm16-aes128-modp3072", NULL },
+       { PROTO_IKE, "aes128gcm16-aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "", NULL },
+       { PROTO_ESP, "sha256", NULL },
+       { PROTO_ESP, "aes128-sha256", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-esn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-esn-noesn", "ESP:AES_CBC_128/HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128-sha256-prfsha256-modp3072", "ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_3072/NO_EXT_SEQ" },
+       { PROTO_ESP, "aes128gcm16-aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "aes128gmac", "ESP:NULL_AES_GMAC_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "", NULL },
+       { PROTO_AH,  "aes128", NULL },
+       { PROTO_AH,  "aes128-sha256", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "sha256-sha1", "AH:HMAC_SHA2_256_128/HMAC_SHA1_96/NO_EXT_SEQ" },
+       { PROTO_AH,  "aes128gmac-sha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "aes128gmac-sha256-prfsha256", "AH:AES_128_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "aes128gmac-aes256gmac-aes128-sha256", "AH:AES_128_GMAC/AES_256_GMAC/HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "sha256-esn", "AH:HMAC_SHA2_256_128/EXT_SEQ" },
+       { PROTO_AH,  "sha256-noesn", "AH:HMAC_SHA2_256_128/NO_EXT_SEQ" },
+       { PROTO_AH,  "sha256-esn-noesn", "AH:HMAC_SHA2_256_128/EXT_SEQ/NO_EXT_SEQ" },
+};
+
+START_TEST(test_create_from_string)
+{
+       proposal_t *proposal;
+       char str[BUF_LEN];
+
+       proposal = proposal_create_from_string(create_data[_i].proto,
+                                                                                  create_data[_i].proposal);
+       if (!create_data[_i].expected)
+       {
+               ck_assert(!proposal);
+               return;
+       }
+       snprintf(str, sizeof(str), "%P", proposal);
+       ck_assert_str_eq(create_data[_i].expected, str);
+       proposal->destroy(proposal);
+}
+END_TEST
+
+static struct {
+       protocol_id_t proto;
+       char *self;
+       char *other;
+       char *expected;
+} select_data[] = {
+       { PROTO_ESP, "aes128", "aes128", "aes128" },
+       { PROTO_ESP, "aes128", "aes256", NULL },
+       { PROTO_ESP, "aes128-aes256", "aes256-aes128", "aes128" },
+       { PROTO_ESP, "aes256-aes128", "aes128-aes256", "aes256" },
+       { PROTO_ESP, "aes128-aes256-sha1-sha256", "aes256-aes128-sha256-sha1", "aes128-sha1" },
+       { PROTO_ESP, "aes256-aes128-sha256-sha1", "aes128-aes256-sha1-sha256", "aes256-sha256" },
+       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256", NULL },
+       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "aes128-sha256-modp3072", "aes128-sha256-modpnone", NULL },
+       { PROTO_ESP, "aes128-sha256-modpnone", "aes128-sha256-modp3072", NULL },
+       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256", "aes128-sha256" },
+       { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
+       { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072" },
+       { PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone" },
+       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
+       { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072" },
+       { PROTO_IKE, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
+};
+
+START_TEST(test_select)
+{
+       proposal_t *self, *other, *selected, *expected;
+
+       self = proposal_create_from_string(select_data[_i].proto,
+                                                                          select_data[_i].self);
+       other = proposal_create_from_string(select_data[_i].proto,
+                                                                               select_data[_i].other);
+       selected = self->select(self, other, TRUE, FALSE);
+       if (select_data[_i].expected)
+       {
+               expected = proposal_create_from_string(select_data[_i].proto,
+                                                                                          select_data[_i].expected);
+               ck_assert(selected);
+               ck_assert_msg(expected->equals(expected, selected), "proposal %P does "
+                                         "not match expected %P", selected, expected);
+               expected->destroy(expected);
+       }
+       else
+       {
+               ck_assert(!selected);
+       }
+       DESTROY_IF(selected);
+       other->destroy(other);
+       self->destroy(self);
+}
+END_TEST
+
+START_TEST(test_select_spi)
+{
+       proposal_t *self, *other, *selected;
+
+       self = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
+       other = proposal_create_from_string(PROTO_ESP, "aes128-sha256-modp3072");
+       other->set_spi(other, 0x12345678);
+
+       selected = self->select(self, other, TRUE, FALSE);
+       ck_assert(selected);
+       ck_assert_int_eq(selected->get_spi(selected), other->get_spi(other));
+       selected->destroy(selected);
+
+       selected = self->select(self, other, FALSE, FALSE);
+       ck_assert(selected);
+       ck_assert_int_eq(selected->get_spi(selected), self->get_spi(self));
+       selected->destroy(selected);
+
+       other->destroy(other);
+       self->destroy(self);
+}
+END_TEST
+
+Suite *proposal_suite_create()
+{
+       Suite *s;
+       TCase *tc;
+
+       s = suite_create("proposal");
+
+       tc = tcase_create("create_from_string");
+       tcase_add_loop_test(tc, test_create_from_string, 0, countof(create_data));
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("select");
+       tcase_add_loop_test(tc, test_select, 0, countof(select_data));
+       tcase_add_test(tc, test_select_spi);
+       suite_add_tcase(s, tc);
+
+       return s;
+}
index 525bdeb..5fab227 100644 (file)
@@ -40,6 +40,7 @@ TEST_SUITE(printf_suite_create)
 TEST_SUITE(auth_cfg_suite_create)
 TEST_SUITE(hasher_suite_create)
 TEST_SUITE(crypter_suite_create)
+TEST_SUITE(proposal_suite_create)
 TEST_SUITE(crypto_factory_suite_create)
 TEST_SUITE_DEPEND(iv_gen_suite_create, RNG, RNG_STRONG)
 TEST_SUITE(pen_suite_create)