From 73d3b9c032eae2074726cd3668546af1c44a8323 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 28 Jun 2012 19:33:05 +0200 Subject: The 'be ready for Jelly Beans' commit - fix concurrentaccess occuring on JB - JB does not allow to extract the private keys from the key storage, rewrite using the key storage to use JAVA API and the external-key management interface --- src/de/blinkt/openvpn/ConfigConverter.java | 1 + src/de/blinkt/openvpn/FileSelect.java | 2 +- src/de/blinkt/openvpn/OpenVPN.java | 6 +- src/de/blinkt/openvpn/OpenVpnManagementThread.java | 40 +++++++++ src/de/blinkt/openvpn/VpnProfile.java | 100 +++++++++++---------- 5 files changed, 99 insertions(+), 50 deletions(-) (limited to 'src/de/blinkt') diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java index 5e0a6eb..3ccda05 100644 --- a/src/de/blinkt/openvpn/ConfigConverter.java +++ b/src/de/blinkt/openvpn/ConfigConverter.java @@ -134,6 +134,7 @@ public class ConfigConverter extends ListActivity { filedata += new String(buf,0,len); len = fis.read(buf); } + fis.close(); return filedata; } catch (FileNotFoundException e) { log(e.getLocalizedMessage()); diff --git a/src/de/blinkt/openvpn/FileSelect.java b/src/de/blinkt/openvpn/FileSelect.java index c235594..bbad5cf 100644 --- a/src/de/blinkt/openvpn/FileSelect.java +++ b/src/de/blinkt/openvpn/FileSelect.java @@ -113,7 +113,7 @@ public class FileSelect extends Activity { data += new String(buf,0,len); len=fis.read(buf); } - + fis.close(); mData =data; mInlineFragment.setData(data); getActionBar().selectTab(inlineFileTab); diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index 64ecf17..db98020 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -147,7 +147,7 @@ public class OpenVPN { } - public static void updateStateString(String state, String msg) { + public synchronized static void updateStateString(String state, String msg) { for (StateListener sl : stateListener) { sl.updateState(state,msg); } @@ -179,7 +179,9 @@ public class OpenVPN { public static void logError(int ressourceId) { newlogItem(new LogItem(LogItem.ERROR, ressourceId)); } - + public static void logError(int ressourceId, Object... args) { + newlogItem(new LogItem(LogItem.ERROR, ressourceId,args)); + } } diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index f23d9d9..e1b3734 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -5,11 +5,20 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; import java.util.LinkedList; import java.util.Vector; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + import android.net.LocalSocket; import android.os.ParcelFileDescriptor; +import android.util.Base64; import android.util.Log; public class OpenVpnManagementThread implements Runnable { @@ -173,6 +182,8 @@ public class OpenVpnManagementThread implements Runnable { // 1 log level N,I,E etc. // 2 log message OpenVPN.logMessage(0, "", args[2]); + } else if (cmd.equals("RSA_SIGN")) { + processSignCommand(argument); } else { OpenVPN.logMessage(0, "MGMT:", "Got unrecognized command" + command); Log.i(TAG, "Got unrecognized command" + command); @@ -389,4 +400,33 @@ public class OpenVpnManagementThread implements Runnable { } + private void processSignCommand(String b64data) { + PrivateKey privkey = mProfile.getKeystoreKey(); + Exception err =null; + try{ + byte[] data = Base64.decode(b64data, Base64.DEFAULT); + Cipher rsasinger = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1PADDING"); + rsasinger.init(Cipher.ENCRYPT_MODE, privkey); + + byte[] signed_bytes = rsasinger.doFinal(data); + String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + managmentCommand("rsa-sig\n"); + managmentCommand(signed_string); + managmentCommand("\nEND\n"); + } catch (NoSuchAlgorithmException e){ + err =e; + } catch (InvalidKeyException e) { + err =e; + } catch (NoSuchPaddingException e) { + err =e; + } catch (IllegalBlockSizeException e) { + err =e; + } catch (BadPaddingException e) { + err =e; + } + if(err !=null) { + OpenVPN.logError(R.string.error_rsa_sign,err.getLocalizedMessage()); + } + } + } diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index dd729a0..8b758b3 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -4,25 +4,23 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Collection; -import java.util.Random; import java.util.UUID; import java.util.Vector; +import org.spongycastle.util.io.pem.PemObject; +import org.spongycastle.util.io.pem.PemWriter; + import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -51,8 +49,7 @@ public class VpnProfile implements Serializable{ protected transient String mTransientPW=null; protected transient String mTransientPCKS12PW=null; - - private static transient String mTempPKCS12Password; + private transient PrivateKey mPrivateKey; public static String DEFAULT_DNS1="131.234.137.23"; public static String DEFAULT_DNS2="131.234.137.24"; @@ -100,6 +97,7 @@ public class VpnProfile implements Serializable{ public boolean mUseDefaultRoutev6=true; public String mCustomRoutesv6=""; public String mKeyPassword=""; + public void clearDefaults() { @@ -122,7 +120,8 @@ public class VpnProfile implements Serializable{ } - static final String OVPNCONFIGPKCS12 = "android.pkcs12"; + static final String OVPNCONFIGCA = "android-ca.pem"; + static final String OVPNCONFIGUSERCERT = "android-user.pem"; public VpnProfile(String name) { @@ -223,9 +222,10 @@ public class VpnProfile implements Serializable{ case VpnProfile.TYPE_USERPASS_KEYSTORE: cfg+="auth-user-pass\n"; case VpnProfile.TYPE_KEYSTORE: - cfg+="pkcs12 "; - cfg+=cacheDir.getAbsolutePath() + "/" + OVPNCONFIGPKCS12; - cfg+="\n"; + cfg+="ca " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGCA + "\n"; + cfg+="cert " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGUSERCERT + "\n"; + cfg+="management-external-key\n"; + break; case VpnProfile.TYPE_USERPASS: cfg+="auth-user-pass\n"; @@ -447,7 +447,7 @@ public class VpnProfile implements Serializable{ Intent intent = new Intent(context,OpenVpnService.class); if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - savePKCS12(context); + saveCertificates(context); } intent.putExtra(prefix + ".ARGV" , buildOpenvpnArgv(context.getCacheDir())); @@ -468,27 +468,13 @@ public class VpnProfile implements Serializable{ return intent; } - private String getTemporaryPKCS12Password() { - if(mTempPKCS12Password!=null) - return mTempPKCS12Password; - - String pw= ""; - // Put enough digits togher to make a password :) - Random r = new Random(); - for(int i=0;i < 4;i++) { - pw += Integer.valueOf(r.nextInt(1000)).toString(); - } - - mTempPKCS12Password=pw; - return mTempPKCS12Password; - - } - - private void savePKCS12(Context context) { + private void saveCertificates(Context context) { PrivateKey privateKey = null; X509Certificate[] cachain=null; try { privateKey = KeyChain.getPrivateKey(context,mAlias); + mPrivateKey = privateKey; + cachain = KeyChain.getCertificateChain(context, mAlias); if(cachain.length <= 1 && !nonNull(mCaFilename)) OpenVPN.logMessage(0, "", context.getString(R.string.keychain_nocacert)); @@ -496,32 +482,50 @@ public class VpnProfile implements Serializable{ for(X509Certificate cert:cachain) { OpenVPN.logInfo(R.string.cert_from_keystore,cert.getSubjectDN()); } + + - KeyStore ks = KeyStore.getInstance("PKCS12"); - ks.load(null, null); + if(nonNull(mCaFilename)) { try { - Certificate cacert = getCacertFromFile(); - - ks.setCertificateEntry("cacert", cacert); + Certificate cacert = getCacertFromFile(); + X509Certificate[] newcachain = new X509Certificate[cachain.length+1]; + for(int i=0;i= 1){ + X509Certificate usercert = cachain[0]; + + FileWriter userout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGUSERCERT); + + PemWriter upw = new PemWriter(userout); + upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded())); + upw.close(); + + } + return; } catch (InterruptedException e) { e.printStackTrace(); - } catch (KeyStoreException e) { - e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (IOException e) { @@ -574,10 +578,6 @@ public class VpnProfile implements Serializable{ return pwcopy; } switch (mAuthenticationType) { - case TYPE_KEYSTORE: - case TYPE_USERPASS_KEYSTORE: - return getTemporaryPKCS12Password(); - case TYPE_PKCS12: case TYPE_USERPASS_PKCS12: return mPKCS12Password; @@ -623,6 +623,7 @@ public class VpnProfile implements Serializable{ data += new String(buf,0,len); len = fr.read(buf); } + fr.close(); } catch (FileNotFoundException e) { return false; } catch (IOException e) { @@ -684,6 +685,11 @@ public class VpnProfile implements Serializable{ } + public PrivateKey getKeystoreKey() { + return mPrivateKey; + } + + } -- cgit v1.2.3