From b79fd315dd89e7a9f648c6a500b41ce7d9970081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 14 May 2014 20:05:30 +0200 Subject: Copy all java files from ics-openvpn. imports from se.leap.bitmaskclient java files have also been updated. WARNING: compiling errors for de.blinkt.openvpn.R, aidl.de.blinkt.openvpn. --- .../main/java/de/blinkt/openvpn/VpnProfile.java | 942 +++++++++++++++++++++ 1 file changed, 942 insertions(+) create mode 100644 app/src/main/java/de/blinkt/openvpn/VpnProfile.java (limited to 'app/src/main/java/de/blinkt/openvpn/VpnProfile.java') diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java new file mode 100644 index 00000000..601fb2df --- /dev/null +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -0,0 +1,942 @@ +package de.blinkt.openvpn; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.preference.PreferenceManager; +import android.security.KeyChain; +import android.security.KeyChainException; +import android.util.Base64; + +import de.blinkt.openvpn.core.NativeUtils; +import de.blinkt.openvpn.core.VpnStatus; +import de.blinkt.openvpn.core.OpenVpnService; +import de.blinkt.openvpn.core.X509Utils; +import org.spongycastle.util.io.pem.PemObject; +import org.spongycastle.util.io.pem.PemWriter; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Locale; +import java.util.UUID; +import java.util.Vector; + +public class VpnProfile implements Serializable { + // Note that this class cannot be moved to core where it belongs since + // the profile loading depends on it being here + // The Serializable documentation mentions that class name change are possible + // but the how is unclear + // + transient public static final long MAX_EMBED_FILE_SIZE = 2048*1024; // 2048kB + // 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]]"; + public static final String DISPLAYNAME_TAG = "[[NAME]]"; + public static final String MINIVPN = "miniopenvpn"; + private static final long serialVersionUID = 7085688938959334563L; + private static final String OVPNCONFIGFILE = "android.conf"; + public static final int MAXLOGLEVEL = 4; + public static final int CURRENT_PROFILE_VERSION = 2; + public static String DEFAULT_DNS1 = "8.8.8.8"; + public static String DEFAULT_DNS2 = "8.8.4.4"; + + public transient String mTransientPW = null; + public transient String mTransientPCKS12PW = null; + + + public static final int TYPE_CERTIFICATES = 0; + public static final int TYPE_PKCS12 = 1; + public static final int TYPE_KEYSTORE = 2; + public static final int TYPE_USERPASS = 3; + public static final int TYPE_STATICKEYS = 4; + public static final int TYPE_USERPASS_CERTIFICATES = 5; + 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; + // variable named wrong and should haven beeen transient + // but needs to keep wrong name to guarante loading of old + // profiles + public transient boolean profileDleted = false; + public int mAuthenticationType = TYPE_KEYSTORE; + public String mName; + public String mAlias; + public String mClientCertFilename; + public String mTLSAuthDirection = ""; + public String mTLSAuthFilename; + public String mClientKeyFilename; + public String mCaFilename; + public boolean mUseLzo = true; + public String mServerPort = "1194"; + public boolean mUseUdp = true; + public String mPKCS12Filename; + public String mPKCS12Password; + public boolean mUseTLSAuth = false; + public String mServerName = "openvpn.blinkt.de"; + public String mDNS1 = DEFAULT_DNS1; + public String mDNS2 = DEFAULT_DNS2; + public String mIPv4Address; + public String mIPv6Address; + public boolean mOverrideDNS = false; + public String mSearchDomain = "blinkt.de"; + public boolean mUseDefaultRoute = true; + public boolean mUsePull = true; + public String mCustomRoutes; + public boolean mCheckRemoteCN = false; + public boolean mExpectTLSCert = true; + public String mRemoteCN = ""; + public String mPassword = ""; + public String mUsername = ""; + public boolean mRoutenopull = false; + public boolean mUseRandomHostname = false; + public boolean mUseFloat = false; + public boolean mUseCustomConfig = false; + public String mCustomConfigOptions = ""; + public String mVerb = "1"; //ignored + public String mCipher = ""; + public boolean mNobind = false; + public boolean mUseDefaultRoutev6 = true; + public String mCustomRoutesv6 = ""; + public String mKeyPassword = ""; + public boolean mPersistTun = false; + public String mConnectRetryMax = "5"; + public String mConnectRetry = "5"; + public boolean mUserEditable = true; + public String mAuth = ""; + public int mX509AuthType = X509_VERIFY_TLSREMOTE_RDN; + private transient PrivateKey mPrivateKey; + // Public attributes, since I got mad with getter/setter + // set members to default values + private UUID mUuid; + public boolean mAllowLocalLAN; + private int mProfileVersion; + public String mExcludedRoutes; + public String mExcludedRoutesv6; + + public VpnProfile(String name) { + mUuid = UUID.randomUUID(); + mName = name; + mProfileVersion = CURRENT_PROFILE_VERSION; + } + + public static String openVpnEscape(String unescaped) { + if (unescaped == null) + return null; + String escapedString = unescaped.replace("\\", "\\\\"); + escapedString = escapedString.replace("\"", "\\\""); + escapedString = escapedString.replace("\n", "\\n"); + + if (escapedString.equals(unescaped) && !escapedString.contains(" ") && + !escapedString.contains("#") && !escapedString.contains(";")) + return unescaped; + else + return '"' + escapedString + '"'; + } + + public void clearDefaults() { + mServerName = "unknown"; + mUsePull = false; + mUseLzo = false; + mUseDefaultRoute = false; + mUseDefaultRoutev6 = false; + mExpectTLSCert = false; + mPersistTun = false; + mAllowLocalLAN = true; + } + + public UUID getUUID() { + return mUuid; + + } + + public String getName() { + if (mName==null) + return "No profile name"; + return mName; + } + + public void upgradeProfile(){ + if(mProfileVersion< 2) { + /* default to the behaviour the OS used */ + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) + mAllowLocalLAN = true; + else + mAllowLocalLAN = false; + } + + mProfileVersion= CURRENT_PROFILE_VERSION; + } + + public String getConfigFile(Context context, boolean configForOvpn3) { + + File cacheDir = context.getCacheDir(); + String cfg = ""; + + // Enable managment interface + cfg += "# Enables connection to GUI\n"; + cfg += "management "; + + cfg += cacheDir.getAbsolutePath() + "/" + "mgmtsocket"; + cfg += " unix\n"; + cfg += "management-client\n"; + // Not needed, see updated man page in 2.3 + //cfg += "management-signal\n"; + cfg += "management-query-passwords\n"; + cfg += "management-hold\n\n"; + + if (!configForOvpn3) + cfg += String.format("setenv IV_GUI_VER %s \n", openVpnEscape(getVersionEnvString(context))); + + cfg += "machine-readable-output\n"; + + + boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS); + + if (useTLSClient && mUsePull) + cfg += "client\n"; + else if (mUsePull) + cfg += "pull\n"; + else if (useTLSClient) + cfg += "tls-client\n"; + + + //cfg += "verb " + mVerb + "\n"; + cfg += "verb " + MAXLOGLEVEL + "\n"; + + if (mConnectRetryMax == null) { + mConnectRetryMax = "5"; + } + + if (!mConnectRetryMax.equals("-1")) + cfg += "connect-retry-max " + mConnectRetryMax + "\n"; + + if (mConnectRetry == null) + mConnectRetry = "5"; + + + cfg += "connect-retry " + mConnectRetry + "\n"; + + cfg += "resolv-retry 60\n"; + + + // We cannot use anything else than tun + cfg += "dev tun\n"; + + // Server Address + cfg += "remote "; + cfg += mServerName; + cfg += " "; + cfg += mServerPort; + if (mUseUdp) + cfg += " udp\n"; + else + cfg += " tcp-client\n"; + + + switch (mAuthenticationType) { + case VpnProfile.TYPE_USERPASS_CERTIFICATES: + cfg += "auth-user-pass\n"; + case VpnProfile.TYPE_CERTIFICATES: + // Ca + cfg += insertFileData("ca", mCaFilename); + + // Client Cert + Key + cfg += insertFileData("key", mClientKeyFilename); + cfg += insertFileData("cert", mClientCertFilename); + + break; + case VpnProfile.TYPE_USERPASS_PKCS12: + cfg += "auth-user-pass\n"; + case VpnProfile.TYPE_PKCS12: + cfg += insertFileData("pkcs12", mPKCS12Filename); + break; + + case VpnProfile.TYPE_USERPASS_KEYSTORE: + cfg += "auth-user-pass\n"; + case VpnProfile.TYPE_KEYSTORE: + if (!configForOvpn3) { + String[] ks = getKeyStoreCertificates(context); + cfg += "### From Keystore ####\n"; + if (ks != null) { + cfg += "\n" + ks[0] + "\n\n"; + if (ks[1] != null) + cfg += "\n" + ks[1] + "\n\n"; + cfg += "\n" + ks[2] + "\n\n"; + cfg += "management-external-key\n"; + } else { + cfg += context.getString(R.string.keychain_access) + "\n"; + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) + if (!mAlias.matches("^[a-zA-Z0-9]$")) + cfg += context.getString(R.string.jelly_keystore_alphanumeric_bug) + "\n"; + } + } + break; + case VpnProfile.TYPE_USERPASS: + cfg += "auth-user-pass\n"; + cfg += insertFileData("ca", mCaFilename); + } + + if (mUseLzo) { + cfg += "comp-lzo\n"; + } + + if (mUseTLSAuth) { + if (mAuthenticationType == TYPE_STATICKEYS) + cfg += insertFileData("secret", mTLSAuthFilename); + else + cfg += insertFileData("tls-auth", mTLSAuthFilename); + + if (nonNull(mTLSAuthDirection)) { + cfg += "key-direction "; + cfg += mTLSAuthDirection; + cfg += "\n"; + } + + } + + if (!mUsePull) { + if (nonNull(mIPv4Address)) + cfg += "ifconfig " + cidrToIPAndNetmask(mIPv4Address) + "\n"; + + if (nonNull(mIPv6Address)) + cfg += "ifconfig-ipv6 " + mIPv6Address + "\n"; + } + + if (mUsePull && mRoutenopull) + cfg += "route-nopull\n"; + + String routes = ""; + + if (mUseDefaultRoute) + routes += "route 0.0.0.0 0.0.0.0 vpn_gateway\n"; + else + { + for (String route : getCustomRoutes(mCustomRoutes)) { + routes += "route " + route + " vpn_gateway\n"; + } + + for (String route: getCustomRoutes(mExcludedRoutes)) { + routes += "route " + route + " net_gateway\n"; + } + } + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && !mAllowLocalLAN) + cfg+="redirect-private block-local\n"; + else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mAllowLocalLAN) + cfg+="redirect-private unblock-local\n"; + + + if (mUseDefaultRoutev6) + cfg += "route-ipv6 ::/0\n"; + else + for (String route : getCustomRoutesv6(mCustomRoutesv6)) { + routes += "route-ipv6 " + route + "\n"; + } + + cfg += routes; + + if (mOverrideDNS || !mUsePull) { + if (nonNull(mDNS1)) + cfg += "dhcp-option DNS " + mDNS1 + "\n"; + if (nonNull(mDNS2)) + cfg += "dhcp-option DNS " + mDNS2 + "\n"; + if (nonNull(mSearchDomain)) + cfg += "dhcp-option DOMAIN " + mSearchDomain + "\n"; + + } + + if (mNobind) + cfg += "nobind\n"; + + + // Authentication + if (mAuthenticationType != TYPE_STATICKEYS) { + if (mCheckRemoteCN) { + if (mRemoteCN == null || mRemoteCN.equals("")) + cfg += "verify-x509-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 += "verify-x509-name " + openVpnEscape(mRemoteCN) + " name\n"; + break; + + case X509_VERIFY_TLSREMOTE_RDN_PREFIX: + cfg += "verify-x509-name " + openVpnEscape(mRemoteCN) + " name-prefix\n"; + break; + + case X509_VERIFY_TLSREMOTE_DN: + cfg += "verify-x509-name " + openVpnEscape(mRemoteCN) + "\n"; + break; + } + } + if (mExpectTLSCert) + cfg += "remote-cert-tls server\n"; + } + + if (nonNull(mCipher)) { + cfg += "cipher " + mCipher + "\n"; + } + + if (nonNull(mAuth)) { + cfg += "auth " + mAuth + "\n"; + } + + // Obscure Settings dialog + if (mUseRandomHostname) + cfg += "#my favorite options :)\nremote-random-hostname\n"; + + if (mUseFloat) + cfg += "float\n"; + + if (mPersistTun) { + cfg += "persist-tun\n"; + cfg += "# persist-tun also enables pre resolving to avoid DNS resolve problem\n"; + cfg += "preresolve\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"; + cfg += mCustomConfigOptions; + cfg += "\n"; + + } + + + return cfg; + } + + public String getVersionEnvString(Context c) { + String version = "unknown"; + try { + PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); + version = packageinfo.versionName; + } catch (PackageManager.NameNotFoundException e) { + VpnStatus.logException(e); + } + return String.format(Locale.US, "%s %s", c.getPackageName(), version); + + } + + //! Put inline data inline and other data as normal escaped filename + private String insertFileData(String cfgentry, String filedata) { + if (filedata == null) { + // TODO: generate good error + return String.format("%s %s\n", cfgentry, "missing"); + } else if (isEmbedded(filedata)) { + String dataWithOutHeader = getEmbeddedContent(filedata); + return String.format(Locale.ENGLISH, "<%s>\n%s\n\n", cfgentry, dataWithOutHeader, cfgentry); + } else { + return String.format(Locale.ENGLISH, "%s %s\n", cfgentry, openVpnEscape(filedata)); + } + } + + private boolean nonNull(String val) { + if (val == null || val.equals("")) + return false; + else + return true; + } + + private Collection getCustomRoutes(String routes) { + Vector cidrRoutes = new Vector(); + if (routes == null) { + // No routes set, return empty vector + return cidrRoutes; + } + for (String route : routes.split("[\n \t]")) { + if (!route.equals("")) { + String cidrroute = cidrToIPAndNetmask(route); + if (cidrroute == null) + return null; + + cidrRoutes.add(cidrroute); + } + } + + return cidrRoutes; + } + + private Collection getCustomRoutesv6(String routes) { + Vector cidrRoutes = new Vector(); + if (routes == null) { + // No routes set, return empty vector + return cidrRoutes; + } + for (String route : routes.split("[\n \t]")) { + if (!route.equals("")) { + cidrRoutes.add(route); + } + } + + return cidrRoutes; + } + + private String cidrToIPAndNetmask(String route) { + String[] parts = route.split("/"); + + // No /xx, assume /32 as netmask + if (parts.length == 1) + parts = (route + "/32").split("/"); + + if (parts.length != 2) + return null; + int len; + try { + len = Integer.parseInt(parts[1]); + } catch (NumberFormatException ne) { + return null; + } + if (len < 0 || len > 32) + return null; + + + long nm = 0xffffffffl; + nm = (nm << (32 - len)) & 0xffffffffl; + + String netmask = String.format(Locale.ENGLISH, "%d.%d.%d.%d", (nm & 0xff000000) >> 24, (nm & 0xff0000) >> 16, (nm & 0xff00) >> 8, nm & 0xff); + return parts[0] + " " + netmask; + } + + private String[] buildOpenvpnArgv(File cacheDir) { + Vector args = new Vector(); + + // Add fixed paramenters + //args.add("/data/data/de.blinkt.openvpn/lib/openvpn"); + args.add(cacheDir.getAbsolutePath() + "/" + VpnProfile.MINIVPN); + + args.add("--config"); + args.add(cacheDir.getAbsolutePath() + "/" + OVPNCONFIGFILE); + + + return args.toArray(new String[args.size()]); + } + + public Intent prepareIntent(Context context) { + String prefix = context.getPackageName(); + + Intent intent = new Intent(context, OpenVpnService.class); + + if (mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { + if (getKeyStoreCertificates(context) == null) + return null; + } + + intent.putExtra(prefix + ".ARGV", buildOpenvpnArgv(context.getCacheDir())); + intent.putExtra(prefix + ".profileUUID", mUuid.toString()); + + ApplicationInfo info = context.getApplicationInfo(); + intent.putExtra(prefix + ".nativelib", info.nativeLibraryDir); + + try { + FileWriter cfg = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); + cfg.write(getConfigFile(context, false)); + cfg.flush(); + cfg.close(); + } catch (IOException e) { + VpnStatus.logException(e); + } + + return intent; + } + + public String[] getKeyStoreCertificates(Context context) { + return getKeyStoreCertificates(context, 5); + } + + public static String getDisplayName(String embeddedFile) { + int start = DISPLAYNAME_TAG.length(); + int end = embeddedFile.indexOf(INLINE_TAG); + return embeddedFile.substring(start,end); + } + + public static String getEmbeddedContent(String data) + { + if (!data.contains(INLINE_TAG)) + return data; + + int start = data.indexOf(INLINE_TAG) + INLINE_TAG.length(); + return data.substring(start); + } + + public static boolean isEmbedded(String data) { + if (data==null) + return false; + if(data.startsWith(INLINE_TAG) || data.startsWith(DISPLAYNAME_TAG)) + return true; + else + return false; + } + + + class NoCertReturnedException extends Exception { + public NoCertReturnedException (String msg) { + super(msg); + } + } + + synchronized String[] getKeyStoreCertificates(Context context,int tries) { + PrivateKey privateKey = null; + X509Certificate[] cachain; + Exception exp=null; + try { + privateKey = KeyChain.getPrivateKey(context, mAlias); + mPrivateKey = privateKey; + + String keystoreChain = null; + + + cachain = KeyChain.getCertificateChain(context, mAlias); + if(cachain == null) + throw new NoCertReturnedException("No certificate returned from Keystore"); + + if (cachain.length <= 1 && !nonNull(mCaFilename)) { + VpnStatus.logMessage(VpnStatus.LogLevel.ERROR, "", context.getString(R.string.keychain_nocacert)); + } else { + StringWriter ksStringWriter = new StringWriter(); + + PemWriter pw = new PemWriter(ksStringWriter); + for (int i = 1; i < cachain.length; i++) { + X509Certificate cert = cachain[i]; + pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded())); + } + pw.close(); + keystoreChain = ksStringWriter.toString(); + } + + + String caout = null; + if (nonNull(mCaFilename)) { + try { + Certificate cacert = X509Utils.getCertificateFromFile(mCaFilename); + StringWriter caoutWriter = new StringWriter(); + PemWriter pw = new PemWriter(caoutWriter); + + pw.writeObject(new PemObject("CERTIFICATE", cacert.getEncoded())); + pw.close(); + caout= caoutWriter.toString(); + + } catch (Exception e) { + VpnStatus.logError("Could not read CA certificate" + e.getLocalizedMessage()); + } + } + + + StringWriter certout = new StringWriter(); + + + if (cachain.length >= 1) { + X509Certificate usercert = cachain[0]; + + PemWriter upw = new PemWriter(certout); + upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded())); + upw.close(); + + } + String user = certout.toString(); + + + String ca, extra; + if(caout==null) { + ca =keystoreChain; + extra=null; + } else { + ca = caout; + extra=keystoreChain; + } + + return new String[]{ca, extra, user}; + } catch (InterruptedException e) { + exp=e; + } catch (FileNotFoundException e) { + exp=e; + } catch (CertificateException e) { + exp=e; + } catch (IOException e) { + exp=e; + } catch (KeyChainException e) { + exp=e; + } catch (NoCertReturnedException e) { + exp =e; + } catch (IllegalArgumentException e) { + exp =e; + } catch (AssertionError e) { + if (tries ==0) + return null; + VpnStatus.logError(String.format("Failure getting Keystore Keys (%s), retrying",e.getLocalizedMessage())); + try { + Thread.sleep(3000); + } catch (InterruptedException e1) { + VpnStatus.logException(e1); + } + return getKeyStoreCertificates(context, tries-1); + } + if (exp != null) { + exp.printStackTrace(); + VpnStatus.logError(R.string.keyChainAccessError, exp.getLocalizedMessage()); + + VpnStatus.logError(R.string.keychain_access); + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) { + if (!mAlias.matches("^[a-zA-Z0-9]$")) { + VpnStatus.logError(R.string.jelly_keystore_alphanumeric_bug); + } + } + } + return null; + } + + //! Return an error if somethign is wrong + public int checkProfile(Context context) { + if (mAuthenticationType == TYPE_KEYSTORE || mAuthenticationType == TYPE_USERPASS_KEYSTORE) { + if (mAlias == null) + return R.string.no_keystore_cert_selected; + } + + if (!mUsePull || mAuthenticationType == TYPE_STATICKEYS) { + if (mIPv4Address == null || cidrToIPAndNetmask(mIPv4Address) == null) + return R.string.ipv4_format_error; + } + if (!mUseDefaultRoute && (getCustomRoutes(mCustomRoutes) == null || getCustomRoutes(mExcludedRoutes) ==null)) + return R.string.custom_route_format_error; + + // Everything okay + return R.string.no_error_found; + + } + + //! Openvpn asks for a "Private Key", this should be pkcs12 key + // + public String getPasswordPrivateKey() { + if (mTransientPCKS12PW != null) { + String pwcopy = mTransientPCKS12PW; + mTransientPCKS12PW = null; + return pwcopy; + } + switch (mAuthenticationType) { + case TYPE_PKCS12: + case TYPE_USERPASS_PKCS12: + return mPKCS12Password; + + case TYPE_CERTIFICATES: + case TYPE_USERPASS_CERTIFICATES: + return mKeyPassword; + + case TYPE_USERPASS: + case TYPE_STATICKEYS: + default: + return null; + } + } + + public boolean isUserPWAuth() { + switch (mAuthenticationType) { + case TYPE_USERPASS: + case TYPE_USERPASS_CERTIFICATES: + case TYPE_USERPASS_KEYSTORE: + case TYPE_USERPASS_PKCS12: + return true; + default: + return false; + + } + } + + public boolean requireTLSKeyPassword() { + if (!nonNull(mClientKeyFilename)) + return false; + + String data = ""; + if (isEmbedded(mClientKeyFilename)) + data = mClientKeyFilename; + else { + char[] buf = new char[2048]; + FileReader fr; + try { + fr = new FileReader(mClientKeyFilename); + int len = fr.read(buf); + while (len > 0) { + data += new String(buf, 0, len); + len = fr.read(buf); + } + fr.close(); + } catch (FileNotFoundException e) { + return false; + } catch (IOException e) { + return false; + } + + } + + if (data.contains("Proc-Type: 4,ENCRYPTED")) + return true; + else if (data.contains("-----BEGIN ENCRYPTED PRIVATE KEY-----")) + return true; + else + return false; + } + + public int needUserPWInput() { + if ((mAuthenticationType == TYPE_PKCS12 || mAuthenticationType == TYPE_USERPASS_PKCS12) && + (mPKCS12Password == null || mPKCS12Password.equals(""))) { + 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() && !(nonNull(mUsername) && (nonNull(mPassword) || mTransientPW != null))) { + return R.string.password; + } + return 0; + } + + public String getPasswordAuth() { + if (mTransientPW != null) { + String pwcopy = mTransientPW; + mTransientPW = null; + return pwcopy; + } else { + return mPassword; + } + } + + // Used by the Array Adapter + @Override + public String toString() { + return mName; + } + + public String getUUIDString() { + return mUuid.toString(); + } + + public PrivateKey getKeystoreKey() { + return mPrivateKey; + } + + public String getSignedData(String b64data) { + PrivateKey privkey = getKeystoreKey(); + Exception err; + + byte[] data = Base64.decode(b64data, Base64.DEFAULT); + + // The Jelly Bean *evil* Hack + // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) { + return processSignJellyBeans(privkey, data); + } + + + try { + + + Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); + + rsasinger.init(Cipher.ENCRYPT_MODE, privkey); + + byte[] signed_bytes = rsasinger.doFinal(data); + return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + + } 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; + } + + VpnStatus.logError(R.string.error_rsa_sign, err.getClass().toString(), err.getLocalizedMessage()); + + return null; + + } + + private String processSignJellyBeans(PrivateKey privkey, byte[] data) { + Exception err; + try { + Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); + getKey.setAccessible(true); + + // Real object type is OpenSSLKey + Object opensslkey = getKey.invoke(privkey); + + getKey.setAccessible(false); + + Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); + + // integer pointer to EVP_pkey + getPkeyContext.setAccessible(true); + int pkey = (Integer) getPkeyContext.invoke(opensslkey); + getPkeyContext.setAccessible(false); + + // 112 with TLS 1.2 (172 back with 4.3), 36 with TLS 1.0 + byte[] signed_bytes = NativeUtils.rsasign(data, pkey); + return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + + } catch (NoSuchMethodException e) { + err = e; + } catch (IllegalArgumentException e) { + err = e; + } catch (IllegalAccessException e) { + err = e; + } catch (InvocationTargetException e) { + err = e; + } catch (InvalidKeyException e) { + err = e; + } + VpnStatus.logError(R.string.error_rsa_sign, err.getClass().toString(), err.getLocalizedMessage()); + + return null; + + } + + +} + + + + -- cgit v1.2.3 From a7f8db4fdb308f2fcd1cc1c5013ac930cc063ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 19 May 2014 16:51:48 +0200 Subject: bitmaskclient.R in de.blinkt.openvpn top level --- app/src/main/java/de/blinkt/openvpn/VpnProfile.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/src/main/java/de/blinkt/openvpn/VpnProfile.java') diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index 601fb2df..afa70100 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -1,5 +1,7 @@ package de.blinkt.openvpn; +import se.leap.bitmaskclient.R; + import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -- cgit v1.2.3 From 6fcd101fcbc7779ffd7239cc35e5c3359ae38fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 28 May 2014 17:15:44 +0200 Subject: Resources merge correctly. --- app/src/main/java/de/blinkt/openvpn/VpnProfile.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/src/main/java/de/blinkt/openvpn/VpnProfile.java') diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index afa70100..000fc47c 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -2,6 +2,8 @@ package de.blinkt.openvpn; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.R; + import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -- cgit v1.2.3 From e50339824809da28beabfaf9ecea7414c131cbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 29 May 2014 20:19:24 +0200 Subject: ics-openvpn receives ifconfig from the server. Refactored AndroidManifest to include launchvpn and openvpnservice. Imported changes from ics-openvpn-upstream --- app/src/main/java/de/blinkt/openvpn/VpnProfile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/de/blinkt/openvpn/VpnProfile.java') diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index 000fc47c..da0298f2 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -727,8 +727,8 @@ public class VpnProfile implements Serializable { //! Return an error if somethign is wrong public int checkProfile(Context context) { if (mAuthenticationType == TYPE_KEYSTORE || mAuthenticationType == TYPE_USERPASS_KEYSTORE) { - if (mAlias == null) - return R.string.no_keystore_cert_selected; + // if (mAlias == null) + // return R.string.no_keystore_cert_selected; } if (!mUsePull || mAuthenticationType == TYPE_STATICKEYS) { -- cgit v1.2.3 From ac69881af1b7bfcdd185989f3e434556b1d62fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 10 Jun 2014 11:19:48 +0200 Subject: Grabs eip authentication data correctly. Merged updated ics-openvpn-upstream (e7803cc8efcd1794e18b4e30a43d814c2834552d). --- .../main/java/de/blinkt/openvpn/VpnProfile.java | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'app/src/main/java/de/blinkt/openvpn/VpnProfile.java') diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index da0298f2..93d0d386 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -4,6 +4,10 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.Dashboard; +import se.leap.bitmaskclient.EIP; +import se.leap.bitmaskclient.Provider; + import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -81,7 +85,7 @@ public class VpnProfile implements Serializable { // but needs to keep wrong name to guarante loading of old // profiles public transient boolean profileDleted = false; - public int mAuthenticationType = TYPE_KEYSTORE; + public int mAuthenticationType = TYPE_CERTIFICATES; public String mName; public String mAlias; public String mClientCertFilename; @@ -256,17 +260,22 @@ public class VpnProfile implements Serializable { cfg += " tcp-client\n"; + android.util.Log.d("vpnprofile", Integer.toString(mAuthenticationType)); switch (mAuthenticationType) { case VpnProfile.TYPE_USERPASS_CERTIFICATES: cfg += "auth-user-pass\n"; case VpnProfile.TYPE_CERTIFICATES: // Ca - cfg += insertFileData("ca", mCaFilename); - - // Client Cert + Key - cfg += insertFileData("key", mClientKeyFilename); - cfg += insertFileData("cert", mClientCertFilename); - + // cfg += insertFileData("ca", mCaFilename); + + // // Client Cert + Key + // cfg += insertFileData("key", mClientKeyFilename); + // cfg += insertFileData("cert", mClientCertFilename); + // FIXME This is all we need...The whole switch statement can go... + SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE); + cfg+="\n"+preferences.getString(Provider.CA_CERT, "")+"\n\n"; + cfg+="\n"+preferences.getString(EIP.PRIVATE_KEY, "")+"\n\n"; + cfg+="\n"+preferences.getString(EIP.CERTIFICATE, "")+"\n\n"; break; case VpnProfile.TYPE_USERPASS_PKCS12: cfg += "auth-user-pass\n"; @@ -557,8 +566,8 @@ public class VpnProfile implements Serializable { Intent intent = new Intent(context, OpenVpnService.class); if (mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - if (getKeyStoreCertificates(context) == null) - return null; + // if (getKeyStoreCertificates(context) == null) + // return null; } intent.putExtra(prefix + ".ARGV", buildOpenvpnArgv(context.getCacheDir())); -- cgit v1.2.3