summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2013-07-11 23:38:59 +0200
committerArne Schwabe <arne@rfc2549.org>2013-07-11 23:38:59 +0200
commit9597430cdbdd5f613b3442347cbe666b1336a454 (patch)
treec89b54ca6509be359017efc393ff9a58d5664e83
parent383c519222d1e7e9d76bd520d3334a15348c324e (diff)
Usage reflection to use Android Bouncycastle to print Subject DN, also display CN in the basic settings screen
--HG-- extra : rebase_source : 6cff9134e9f0bd0e5261edd7ac0b4139b1580d3b
-rw-r--r--res/layout/keystore_selector.xml67
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java6
-rw-r--r--src/de/blinkt/openvpn/core/X509Utils.java42
-rw-r--r--src/de/blinkt/openvpn/fragments/Settings_Basic.java41
4 files changed, 118 insertions, 38 deletions
diff --git a/res/layout/keystore_selector.xml b/res/layout/keystore_selector.xml
index 211e977b..28a51836 100644
--- a/res/layout/keystore_selector.xml
+++ b/res/layout/keystore_selector.xml
@@ -17,39 +17,52 @@
<!-- A layout to select a certificate, akin to a file selector on web pages. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="8dip"
- android:gravity="center_vertical" >
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dip"
+ android:gravity="center_vertical">
<Button
- android:id="@+id/select_keystore_button"
- style="@style/accountSetupButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:text="@string/select" />
+ android:id="@+id/select_keystore_button"
+ style="@style/accountSetupButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:text="@string/select"/>
<TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_toLeftOf="@+id/select_keystore_button"
- android:textStyle="bold" />
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_toLeftOf="@+id/select_keystore_button"
+ android:text="@string/client_certificate_title"
+ android:textStyle="bold"/>
<TextView
- android:id="@+id/aliasname"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_below="@+id/title"
- android:layout_marginLeft="16dip"
- android:layout_toLeftOf="@+id/select_keystore_button"
- android:ellipsize="end"
- android:singleLine="true"
- android:text="@string/no_certificate" />
+ android:id="@+id/aliasname"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@+id/title"
+ android:layout_marginLeft="16dip"
+ android:layout_toLeftOf="@+id/select_keystore_button"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:text="@string/no_certificate"/>
+
+ <TextView
+ android:id="@+id/alias_certificate"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="16dip"
+ android:layout_below="@id/aliasname"
+ android:layout_toLeftOf="@+id/select_keystore_button"
+ android:ellipsize="end"
+ android:singleLine="true"
+ />
<!-- android:textColor="@color/text_secondary_color" -->
</RelativeLayout> \ No newline at end of file
diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java
index 190cdf9a..e44847b6 100644
--- a/src/de/blinkt/openvpn/VpnProfile.java
+++ b/src/de/blinkt/openvpn/VpnProfile.java
@@ -573,12 +573,6 @@ public class VpnProfile implements Serializable{
if(cachain.length <= 1 && !nonNull(mCaFilename))
OpenVPN.logMessage(0, "", context.getString(R.string.keychain_nocacert));
- for(X509Certificate cert:cachain) {
- OpenVPN.logInfo(R.string.cert_from_keystore,X509Utils.getCertificateFriendlyName(cert));
- }
-
-
-
if(nonNull(mCaFilename)) {
try {
diff --git a/src/de/blinkt/openvpn/core/X509Utils.java b/src/de/blinkt/openvpn/core/X509Utils.java
index 4d2e6668..efdda3ca 100644
--- a/src/de/blinkt/openvpn/core/X509Utils.java
+++ b/src/de/blinkt/openvpn/core/X509Utils.java
@@ -8,12 +8,16 @@ import de.blinkt.openvpn.VpnProfile;
import org.spongycastle.util.io.pem.PemObject;
import org.spongycastle.util.io.pem.PemReader;
+
import javax.security.auth.x500.X500Principal;
import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.Hashtable;
public class X509Utils {
public static Certificate getCertificateFromFile(String certfilename) throws FileNotFoundException, CertificateException {
@@ -70,10 +74,42 @@ public class X509Utils {
}
public static String getCertificateFriendlyName(X509Certificate cert) {
- X500Principal principal = (X500Principal) cert.getSubjectDN();
+ X500Principal principal = cert.getSubjectX500Principal();
+ byte[] encodedSubject = principal.getEncoded();
+ String friendlyName=null;
+
+ /* Hack so we do not have to ship a whole Spongy/bouncycastle */
+ try {
+ Class X509NameClass = Class.forName("com.android.org.bouncycastle.asn1.x509.X509Name");
+ Method getInstance = X509NameClass.getMethod("getInstance",Object.class);
+
+ Hashtable defaultSymbols = (Hashtable) X509NameClass.getField("DefaultSymbols").get(X509NameClass);
+
+ if (!defaultSymbols.containsKey("1.2.840.113549.1.9.1"))
+ defaultSymbols.put("1.2.840.113549.1.9.1","eMail");
+
+ Object subjectName = getInstance.invoke(X509NameClass, encodedSubject);
+
+ Method toString = X509NameClass.getMethod("toString",boolean.class,Hashtable.class);
+
+ friendlyName= (String) toString.invoke(subjectName,true,defaultSymbols);
+
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+
+ /* Fallback if the reflection method did not work */
+ if(friendlyName==null)
+ friendlyName = principal.getName();
- String friendlyName = principal.getName();
- System.out.println(friendlyName);
// Really evil hack to decode email address
// See: http://code.google.com/p/android/issues/detail?id=21531
diff --git a/src/de/blinkt/openvpn/fragments/Settings_Basic.java b/src/de/blinkt/openvpn/fragments/Settings_Basic.java
index 77025dbd..5dc4e437 100644
--- a/src/de/blinkt/openvpn/fragments/Settings_Basic.java
+++ b/src/de/blinkt/openvpn/fragments/Settings_Basic.java
@@ -29,6 +29,10 @@ import de.blinkt.openvpn.R;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.R.id;
import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.X509Utils;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
public class Settings_Basic extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback {
private static final int CHOOSE_FILE_OFFSET = 1000;
@@ -42,6 +46,7 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On
private FileSelectLayout mCaCert;
private FileSelectLayout mClientKey;
private TextView mAliasName;
+ private TextView mAliasCertificate;
private CheckBox mUseLzo;
private ToggleButton mTcpUdp;
private Spinner mType;
@@ -58,13 +63,13 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On
private SparseArray<FileSelectLayout> fileselects = new SparseArray<FileSelectLayout>();
- private void addFileSelectLayout (FileSelectLayout fsl) {
+
+ private void addFileSelectLayout (FileSelectLayout fsl) {
int i = fileselects.size() + CHOOSE_FILE_OFFSET;
fileselects.put(i, fsl);
fsl.setFragment(this,i);
}
-
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String profileuuid =getArguments().getString(getActivity().getPackageName() + ".profileUUID");
@@ -72,6 +77,34 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On
getActivity().setTitle(getString(R.string.edit_profile_title, mProfile.getName()));
}
+
+ private void setKeystoreCertficate()
+ {
+ new Thread() {
+ public void run() {
+ String certstr;
+ try {
+
+
+ X509Certificate cert = KeyChain.getCertificateChain(getActivity(), mProfile.mAlias)[0];
+ certstr=X509Utils.getCertificateFriendlyName(cert);
+ } catch (Exception e) {
+ certstr="Could not get certificate from Keystore";
+ }
+
+ final String certStringCopy=certstr;
+ getActivity().runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ mAliasCertificate.setText(certStringCopy);
+ }
+ });
+
+ }
+ }.start();
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -90,6 +123,7 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On
mType = (Spinner) mView.findViewById(R.id.type);
mPKCS12Password = (TextView) mView.findViewById(R.id.pkcs12password);
mAliasName = (TextView) mView.findViewById(R.id.aliasname);
+ mAliasCertificate = (TextView) mView.findViewById(id.alias_certificate);
mUserName = (EditText) mView.findViewById(R.id.auth_username);
mPassword = (EditText) mView.findViewById(R.id.auth_password);
@@ -252,8 +286,11 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On
private void setAlias() {
if(mProfile.mAlias == null) {
mAliasName.setText(R.string.client_no_certificate);
+ mAliasCertificate.setText("");
} else {
+ mAliasCertificate.setText("Loading certificate from Keystore...");
mAliasName.setText(mProfile.mAlias);
+ setKeystoreCertficate();
}
}