summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2012-07-20 00:16:01 +0200
committerArne Schwabe <arne@rfc2549.org>2012-07-20 00:16:01 +0200
commit2f817e8adc632df9f5996aee7b578f1820422d11 (patch)
tree0d42eca5d1cc3be9069f4972d3e0411e881d1102
parentf0c15a0d3396d2a148bf1f1078fa68e7ebf9bcea (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.xml22
-rw-r--r--res/values/strings.xml1
-rw-r--r--src/de/blinkt/openvpn/ConfigConverter.java233
-rw-r--r--src/de/blinkt/openvpn/Settings_Basic.java8
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);