From 5b97d4a3d62cb70c790f2c71c464224368483ae8 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 20 Jul 2012 00:16:01 +0200 Subject: - Use config file name instead for default VPN name (closes issue #53) - Allow importing the pkcs12 into the android keystone when converting configuration --- src/de/blinkt/openvpn/ConfigConverter.java | 233 +++++++++++++++++++++++------ src/de/blinkt/openvpn/Settings_Basic.java | 8 +- 2 files changed, 192 insertions(+), 49 deletions(-) (limited to 'src/de/blinkt') diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java index ed252f7d..ee5a4415 100644 --- a/src/de/blinkt/openvpn/ConfigConverter.java +++ b/src/de/blinkt/openvpn/ConfigConverter.java @@ -10,14 +10,21 @@ import java.util.List; import java.util.Vector; import android.app.Activity; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; import android.app.ListActivity; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Bundle; import android.os.Environment; +import android.security.KeyChain; +import android.security.KeyChainAliasCallback; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.View; import android.widget.ArrayAdapter; +import android.widget.CheckBox; import de.blinkt.openvpn.ConfigParser.ConfigParseError; public class ConfigConverter extends ListActivity { @@ -29,13 +36,20 @@ public class ConfigConverter extends ListActivity { private List mPathsegments; + private String mAliasName=null; + + private int RESULT_INSTALLPKCS12 = 7; + + private String mPossibleName=null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.config_converter); } - + + @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()==R.id.cancel){ @@ -47,16 +61,13 @@ public class ConfigConverter extends ListActivity { return true; } - Intent result = new Intent(); - ProfileManager vpl = ProfileManager.getInstance(this); + Intent in = installPKCS12(); - setUniqueProfileName(vpl); - vpl.addProfile(mResult); - vpl.saveProfile(this, mResult); - vpl.saveProfileList(this); - result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString()); - setResult(Activity.RESULT_OK, result); - finish(); + if(in != null) + startActivityForResult(in, RESULT_INSTALLPKCS12); + else + saveProfile(); + return true; } @@ -64,16 +75,101 @@ public class ConfigConverter extends ListActivity { } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if(requestCode==RESULT_INSTALLPKCS12) { + if(resultCode==Activity.RESULT_OK) { + showCertDialog(); + } + } + + super.onActivityResult(requestCode, resultCode, data); + } + + private void saveProfile() { + Intent result = new Intent(); + ProfileManager vpl = ProfileManager.getInstance(this); + + setUniqueProfileName(vpl); + vpl.addProfile(mResult); + vpl.saveProfile(this, mResult); + vpl.saveProfileList(this); + result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString()); + setResult(Activity.RESULT_OK, result); + finish(); + } + + public void showCertDialog () { + try { + KeyChain.choosePrivateKeyAlias(this, + new KeyChainAliasCallback() { + + public void alias(String alias) { + // Credential alias selected. Remember the alias selection for future use. + mResult.mAlias=alias; + saveProfile(); + } + + + }, + new String[] {"RSA"}, // List of acceptable key types. null for any + null, // issuer, null for any + mResult.mServerName, // host name of server requesting the cert, null if unavailable + -1, // port of server requesting the cert, -1 if unavailable + mAliasName); // alias to preselect, null if unavailable + } catch (ActivityNotFoundException anf) { + Builder ab = new AlertDialog.Builder(this); + ab.setTitle(R.string.broken_image_cert_title); + ab.setMessage(R.string.broken_image_cert); + ab.setPositiveButton(android.R.string.ok, null); + ab.show(); + } + } + + + private Intent installPKCS12() { + if(!((CheckBox)findViewById(R.id.importpkcs12)).isChecked()) + return null; + File possiblepkcs12 = findFile(mResult.mPKCS12Filename); + + if(possiblepkcs12!=null) { + Intent inkeyintent = KeyChain.createInstallIntent(); + byte[] pkcs12data; + try { + pkcs12data = readBytesFromFile(possiblepkcs12); + } catch (IOException e) { + return null; + } + + inkeyintent.putExtra(KeyChain.EXTRA_PKCS12,pkcs12data ); + + mAliasName = possiblepkcs12.getName().replace(".p12", ""); + if(mAliasName.equals("")) + mAliasName=null; + + if(mAliasName!=null){ + inkeyintent.putExtra(KeyChain.EXTRA_NAME, mAliasName); + } + return inkeyintent; + + } + return null; + } + private void setUniqueProfileName(ProfileManager vpl) { - int i=1; - String newname = getString(R.string.converted_profile); - + int i=0; + + String newname = mPossibleName; + while(vpl.getProfileByName(newname)!=null) { i++; - newname = getString(R.string.converted_profile_i,i); + if(i==1) + newname = getString(R.string.converted_profile); + else + newname = getString(R.string.converted_profile_i,i); } - + mResult.mName=newname; } @@ -84,19 +180,32 @@ public class ConfigConverter extends ListActivity { return true; } - private String embedFile(String filename) { - if(filename == null || filename.equals("")) + if(filename==null) return null; + // Already embedded, nothing to do if(filename.startsWith(VpnProfile.INLINE_TAG)) return filename; + File possibleFile = findFile(filename); + if(possibleFile==null) + return null; + else + return readFileContent(possibleFile); + + } + + private File findFile(String filename) + { + if(filename == null || filename.equals("")) + return null; + // Try diffent path relative to /mnt/sdcard File sdcard = Environment.getExternalStorageDirectory(); File root = new File("/"); - + Vector dirlist = new Vector(); for(int i=mPathsegments.size()-1;i >=0 ;i--){ @@ -108,8 +217,8 @@ public class ConfigConverter extends ListActivity { } dirlist.add(sdcard); dirlist.add(root); - - + + String[] fileparts = filename.split("/"); for(File rootdir:dirlist){ String suffix=""; @@ -124,26 +233,7 @@ public class ConfigConverter extends ListActivity { continue; // read the file inline - - String filedata = ""; - byte[] buf =new byte[2048]; - - log(R.string.trying_to_read, possibleFile.getAbsolutePath()); - try { - FileInputStream fis = new FileInputStream(possibleFile); - int len = fis.read(buf); - while( len > 0){ - filedata += new String(buf,0,len); - len = fis.read(buf); - } - fis.close(); - return VpnProfile.INLINE_TAG + filedata; - } catch (FileNotFoundException e) { - log(e.getLocalizedMessage()); - } catch (IOException e) { - log(e.getLocalizedMessage()); - } - + return possibleFile; } } @@ -151,6 +241,51 @@ public class ConfigConverter extends ListActivity { return null; } + String readFileContent(File possibleFile) { + String filedata = ""; + byte[] buf =new byte[2048]; + + log(R.string.trying_to_read, possibleFile.getAbsolutePath()); + try { + FileInputStream fis = new FileInputStream(possibleFile); + int len = fis.read(buf); + while( len > 0){ + filedata += new String(buf,0,len); + len = fis.read(buf); + } + fis.close(); + return VpnProfile.INLINE_TAG + filedata; + } catch (FileNotFoundException e) { + log(e.getLocalizedMessage()); + } catch (IOException e) { + log(e.getLocalizedMessage()); + } + + return null; + } + + + private byte[] readBytesFromFile(File file) throws IOException { + InputStream input = new FileInputStream(file); + + long len= file.length(); + + + // Create the byte array to hold the data + byte[] bytes = new byte[(int) len]; + + // Read in the bytes + int offset = 0; + int bytesRead = 0; + while (offset < bytes.length + && (bytesRead=input.read(bytes, offset, bytes.length-offset)) >= 0) { + offset += bytesRead; + } + + input.close(); + return bytes; + } + void embedFiles() { // This where I would like to have a c++ style // void embedFile(std::string & option) @@ -159,7 +294,7 @@ public class ConfigConverter extends ListActivity { mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename); mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename); mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename); - + if(mResult.mUsername != null && !mResult.mUsername.equals("")){ String data =embedFile(mResult.mUsername); mResult.mName=null; @@ -191,9 +326,16 @@ public class ConfigConverter extends ListActivity { //log(R.string.import_experimental); log(R.string.importing_config,data.toString()); try { + if(data.getScheme().equals("file")) { + mPossibleName = data.getLastPathSegment(); + if(mPossibleName!=null){ + mPossibleName =mPossibleName.replace(".ovpn", ""); + mPossibleName =mPossibleName.replace(".conf", ""); + } + } InputStream is = getContentResolver().openInputStream(data); mPathsegments = data.getPathSegments(); - + doImport(is); } catch (FileNotFoundException e) { log(R.string.import_content_resolve_error); @@ -238,12 +380,13 @@ public class ConfigConverter extends ListActivity { int until = copt.indexOf('\n'); copt = copt.substring(until+1); } - + log(copt); } - if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) { - log(R.string.import_pkcs12_to_keystore); + if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE || + mResult.mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { + findViewById(R.id.importpkcs12).setVisibility(View.VISIBLE); } } diff --git a/src/de/blinkt/openvpn/Settings_Basic.java b/src/de/blinkt/openvpn/Settings_Basic.java index 0bf3078a..3ac00a66 100644 --- a/src/de/blinkt/openvpn/Settings_Basic.java +++ b/src/de/blinkt/openvpn/Settings_Basic.java @@ -300,11 +300,11 @@ public class Settings_Basic extends Fragment implements View.OnClickListener, On }, - new String[] {"RSA", "DSA"}, // List of acceptable key types. null for any + new String[] {"RSA"}, // List of acceptable key types. null for any null, // issuer, null for any - "internal.example.com", // host name of server requesting the cert, null if unavailable - 443, // port of server requesting the cert, -1 if unavailable - null); // alias to preselect, null if unavailable + mProfile.mServerName, // host name of server requesting the cert, null if unavailable + -1, // port of server requesting the cert, -1 if unavailable + mProfile.mAlias); // alias to preselect, null if unavailable } catch (ActivityNotFoundException anf) { Builder ab = new AlertDialog.Builder(getActivity()); ab.setTitle(R.string.broken_image_cert_title); -- cgit v1.2.3