aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2012-08-28 14:09:18 +0200
committerTobias Brunner <tobias@strongswan.org>2012-08-31 18:24:43 +0200
commitf46da851ab51a1b6ef6b9817f49a866fb25e1c09 (patch)
tree492ead8a34dd8958d3d84d246f54b7971ec70fbf /src
parent3f9e90f618b1abb5f25c62d44b2a059cf1b6b78c (diff)
downloadstrongswan-f46da851ab51a1b6ef6b9817f49a866fb25e1c09.tar.bz2
strongswan-f46da851ab51a1b6ef6b9817f49a866fb25e1c09.tar.xz
android: Allow configuration of a user certificate
Diffstat (limited to 'src')
-rw-r--r--src/frontends/android/res/layout/profile_detail_view.xml20
-rw-r--r--src/frontends/android/res/values-de/arrays.xml1
-rw-r--r--src/frontends/android/res/values-de/strings.xml4
-rw-r--r--src/frontends/android/res/values-pl/arrays.xml1
-rw-r--r--src/frontends/android/res/values-pl/strings.xml6
-rw-r--r--src/frontends/android/res/values/arrays.xml1
-rw-r--r--src/frontends/android/res/values/strings.xml4
-rw-r--r--src/frontends/android/src/org/strongswan/android/ui/VpnProfileDetailActivity.java170
8 files changed, 198 insertions, 9 deletions
diff --git a/src/frontends/android/res/layout/profile_detail_view.xml b/src/frontends/android/res/layout/profile_detail_view.xml
index 2a52ae032..39c94348b 100644
--- a/src/frontends/android/res/layout/profile_detail_view.xml
+++ b/src/frontends/android/res/layout/profile_detail_view.xml
@@ -62,7 +62,7 @@
android:id="@+id/vpn_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:spinnerMode="dialog"
+ android:spinnerMode="dropdown"
android:entries="@array/vpn_types" />
<LinearLayout
@@ -100,6 +100,24 @@
</LinearLayout>
+ <LinearLayout
+ android:id="@+id/user_certificate_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:text="@string/profile_user_certificate_label" />
+
+ <include
+ android:id="@+id/select_user_certificate"
+ layout="@layout/certificate_selector" />
+
+ </LinearLayout>
+
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/src/frontends/android/res/values-de/arrays.xml b/src/frontends/android/res/values-de/arrays.xml
index 8661a37be..efa4bcb03 100644
--- a/src/frontends/android/res/values-de/arrays.xml
+++ b/src/frontends/android/res/values-de/arrays.xml
@@ -17,5 +17,6 @@
<!-- the order here must match the enum entries in VpnType.java -->
<string-array name="vpn_types">
<item>IKEv2 EAP (Benutzername/Passwort)</item>
+ <item>IKEv2 Zertifikat</item>
</string-array>
</resources> \ No newline at end of file
diff --git a/src/frontends/android/res/values-de/strings.xml b/src/frontends/android/res/values-de/strings.xml
index 9e415ab8b..a04da7208 100644
--- a/src/frontends/android/res/values-de/strings.xml
+++ b/src/frontends/android/res/values-de/strings.xml
@@ -25,6 +25,7 @@
<string name="search">Suchen</string>
<string name="vpn_not_supported_title">VPN nicht unterstützt</string>
<string name="vpn_not_supported">Ihr Gerät unterstützt keine VPN Anwendungen.\nBitte kontaktieren Sie den Hersteller.</string>
+ <string name="loading">Laden&#8230;</string>
<!-- Log view -->
<string name="log_title">Log</string>
@@ -53,6 +54,9 @@
<string name="profile_username_label">Benutzername:</string>
<string name="profile_password_label">Passwort:</string>
<string name="profile_password_hint">(anfordern wenn benötigt)</string>
+ <string name="profile_user_certificate_label">Benutzer-Zertifikat:</string>
+ <string name="profile_user_select_certificate_label">Benutzer-Zertifikat auswählen</string>
+ <string name="profile_user_select_certificate">Wählen Sie ein bestimmtes Benutzer-Zertifikat</string>
<string name="profile_ca_label">CA-Zertifikat:</string>
<string name="profile_ca_auto_label">Automatisch wählen</string>
<string name="profile_ca_select_certificate_label">CA-Zertifikat auswählen</string>
diff --git a/src/frontends/android/res/values-pl/arrays.xml b/src/frontends/android/res/values-pl/arrays.xml
index ed14934e0..3e1af5f82 100644
--- a/src/frontends/android/res/values-pl/arrays.xml
+++ b/src/frontends/android/res/values-pl/arrays.xml
@@ -17,5 +17,6 @@
<!-- the order here must match the enum entries in VpnType.java -->
<string-array name="vpn_types">
<item>IKEv2 EAP (użytkownik/hasło)</item>
+ <item>IKEv2 certyfikat</item>
</string-array>
</resources> \ No newline at end of file
diff --git a/src/frontends/android/res/values-pl/strings.xml b/src/frontends/android/res/values-pl/strings.xml
index 4a474e88b..54f4259ae 100644
--- a/src/frontends/android/res/values-pl/strings.xml
+++ b/src/frontends/android/res/values-pl/strings.xml
@@ -27,6 +27,7 @@
<string name="search">Szukaj</string>
<string name="vpn_not_supported_title">Nie obsługiwany VPN</string>
<string name="vpn_not_supported">Urządzenie nie obsługuje aplikacji VPN.\nProszę skontaktować się z producentem.</string>
+ <string name="loading">Wczytywanie&#8230;</string>
<!-- Log view -->
<string name="log_title">Log</string>
@@ -54,7 +55,10 @@
<string name="profile_vpn_type_label">Typ:</string>
<string name="profile_username_label">Użytkownik:</string>
<string name="profile_password_label">Hasło:</string>
- <string name="profile_password_hint">(w razie potrzebz zapromptuj)</string>
+ <string name="profile_password_hint">(w razie potrzeby zapromptuj)</string>
+ <string name="profile_user_certificate_label">Certyfikat użytkownika:</string>
+ <string name="profile_user_select_certificate_label">Wybierz certyfikat użytkownika</string>
+ <string name="profile_user_select_certificate">>Wybierz określony certyfikat użytkownika</string>
<string name="profile_ca_label">Certyfikat CA:</string>
<string name="profile_ca_auto_label">Wybierz automatycznie</string>
<string name="profile_ca_select_certificate_label">Wybierz certyfikat CA</string>
diff --git a/src/frontends/android/res/values/arrays.xml b/src/frontends/android/res/values/arrays.xml
index 62164f7c2..21576f22c 100644
--- a/src/frontends/android/res/values/arrays.xml
+++ b/src/frontends/android/res/values/arrays.xml
@@ -17,5 +17,6 @@
<!-- the order here must match the enum entries in VpnType.java -->
<string-array name="vpn_types">
<item>IKEv2 EAP (Username/Password)</item>
+ <item>IKEv2 Certificate</item>
</string-array>
</resources> \ No newline at end of file
diff --git a/src/frontends/android/res/values/strings.xml b/src/frontends/android/res/values/strings.xml
index 29cd6430b..3e4b746fd 100644
--- a/src/frontends/android/res/values/strings.xml
+++ b/src/frontends/android/res/values/strings.xml
@@ -25,6 +25,7 @@
<string name="search">Search</string>
<string name="vpn_not_supported_title">VPN not supported</string>
<string name="vpn_not_supported">Your device does not support VPN applications.\nPlease contact the manufacturer.</string>
+ <string name="loading">Loading&#8230;</string>
<!-- Log view -->
<string name="log_title">Log</string>
@@ -53,6 +54,9 @@
<string name="profile_username_label">Username:</string>
<string name="profile_password_label">Password:</string>
<string name="profile_password_hint">(prompt when needed)</string>
+ <string name="profile_user_certificate_label">User certificate:</string>
+ <string name="profile_user_select_certificate_label">Select user certificate</string>
+ <string name="profile_user_select_certificate">Select a specific user certificate</string>
<string name="profile_ca_label">CA certificate:</string>
<string name="profile_ca_auto_label">Select automatically</string>
<string name="profile_ca_select_certificate_label">Select CA certificate</string>
diff --git a/src/frontends/android/src/org/strongswan/android/ui/VpnProfileDetailActivity.java b/src/frontends/android/src/org/strongswan/android/ui/VpnProfileDetailActivity.java
index 6cdf97b4b..91e521cf4 100644
--- a/src/frontends/android/src/org/strongswan/android/ui/VpnProfileDetailActivity.java
+++ b/src/frontends/android/src/org/strongswan/android/ui/VpnProfileDetailActivity.java
@@ -28,9 +28,14 @@ import org.strongswan.android.logic.TrustedCertificateManager;
import android.app.Activity;
import android.app.AlertDialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+import android.security.KeyChainException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -54,6 +59,8 @@ public class VpnProfileDetailActivity extends Activity
private VpnProfileDataSource mDataSource;
private Long mId;
private TrustedCertificateEntry mCertEntry;
+ private String mUserCertLoading;
+ private TrustedCertificateEntry mUserCertEntry;
private VpnType mVpnType = VpnType.IKEV2_EAP;
private VpnProfile mProfile;
private EditText mName;
@@ -62,6 +69,8 @@ public class VpnProfileDetailActivity extends Activity
private ViewGroup mUsernamePassword;
private EditText mUsername;
private EditText mPassword;
+ private ViewGroup mUserCertificate;
+ private TwoLineListItem mSelectUserCert;
private CheckBox mCheckAuto;
private TwoLineListItem mSelectCert;
@@ -86,6 +95,9 @@ public class VpnProfileDetailActivity extends Activity
mUsername = (EditText)findViewById(R.id.username);
mPassword = (EditText)findViewById(R.id.password);
+ mUserCertificate = (ViewGroup)findViewById(R.id.user_certificate_group);
+ mSelectUserCert = (TwoLineListItem)findViewById(R.id.select_user_certificate);
+
mCheckAuto = (CheckBox)findViewById(R.id.ca_auto);
mSelectCert = (TwoLineListItem)findViewById(R.id.select_certificate);
@@ -94,17 +106,19 @@ public class VpnProfileDetailActivity extends Activity
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
mVpnType = VpnType.values()[position];
- updateClientCredentialView();
+ updateCredentialView();
}
@Override
public void onNothingSelected(AdapterView<?> parent)
{ /* should not happen */
mVpnType = VpnType.IKEV2_EAP;
- updateClientCredentialView();
+ updateCredentialView();
}
});
+ mSelectUserCert.setOnClickListener(new SelectUserCertOnClickListener());
+
mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
@@ -131,7 +145,7 @@ public class VpnProfileDetailActivity extends Activity
loadProfileData(savedInstanceState);
- updateClientCredentialView();
+ updateCredentialView();
updateCertificateSelector();
}
@@ -150,6 +164,10 @@ public class VpnProfileDetailActivity extends Activity
{
outState.putLong(VpnProfileDataSource.KEY_ID, mId);
}
+ if (mUserCertEntry != null)
+ {
+ outState.putString(VpnProfileDataSource.KEY_USER_CERTIFICATE, mUserCertEntry.getAlias());
+ }
if (mCertEntry != null)
{
outState.putString(VpnProfileDataSource.KEY_CERTIFICATE, mCertEntry.getAlias());
@@ -201,11 +219,32 @@ public class VpnProfileDetailActivity extends Activity
}
/**
- * Update the UI to enter client credentials depending on the type of VPN currently selected
+ * Update the UI to enter credentials depending on the type of VPN currently selected
*/
- private void updateClientCredentialView()
+ private void updateCredentialView()
{
mUsernamePassword.setVisibility(mVpnType.getRequiresUsernamePassword() ? View.VISIBLE : View.GONE);
+ mUserCertificate.setVisibility(mVpnType.getRequiresCertificate() ? View.VISIBLE : View.GONE);
+
+ if (mVpnType.getRequiresCertificate())
+ {
+ if (mUserCertLoading != null)
+ {
+ mSelectUserCert.getText1().setText(mUserCertLoading);
+ mSelectUserCert.getText2().setText(R.string.loading);
+ }
+ else if (mUserCertEntry != null)
+ { /* clear any errors and set the new data */
+ mSelectUserCert.getText1().setError(null);
+ mSelectUserCert.getText1().setText(mUserCertEntry.getAlias());
+ mSelectUserCert.getText2().setText(mUserCertEntry.getCertificate().getSubjectDN().toString());
+ }
+ else
+ {
+ mSelectUserCert.getText1().setText(R.string.profile_user_select_certificate_label);
+ mSelectUserCert.getText2().setText(R.string.profile_user_select_certificate);
+ }
+ }
}
/**
@@ -300,6 +339,11 @@ public class VpnProfileDetailActivity extends Activity
valid = false;
}
}
+ if (mVpnType.getRequiresCertificate() && mUserCertEntry == null)
+ { /* let's show an error icon */
+ mSelectUserCert.getText1().setError("");
+ valid = false;
+ }
if (!mCheckAuto.isChecked() && mCertEntry == null)
{
showCertificateAlert();
@@ -326,6 +370,10 @@ public class VpnProfileDetailActivity extends Activity
password = password.isEmpty() ? null : password;
mProfile.setPassword(password);
}
+ if (mVpnType.getRequiresCertificate())
+ {
+ mProfile.setUserCertificateAlias(mUserCertEntry.getAlias());
+ }
String certAlias = mCheckAuto.isChecked() ? null : mCertEntry.getAlias();
mProfile.setCertificateAlias(certAlias);
}
@@ -337,7 +385,7 @@ public class VpnProfileDetailActivity extends Activity
*/
private void loadProfileData(Bundle savedInstanceState)
{
- String alias = null;
+ String useralias = null, alias = null;
getActionBar().setTitle(R.string.add_profile);
if (mId != null && mId != 0)
@@ -350,6 +398,7 @@ public class VpnProfileDetailActivity extends Activity
mVpnType = mProfile.getVpnType();
mUsername.setText(mProfile.getUsername());
mPassword.setText(mProfile.getPassword());
+ useralias = mProfile.getUserCertificateAlias();
alias = mProfile.getCertificateAlias();
getActionBar().setTitle(mProfile.getName());
}
@@ -363,7 +412,16 @@ public class VpnProfileDetailActivity extends Activity
mSelectVpnType.setSelection(mVpnType.ordinal());
- /* check if the user selected a certificate previously */
+ /* check if the user selected a user certificate previously */
+ useralias = savedInstanceState == null ? useralias: savedInstanceState.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE);
+ if (useralias != null)
+ {
+ UserCertificateLoader loader = new UserCertificateLoader(this, useralias);
+ mUserCertLoading = useralias;
+ loader.execute();
+ }
+
+ /* check if the user selected a CA certificate previously */
alias = savedInstanceState == null ? alias : savedInstanceState.getString(VpnProfileDataSource.KEY_CERTIFICATE);
mCheckAuto.setChecked(alias == null);
if (alias != null)
@@ -380,4 +438,102 @@ public class VpnProfileDetailActivity extends Activity
}
}
}
+
+ private class SelectUserCertOnClickListener implements OnClickListener, KeyChainAliasCallback
+ {
+ @Override
+ public void onClick(View v)
+ {
+ String useralias = mUserCertEntry != null ? mUserCertEntry.getAlias() : null;
+ KeyChain.choosePrivateKeyAlias(VpnProfileDetailActivity.this, this, new String[] { "RSA" }, null, null, -1, useralias);
+ }
+
+ @Override
+ public void alias(final String alias)
+ {
+ if (alias != null)
+ { /* otherwise the dialog was canceled, the request denied */
+ try
+ {
+ final X509Certificate[] chain = KeyChain.getCertificateChain(VpnProfileDetailActivity.this, alias);
+ /* alias() is not called from our main thread */
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run()
+ {
+ if (chain != null && chain.length > 0)
+ {
+ mUserCertEntry = new TrustedCertificateEntry(alias, chain[0]);
+ }
+ updateCredentialView();
+ }
+ });
+ }
+ catch (KeyChainException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Load the selected user certificate asynchronously. This cannot be done
+ * from the main thread as getCertificateChain() calls back to our main
+ * thread to bind to the KeyChain service resulting in a deadlock.
+ */
+ private class UserCertificateLoader extends AsyncTask<Void, Void, X509Certificate>
+ {
+ private final Context mContext;
+ private final String mAlias;
+
+ public UserCertificateLoader(Context context, String alias)
+ {
+ mContext = context;
+ mAlias = alias;
+ }
+
+ @Override
+ protected X509Certificate doInBackground(Void... params)
+ {
+ X509Certificate[] chain = null;
+ try
+ {
+ chain = KeyChain.getCertificateChain(mContext, mAlias);
+ }
+ catch (KeyChainException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ if (chain != null && chain.length > 0)
+ {
+ return chain[0];
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(X509Certificate result)
+ {
+ if (result != null)
+ {
+ mUserCertEntry = new TrustedCertificateEntry(mAlias, result);
+ }
+ else
+ { /* previously selected certificate is not here anymore */
+ mSelectUserCert.getText1().setError("");
+ mUserCertEntry = null;
+ }
+ mUserCertLoading = null;
+ updateCredentialView();
+ }
+ }
}