diff options
author | Arne Schwabe <arne@rfc2549.org> | 2012-07-20 00:16:01 +0200 |
---|---|---|
committer | Arne Schwabe <arne@rfc2549.org> | 2012-07-20 00:16:01 +0200 |
commit | 5b97d4a3d62cb70c790f2c71c464224368483ae8 (patch) | |
tree | e69860ccd3fa0b096a8c841b3f6a55d251f08d54 | |
parent | 1e7773f944ec179fa9057212a4a2910893e1b770 (diff) |
- Use config file name instead for default VPN name (closes issue #53)
- Allow importing the pkcs12 into the android keystone when converting configuration
-rw-r--r-- | res/layout/config_converter.xml | 22 | ||||
-rw-r--r-- | res/values/strings.xml | 1 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/ConfigConverter.java | 233 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/Settings_Basic.java | 8 |
4 files changed, 215 insertions, 49 deletions
diff --git a/res/layout/config_converter.xml b/res/layout/config_converter.xml new file mode 100644 index 00000000..13733fb3 --- /dev/null +++ b/res/layout/config_converter.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > +<CheckBox + android:id="@+id/importpkcs12" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:checked="true" + android:text="@string/importpkcs12fromconfig" + android:visibility="gone" + /> + <ListView + android:id="@android:id/list" + android:layout_width="fill_parent" + android:layout_height="fill_parent" /> + + + + </LinearLayout> + diff --git a/res/values/strings.xml b/res/values/strings.xml index 41015848..fca7a777 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -237,4 +237,5 @@ <string name="faq_howto_title">Quick Start</string> <string name="setting_loadtun_summary">Try to load the tun.ko kernel module before trying to connect. Needs rooted devices.</string> <string name="setting_loadtun">Load tun module</string> + <string name="importpkcs12fromconfig">Import PKCS12 from configuration into Android Keystore</string> </resources> 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<String> 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<File> dirlist = new Vector<File>();
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); |