platform/android/Rhodes/src/com/rhomobile/rhodes/socket/SSLImpl.java in rhodes-7.1.17 vs platform/android/Rhodes/src/com/rhomobile/rhodes/socket/SSLImpl.java in rhodes-7.4.1
- old
+ new
@@ -38,14 +38,17 @@
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
+import java.security.PrivateKey;
+import java.security.KeyStore.PasswordProtection;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.UnrecoverableEntryException;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@@ -54,19 +57,25 @@
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import android.net.http.X509TrustManagerExtensions;
+import android.os.Build;
import android.util.Base64;
import com.rhomobile.rhodes.Logger;
import com.rhomobile.rhodes.RhoConf;
import com.rhomobile.rhodes.file.RhoFileApi;
import java.util.StringTokenizer;
import java.security.SecureRandom;
+import android.os.Looper;
+import com.rhomobile.rhodes.RhodesService;
+import org.conscrypt.BaseOpenSSLSocketAdapterFactory;
+import org.conscrypt.Conscrypt;
+import org.conscrypt.OpenSSLProvider;
public class SSLImpl {
private static final String TAG = "SSLImplJava";
@@ -80,11 +89,16 @@
//Used from jni
@SuppressWarnings("unused")
private int sockfd;
private InputStream is;
- private OutputStream os;
+ private OutputStream os;
+
+ private static Certificate local_server_cert = null;
+ private static PrivateKey client_private_key = null;
+ private static Certificate[] client_cert_chain = null;
+
public native RhoSockAddr getRemoteSockAddr(int sockfd);
private static class MyTrustManager implements X509TrustManager {
@@ -296,15 +310,121 @@
Logger.I(TAG, "SSL certificates loaded: " + String.valueOf(certs.size()) );
return certs;
}
-
+
+ private static Certificate loadLocalServerCert(byte[] data)
+ {
+ InputStream certStream = new ByteArrayInputStream(data);
+ Certificate cert = null;
+
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ cert = cf.generateCertificate(certStream);
+ certStream.close();
+ }
+ catch(Exception e)
+ {
+ Logger.E(TAG, e.getMessage());
+ }
+
+ return cert;
+ }
+
+ public static PrivateKey getClientPrivateKey()
+ {
+ return client_private_key;
+ }
+
+ public static Certificate[] getClientCertChain()
+ {
+ return client_cert_chain;
+ }
+
+ private static void loadLocalCientP12Bundle(byte[] data, String pwd)
+ {
+ if (client_private_key == null && client_cert_chain == null) {
+ try {
+ KeyStore clientKeystore = KeyStore.getInstance("pkcs12");
+ InputStream p12Stream = new ByteArrayInputStream(data);
+ clientKeystore.load(p12Stream, pwd.toCharArray());
+
+ KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection(pwd.toCharArray());
+ KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) clientKeystore.getEntry("taup12", protParam);
+ client_private_key = pkEntry.getPrivateKey();
+ client_cert_chain = pkEntry.getCertificateChain();
+
+ p12Stream.close();
+ }
+ catch (Exception e)
+ {
+ Logger.I(TAG, e.getMessage());
+ client_private_key = null;
+ client_cert_chain = null;
+ }
+
+ }
+ }
+
+ public static SSLSocketFactory getSecureClientFactory() throws NoSuchAlgorithmException, KeyManagementException, CertificateException, KeyStoreException, IOException, UnrecoverableKeyException
+ {
+ SSLContext context = SSLContext.getInstance("TLS");
+
+ Logger.I(TAG, "Creating TrustManager for system certificates");
+ TrustManagerFactory systemTmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ systemTmf.init((KeyStore)null);
+ X509TrustManager systemTrustManager = (X509TrustManager)systemTmf.getTrustManagers()[0];
+
+ KeyStore keystore = KeyStore.getInstance( KeyStore.getDefaultType() );
+ keystore.load(null);
+
+ if(local_server_cert != null)
+ {
+ keystore.setCertificateEntry("cert-alias-local", local_server_cert);
+ }
+
+ Logger.I(TAG, "Creating TrustManager for custom certificates");
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(keystore);
+ X509TrustManager customTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
+
+ KeyManagerFactory kmf = null;
+ KeyStore clientKeystore = null;
+
+ if(client_private_key != null && client_cert_chain != null)
+ {
+ if (clientKeystore == null)
+ {
+ clientKeystore = KeyStore.getInstance("pkcs12");
+ clientKeystore.load(null);
+ }
+
+ KeyStore.PrivateKeyEntry pkEntry = new KeyStore.PrivateKeyEntry(client_private_key, client_cert_chain);
+ clientKeystore.setEntry("taup12", pkEntry, null);
+ }
+
+ if (clientKeystore != null) {
+ kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientKeystore, null);
+ }
+
+ context.init(
+ (kmf==null)?null:kmf.getKeyManagers(),
+ new TrustManager[] { new MySecureTrustManager( systemTrustManager, customTrustManager ) },
+ new SecureRandom()
+ );
+
+ Logger.I(TAG, "Secure SSL factory initialization completed");
+
+ return (SSLSocketFactory)context.getSocketFactory();
+ }
+
private static SSLSocketFactory getSecureFactory() throws NoSuchAlgorithmException, KeyManagementException, CertificateException, KeyStoreException, IOException, UnrecoverableKeyException {
Logger.I(TAG, "Creating secure SSL factory");
- SSLContext context = SSLContext.getInstance("TLS");
+ SSLContext context = Build.VERSION.SDK_INT >= 30 ? SSLContext.getInstance("TLS", new OpenSSLProvider()) : SSLContext.getInstance("TLS");
// First, load all system installed certificates
Logger.I(TAG, "Creating TrustManager for system certificates");
TrustManagerFactory systemTmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
systemTmf.init((KeyStore)null);
@@ -321,38 +441,58 @@
for ( int i = 0; i < certs.size(); ++i ) {
keystore.setCertificateEntry("cert-alias"+ String.valueOf(i),certs.get(i));
}
}
+ if(local_server_cert != null)
+ {
+ keystore.setCertificateEntry("cert-alias-local", local_server_cert);
+ }
Logger.I(TAG, "Creating TrustManager for custom certificates");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
X509TrustManager customTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
KeyManagerFactory kmf = null;
-
+ KeyStore clientKeystore = null;
+
if ( RhoConf.isExist("clientSSLCertificate")) {
String clientCertPath = RhoConf.getString("clientSSLCertificate");
Logger.I(TAG, "clientSSLCertificate is " + clientCertPath );
-
if ( clientCertPath.length() > 0 ) {
Logger.I(TAG, "Creating KeyManager for client certificates");
kmf = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );
String password = "";
if (RhoConf.isExist("clientSSLCertificatePassword")) {
password = RhoConf.getString("clientSSLCertificatePassword");
}
-
- KeyStore clientKeystore = KeyStore.getInstance( "pkcs12" );
- clientKeystore.load( RhoFileApi.open(clientCertPath), password.toCharArray() );
- kmf.init(clientKeystore, password.toCharArray());
+
+ clientKeystore = KeyStore.getInstance("pkcs12");
+ clientKeystore.load(RhoFileApi.open(clientCertPath), password.toCharArray() );
}
}
+
+ if(client_private_key != null && client_cert_chain != null)
+ {
+ if (clientKeystore == null)
+ {
+ clientKeystore = KeyStore.getInstance("pkcs12");
+ clientKeystore.load(null);
+ }
+
+ KeyStore.PrivateKeyEntry pkEntry = new KeyStore.PrivateKeyEntry(client_private_key, client_cert_chain);
+ clientKeystore.setEntry("taup12", pkEntry, null);
+ }
+
+ if (clientKeystore != null) {
+ kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientKeystore, null);
+ }
/*
* this really works only with first provided TrustManager,
* so we make our own wrapper which encapsulates both system installed and custom provided certificates
*/
@@ -366,20 +506,24 @@
return (SSLSocketFactory)context.getSocketFactory();
}
- private static SSLSocketFactory getFactory(boolean verify) throws NoSuchAlgorithmException, KeyManagementException, CertificateException, KeyStoreException, IOException, UnrecoverableKeyException {
- if (verify) {
+ public static SSLSocketFactory getFactory(boolean verify) throws NoSuchAlgorithmException, KeyManagementException, CertificateException, KeyStoreException, IOException, UnrecoverableKeyException {
+
+ if (Build.VERSION.SDK_INT >= 30)
+ Conscrypt.setUseEngineSocketByDefault(false);
+
+ if (verify) {
//if ( secureFactory == null ) {
secureFactory = getSecureFactory();
//}
return secureFactory;
}
if (factory == null) {
- SSLContext context = SSLContext.getInstance("TLS");
+ SSLContext context = Build.VERSION.SDK_INT >= 30 ? SSLContext.getInstance("TLS", new OpenSSLProvider()) : SSLContext.getInstance("TLS");
TrustManager[] managers = {new MyTrustManager()};
context.init(null, managers, new SecureRandom());
factory = context.getSocketFactory();
}
return factory;
@@ -396,10 +540,95 @@
reportFail("connect", e);
e.printStackTrace();
return false;
}
}
+
+ public static void setRawCertificate(byte[] data)
+ {
+ local_server_cert = loadLocalServerCert(data);
+ }
+
+
+ public static void setP12(byte[] data, String p)
+ {
+ loadLocalCientP12Bundle(data, p);
+ }
+
+ private class SSLThreadIn extends Thread
+ {
+ private int n = 0;
+ private InputStream is = null;
+ private byte[] data = null;
+ private int size = 0;
+
+ public SSLThreadIn(InputStream i, byte[] d, int s)
+ {
+ this.is = i;
+ size = s;
+ data = d;
+ }
+
+ public void run() {
+ if(is != null)
+ {
+ try {
+ n = is.read(data, 0, size);
+ } catch (IOException e) {
+
+ }
+ }
+ }
+
+ public int getReadenBytes()
+ {
+ return n;
+ }
+
+ }
+
+ private class SSLThreadShutdown extends Thread
+ {
+ private SSLSocket sock;
+
+ public SSLThreadShutdown(SSLSocket s)
+ {
+ sock = s;
+ }
+
+ public void run() {
+ try {
+ sock.close();
+ } catch (IOException e) {
+
+ }
+ }
+ }
+
+ private class SSLThreadOut extends Thread
+ {
+ private OutputStream os = null;
+ private byte[] data = null;
+
+ public SSLThreadOut(OutputStream o, byte[] d)
+ {
+ this.os = o;
+ data = d;
+ }
+
+ public void run() {
+ if(os != null)
+ {
+ try {
+ os.write(data);
+ } catch (IOException e) {
+
+ }
+ }
+ }
+
+ }
public boolean connect(int fd, boolean sslVerifyPeer, String hostname ) {
try {
Logger.I(TAG, "SSL connect to " + hostname);
@@ -431,11 +660,18 @@
public void shutdown() {
try {
if (sock != null) {
synchronized (this) {
if (sock != null) {
- sock.close();
+
+ if (RhodesService.isLocalHttpsServerEnable() && Looper.myLooper() == Looper.getMainLooper()) {
+ SSLThreadShutdown shutdownThread = new SSLThreadShutdown(sock);
+ shutdownThread.start();
+ shutdownThread.join();
+ } else
+ sock.close();
+
sock = null;
os = null;
is = null;
//TODO: check file descriptor is closed gracefully
@@ -456,11 +692,18 @@
synchronized (this) {
if (os != null)
aOs = os;
}
if (aOs != null) {
- aOs.write(data);
+
+ if (RhodesService.isLocalHttpsServerEnable() && Looper.myLooper() == Looper.getMainLooper()) {
+ SSLThreadOut ssl_out = new SSLThreadOut(os, data);
+ ssl_out.start();
+ ssl_out.join();
+ } else
+ aOs.write(data);
+
return true;
}
}
}
catch (Exception e) {
@@ -477,11 +720,20 @@
if (is != null)
aIs = is;
}
if (aIs != null) {
int size = data.length;
- int n = is.read(data, 0, size);
+ int n = 0;
+
+ if (RhodesService.isLocalHttpsServerEnable() && Looper.myLooper() == Looper.getMainLooper()) {
+ SSLThreadIn ssl_in = new SSLThreadIn(is, data, size);
+ ssl_in.start();
+ ssl_in.join();
+ n = ssl_in.getReadenBytes();
+ } else
+ n = is.read(data, 0, size);
+
return n;
}
}
}
catch (Exception e) {
@@ -490,6 +742,6 @@
return -1;
}
-}
+}
\ No newline at end of file