summaryrefslogtreecommitdiff
path: root/src/de/blinkt/openvpn
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/blinkt/openvpn')
-rw-r--r--src/de/blinkt/openvpn/ConfigConverter.java1
-rw-r--r--src/de/blinkt/openvpn/ConfigParser.java26
-rw-r--r--src/de/blinkt/openvpn/OpenVpnService.java2
-rw-r--r--src/de/blinkt/openvpn/RemoteCNPreference.java109
-rw-r--r--src/de/blinkt/openvpn/Settings_Authentication.java101
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java111
6 files changed, 274 insertions, 76 deletions
diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java
index d715e8b7..780018f9 100644
--- a/src/de/blinkt/openvpn/ConfigConverter.java
+++ b/src/de/blinkt/openvpn/ConfigConverter.java
@@ -111,6 +111,7 @@ public class ConfigConverter extends ListActivity {
if(mResult.mRemoteCN.startsWith("/"))
mResult.mRemoteCN = mResult.mRemoteCN.substring(1);
mResult.mRemoteCN = mResult.mRemoteCN.replace("/", ", ");
+ mResult.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_DN;
}
public void showCertDialog () {
diff --git a/src/de/blinkt/openvpn/ConfigParser.java b/src/de/blinkt/openvpn/ConfigParser.java
index 60cf22b4..28608c9a 100644
--- a/src/de/blinkt/openvpn/ConfigParser.java
+++ b/src/de/blinkt/openvpn/ConfigParser.java
@@ -439,13 +439,39 @@ public class ConfigParser {
np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE;
noauthtypeset=false;
}
+
+ Vector<String> compatnames = getOption("compat-names",1,2);
+ Vector<String> nonameremapping = getOption("no-name-remapping",1,1);
Vector<String> tlsremote = getOption("tls-remote",1,1);
if(tlsremote!=null){
np.mRemoteCN = tlsremote.get(1);
np.mCheckRemoteCN=true;
+ np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE;
+
+ if((compatnames!=null && compatnames.size() > 2) ||
+ (nonameremapping!=null))
+ np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING;
+ }
+
+ Vector<String> x509verifyname = getOption("x509-verify-name",1,2);
+ if(x509verifyname!=null){
+ np.mRemoteCN = x509verifyname.get(1);
+ np.mCheckRemoteCN=true;
+ if(x509verifyname.size()>2) {
+ if (x509verifyname.get(2).equals("name"))
+ np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN;
+ else if (x509verifyname.get(2).equals("name-prefix"))
+ np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX;
+ else
+ throw new ConfigParseError("Unknown parameter to x509-verify-name: " + x509verifyname.get(2) );
+ } else {
+ np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_DN;
+ }
+
}
+
Vector<String> verb = getOption("verb",1,1);
if(verb!=null){
np.mVerb=verb.get(1);
diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java
index 241bf774..e580089f 100644
--- a/src/de/blinkt/openvpn/OpenVpnService.java
+++ b/src/de/blinkt/openvpn/OpenVpnService.java
@@ -237,7 +237,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
// Registers BroadcastReceiver to track network connection changes.
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
mNetworkStateReceiver = new NetworkSateReceiver(magnagement);
- this.registerReceiver(mNetworkStateReceiver, filter);
+ registerReceiver(mNetworkStateReceiver, filter);
}
synchronized void unregisterNetworkStateReceiver() {
diff --git a/src/de/blinkt/openvpn/RemoteCNPreference.java b/src/de/blinkt/openvpn/RemoteCNPreference.java
new file mode 100644
index 00000000..4daf54c2
--- /dev/null
+++ b/src/de/blinkt/openvpn/RemoteCNPreference.java
@@ -0,0 +1,109 @@
+package de.blinkt.openvpn;
+
+import android.content.Context;
+import android.preference.DialogPreference;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+
+public class RemoteCNPreference extends DialogPreference {
+
+
+ private Spinner mSpinner;
+ private EditText mEditText;
+ private int mDNType;
+ private ArrayAdapter<String> mAuthtypes;
+ private String mDn;
+
+ public RemoteCNPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setDialogLayoutResource(R.layout.tlsremote);
+
+ }
+
+ @Override
+ protected void onBindDialogView(View view) {
+
+ super.onBindDialogView(view);
+
+ mEditText = (EditText) view.findViewById(R.id.tlsremotecn);
+ mSpinner = (Spinner) view.findViewById(R.id.x509verifytype);
+ if(mDn!=null)
+ mEditText.setText(mDn);
+
+ populateSpinner();
+
+ }
+
+ private void populateSpinner() {
+ mAuthtypes = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item);
+ mAuthtypes.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+ mAuthtypes.add(getContext().getString(R.string.complete_dn));
+ mAuthtypes.add("RDN (common name)");
+ mAuthtypes.add("RDN prefix");
+ if (mDNType == VpnProfile.X509_VERIFY_TLSREMOTE || mDNType == VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING )
+ mAuthtypes.add("tls-remote (DEPRECATED)");
+
+ mSpinner.setAdapter(mAuthtypes);
+ }
+
+ public String getCNText() {
+ return mDn;
+ }
+
+ public int getAuthtype() {
+ return mDNType;
+ }
+
+ public void setDN(String dn) {
+ mDn = dn;
+ if(mEditText!=null)
+ mEditText.setText(dn);
+ }
+
+ void setAuthType(int x509authtype) {
+ mDNType = x509authtype;
+ if (mSpinner!=null)
+ populateSpinner();
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ super.onDialogClosed(positiveResult);
+
+ if (positiveResult) {
+ String dn = mEditText.getText().toString();
+ int authtype = getAuthTypeFromSpinner();
+ if (callChangeListener(new Pair<Integer, String>(authtype, dn))) {
+ mDn = dn;
+ mDNType = authtype;
+ }
+ }
+ }
+
+ private int getAuthTypeFromSpinner() {
+ int pos = mSpinner.getSelectedItemPosition();
+ switch (pos) {
+ case 0:
+ return VpnProfile.X509_VERIFY_TLSREMOTE_DN;
+ case 1:
+ return VpnProfile.X509_VERIFY_TLSREMOTE_RDN;
+ case 2:
+ return VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX;
+ case 3:
+ // This is the tls-remote entry, only visible if mDntype is a
+ // tls-remote type
+ return mDNType;
+ default:
+ return VpnProfile.X509_VERIFY_TLSREMOTE;
+ }
+ }
+
+}
diff --git a/src/de/blinkt/openvpn/Settings_Authentication.java b/src/de/blinkt/openvpn/Settings_Authentication.java
index 4e3f1e6f..8f73cd07 100644
--- a/src/de/blinkt/openvpn/Settings_Authentication.java
+++ b/src/de/blinkt/openvpn/Settings_Authentication.java
@@ -11,13 +11,14 @@ import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.SwitchPreference;
+import android.util.Pair;
public class Settings_Authentication extends OpenVpnPreferencesFragment implements OnPreferenceChangeListener, OnPreferenceClickListener {
private static final int SELECT_TLS_FILE = 23223232;
private CheckBoxPreference mExpectTLSCert;
private CheckBoxPreference mCheckRemoteCN;
- private EditTextPreference mRemoteCN;
+ private RemoteCNPreference mRemoteCN;
private ListPreference mTLSAuthDirection;
private Preference mTLSAuthFile;
private SwitchPreference mUseTLSAuth;
@@ -34,34 +35,36 @@ public class Settings_Authentication extends OpenVpnPreferencesFragment implemen
mExpectTLSCert = (CheckBoxPreference) findPreference("remoteServerTLS");
mCheckRemoteCN = (CheckBoxPreference) findPreference("checkRemoteCN");
- mRemoteCN = (EditTextPreference) findPreference("remotecn");
+ mRemoteCN = (RemoteCNPreference) findPreference("remotecn");
mRemoteCN.setOnPreferenceChangeListener(this);
-
+
mUseTLSAuth = (SwitchPreference) findPreference("useTLSAuth" );
mTLSAuthFile = findPreference("tlsAuthFile");
mTLSAuthDirection = (ListPreference) findPreference("tls_direction");
-
-
+
+
mTLSAuthFile.setOnPreferenceClickListener(this);
-
+
mCipher =(EditTextPreference) findPreference("cipher");
mCipher.setOnPreferenceChangeListener(this);
-
+
mAuth =(EditTextPreference) findPreference("auth");
mAuth.setOnPreferenceChangeListener(this);
-
+
loadSettings();
}
@Override
protected void loadSettings() {
-
+
mExpectTLSCert.setChecked(mProfile.mExpectTLSCert);
mCheckRemoteCN.setChecked(mProfile.mCheckRemoteCN);
- mRemoteCN.setText(mProfile.mRemoteCN);
- onPreferenceChange(mRemoteCN, mProfile.mRemoteCN);
-
+ mRemoteCN.setDN(mProfile.mRemoteCN);
+ mRemoteCN.setAuthType(mProfile.mX509AuthType);
+ onPreferenceChange(mRemoteCN,
+ new Pair<Integer, String>(mProfile.mX509AuthType, mProfile.mRemoteCN));
+
mUseTLSAuth.setChecked(mProfile.mUseTLSAuth);
mTlsAuthFileData= mProfile.mTLSAuthFilename;
setTlsAuthSummary(mTlsAuthFileData);
@@ -71,76 +74,106 @@ public class Settings_Authentication extends OpenVpnPreferencesFragment implemen
mAuth.setText(mProfile.mAuth);
onPreferenceChange(mAuth, mProfile.mAuth);
}
-
+
@Override
protected void saveSettings() {
mProfile.mExpectTLSCert=mExpectTLSCert.isChecked();
mProfile.mCheckRemoteCN=mCheckRemoteCN.isChecked();
- mProfile.mRemoteCN=mRemoteCN.getText();
-
+ mProfile.mRemoteCN=mRemoteCN.getCNText();
+ mProfile.mX509AuthType=mRemoteCN.getAuthtype();
+
mProfile.mUseTLSAuth = mUseTLSAuth.isChecked();
mProfile.mTLSAuthFilename = mTlsAuthFileData;
-
+
if(mTLSAuthDirection.getValue()==null)
mProfile.mTLSAuthDirection=null;
else
mProfile.mTLSAuthDirection = mTLSAuthDirection.getValue().toString();
-
+
if(mCipher.getText()==null)
mProfile.mCipher=null;
else
mProfile.mCipher = mCipher.getText();
-
+
if(mAuth.getText()==null)
mProfile.mAuth = null;
else
mProfile.mAuth = mAuth.getText();
-
+
}
-
-
+
+
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if(preference==mRemoteCN) {
- if ("".equals(newValue))
- preference.setSummary(mProfile.mServerName);
+ @SuppressWarnings("unchecked")
+ int authtype = ((Pair<Integer, String>) newValue).first;
+ @SuppressWarnings("unchecked")
+ String dn = ((Pair<Integer, String>) newValue).second;
+
+ if ("".equals(dn))
+ preference.setSummary(getX509String(VpnProfile.X509_VERIFY_TLSREMOTE_RDN, mProfile.mServerName));
else
- preference.setSummary((String)newValue);
+ preference.setSummary(getX509String(authtype,dn));
+
} else if (preference == mCipher || preference == mAuth) {
preference.setSummary((CharSequence) newValue);
}
return true;
}
+ private CharSequence getX509String(int authtype, String dn) {
+ String ret ="";
+ switch (authtype) {
+ case VpnProfile.X509_VERIFY_TLSREMOTE:
+ case VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING:
+ ret+="tls-remote ";
+ break;
+
+ case VpnProfile.X509_VERIFY_TLSREMOTE_DN:
+ ret="dn: ";
+ break;
+
+ case VpnProfile.X509_VERIFY_TLSREMOTE_RDN:
+ ret="rdn: ";
+ break;
+
+ case VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX:
+ ret="rdn prefix: ";
+ break;
+ }
+ return ret + dn;
+ }
+
void startFileDialog() {
Intent startFC = new Intent(getActivity(),FileSelect.class);
startFC.putExtra(FileSelect.START_DATA, Environment.getExternalStorageDirectory().getPath());
-
+
startActivityForResult(startFC,SELECT_TLS_FILE);
}
@Override
public boolean onPreferenceClick(Preference preference) {
startFileDialog();
return true;
-
+
}
-
+
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==SELECT_TLS_FILE && resultCode == Activity.RESULT_OK){
- String result = data.getStringExtra(FileSelect.RESULT_DATA);
- mTlsAuthFileData=result;
- setTlsAuthSummary(result);
-
+ String result = data.getStringExtra(FileSelect.RESULT_DATA);
+ mTlsAuthFileData=result;
+ setTlsAuthSummary(result);
+
}
}
private void setTlsAuthSummary(String result) {
if(result==null) result = getString(R.string.no_certificate);
if(result.startsWith(VpnProfile.INLINE_TAG))
- mTLSAuthFile.setSummary(R.string.inline_file_data);
- else
- mTLSAuthFile.setSummary(result);
+ mTLSAuthFile.setSummary(R.string.inline_file_data);
+ else
+ mTLSAuthFile.setSummary(result);
}
} \ No newline at end of file
diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java
index ea034b55..fcb0679f 100644
--- a/src/de/blinkt/openvpn/VpnProfile.java
+++ b/src/de/blinkt/openvpn/VpnProfile.java
@@ -57,6 +57,14 @@ public class VpnProfile implements Serializable{
public static final int TYPE_USERPASS_PKCS12 = 6;
public static final int TYPE_USERPASS_KEYSTORE = 7;
+ public static final int X509_VERIFY_TLSREMOTE=0;
+ public static final int X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING=1;
+ public static final int X509_VERIFY_TLSREMOTE_DN=2;
+ public static final int X509_VERIFY_TLSREMOTE_RDN=3;
+ public static final int X509_VERIFY_TLSREMOTE_RDN_PREFIX=4;
+
+
+
// Don't change this, not all parts of the program use this constant
public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID";
public static final String INLINE_TAG = "[[INLINE]]";
@@ -119,10 +127,11 @@ public class VpnProfile implements Serializable{
public String mConnectRetry="5";
public boolean mUserEditable=true;
public String mAuth="";
-
+ public int mX509AuthType=X509_VERIFY_TLSREMOTE_RDN;
+
static final String MINIVPN = "miniopenvpn";
-
-
+
+
static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException;
static {
System.loadLibrary("opvpnutil");
@@ -211,16 +220,16 @@ public class VpnProfile implements Serializable{
if(mConnectRetryMax ==null) {
mConnectRetryMax="5";
}
-
+
if(!mConnectRetryMax.equals("-1"))
- cfg+="connect-retry-max " + mConnectRetryMax+ "\n";
-
+ cfg+="connect-retry-max " + mConnectRetryMax+ "\n";
+
if(mConnectRetry==null)
mConnectRetry="5";
-
-
+
+
cfg+="connect-retry " + mConnectRetry + "\n";
-
+
cfg+="resolv-retry 60\n";
@@ -330,7 +339,7 @@ public class VpnProfile implements Serializable{
cfg+="max-routes " + numroutes + "\n";
}
cfg+=routes;
-
+
if(mOverrideDNS || !mUsePull) {
if(nonNull(mDNS1))
cfg+="dhcp-option DNS " + mDNS1 + "\n";
@@ -349,9 +358,29 @@ public class VpnProfile implements Serializable{
// Authentication
if(mCheckRemoteCN) {
if(mRemoteCN == null || mRemoteCN.equals("") )
- cfg+="tls-remote " + mServerName + "\n";
- else
- cfg += "tls-remote " + openVpnEscape(mRemoteCN) + "\n";
+ cfg+="x509-verify-name " + mServerName + " name\n";
+ else
+ switch (mX509AuthType) {
+
+ // 2.2 style x509 checks
+ case X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING:
+ cfg+="compat-names no-remapping\n";
+ case X509_VERIFY_TLSREMOTE:
+ cfg+="tls-remote " + openVpnEscape(mRemoteCN) + "\n";
+ break;
+
+ case X509_VERIFY_TLSREMOTE_RDN:
+ cfg+="x509-verify-name " + openVpnEscape(mRemoteCN) + " name\n";
+ break;
+
+ case X509_VERIFY_TLSREMOTE_RDN_PREFIX:
+ cfg+="x509-verify-name " + openVpnEscape(mRemoteCN) + " name-prefix\n";
+ break;
+
+ case X509_VERIFY_TLSREMOTE_DN:
+ cfg+="x509-verify-name " + openVpnEscape(mRemoteCN) + "\n";
+ break;
+ }
}
if(mExpectTLSCert)
cfg += "remote-cert-tls server\n";
@@ -377,15 +406,15 @@ public class VpnProfile implements Serializable{
cfg+= "# persist-tun also sets persist-remote-ip to avoid DNS resolve problem\n";
cfg+= "persist-remote-ip\n";
}
-
+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean usesystemproxy = prefs.getBoolean("usesystemproxy", true);
if(usesystemproxy) {
cfg+= "# Use system proxy setting\n";
cfg+= "management-query-proxy\n";
}
-
-
+
+
if(mUseCustomConfig) {
cfg += "# Custom configuration options\n";
cfg += "# You are on your on own here :)\n";
@@ -536,17 +565,17 @@ public class VpnProfile implements Serializable{
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));
-
+
for(X509Certificate cert:cachain) {
OpenVPN.logInfo(R.string.cert_from_keystore,cert.getSubjectDN());
}
-
-
-
+
+
+
if(nonNull(mCaFilename)) {
try {
@@ -554,15 +583,15 @@ public class VpnProfile implements Serializable{
X509Certificate[] newcachain = new X509Certificate[cachain.length+1];
for(int i=0;i<cachain.length;i++)
newcachain[i]=cachain[i];
-
+
newcachain[cachain.length-1]=(X509Certificate) cacert;
-
+
} catch (Exception e) {
OpenVPN.logError("Could not read CA certificate" + e.getLocalizedMessage());
}
}
-
+
StringWriter caout = new StringWriter();
@@ -571,9 +600,9 @@ public class VpnProfile implements Serializable{
pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded()));
}
pw.close();
-
-
-
+
+
+
StringWriter certout = new StringWriter();
@@ -606,16 +635,16 @@ public class VpnProfile implements Serializable{
return null;
}
private Certificate getCacertFromFile() throws FileNotFoundException, CertificateException {
- CertificateFactory certFact = CertificateFactory.getInstance("X.509");
-
- InputStream inStream;
-
- if(mCaFilename.startsWith(INLINE_TAG))
- inStream = new ByteArrayInputStream(mCaFilename.replace(INLINE_TAG,"").getBytes());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+
+ InputStream inStream;
+
+ if(mCaFilename.startsWith(INLINE_TAG))
+ inStream = new ByteArrayInputStream(mCaFilename.replace(INLINE_TAG,"").getBytes());
else
inStream = new FileInputStream(mCaFilename);
-
- return certFact.generateCertificate(inStream);
+
+ return certFact.generateCertificate(inStream);
}
@@ -703,7 +732,7 @@ public class VpnProfile implements Serializable{
}
}
-
+
if(data.contains("Proc-Type: 4,ENCRYPTED"))
return true;
else if(data.contains("-----BEGIN ENCRYPTED PRIVATE KEY-----"))
@@ -718,14 +747,14 @@ public class VpnProfile implements Serializable{
if(mTransientPCKS12PW==null)
return R.string.pkcs12_file_encryption_key;
}
-
+
if(mAuthenticationType == TYPE_CERTIFICATES || mAuthenticationType == TYPE_USERPASS_CERTIFICATES) {
if(requireTLSKeyPassword() && !nonNull(mKeyPassword))
if(mTransientPCKS12PW==null) {
return R.string.private_key_password;
}
}
-
+
if(isUserPWAuth() && (mPassword.equals("") || mPassword == null)) {
if(mTransientPW==null)
return R.string.password;
@@ -783,7 +812,7 @@ public class VpnProfile implements Serializable{
byte[] signed_bytes = rsasinger.doFinal(data);
return Base64.encodeToString(signed_bytes, Base64.NO_WRAP);
-
+
} catch (NoSuchAlgorithmException e){
err =e;
} catch (InvalidKeyException e) {
@@ -825,7 +854,7 @@ public class VpnProfile implements Serializable{
byte[] signed_bytes = rsasign(data, pkey);
return Base64.encodeToString(signed_bytes, Base64.NO_WRAP);
-
+
} catch (NoSuchMethodException e) {
err=e;
} catch (IllegalArgumentException e) {
@@ -845,7 +874,7 @@ public class VpnProfile implements Serializable{
}
-
+
}