diff options
| -rw-r--r-- | res/layout/keystore_selector.xml | 67 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 6 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/core/X509Utils.java | 42 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/fragments/Settings_Basic.java | 41 | 
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();  		}  	} | 
