Programmatically add a certificate authority while keeping Android system SSL certificates - java

There are lots of questions about this topic on StackOverflow, but I do not seem to find one related to my problem.
I have an Android application that needs to communicate with HTTPS servers: some signed with a CA registered in the Android system keystore (common HTTPS websites), and some signed with a CA I own but not in the Android system keystore (a server with an autosigned certificate for instance).
I know how to add my CA programmatically and force every HTTPS connection to use it. I use the following code:
public class SslCertificateAuthority {
public static void addCertificateAuthority(InputStream inputStream) {
try {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(inputStream);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
However, doing that disables the use of the Android system keystore, and I cannot query HTTPS sites signed with other CA any more.
I tried to add my CA in the Android keystore, using:
KeyStore.getInstance("AndroidCAStore")
... but I cannot then add my CA in it (an exception is launched).
I could use the instance method HttpsURLConnection.setSSLSocketFactory(...) instead of the static global HttpsURLConnection.setDefaultSSLSocketFactory(...) to tell on a case by case basis when my CA has to be used.
But it isn't practical at all, all the more since sometimes I cannot pass a preconfigured HttpsURLConnection object to some libraries.
Some ideas about how I could do that?
EDIT - ANSWER
Ok, following the given advice, here is my working code. It might need some enhancements, but it seems to work as a starting point.
public class SslCertificateAuthority {
private static class UnifiedTrustManager implements X509TrustManager {
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public UnifiedTrustManager(KeyStore localKeyStore) throws KeyStoreException {
try {
this.defaultTrustManager = createTrustManager(null);
this.localTrustManager = createTrustManager(localKeyStore);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
private X509TrustManager createTrustManager(KeyStore store) throws NoSuchAlgorithmException, KeyStoreException {
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init((KeyStore) store);
TrustManager[] trustManagers = tmf.getTrustManagers();
return (X509TrustManager) trustManagers[0];
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkClientTrusted(chain, authType);
}
}
#Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] first = defaultTrustManager.getAcceptedIssuers();
X509Certificate[] second = localTrustManager.getAcceptedIssuers();
X509Certificate[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
}
public static void setCustomCertificateAuthority(InputStream inputStream) {
try {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(inputStream);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore and system CA
UnifiedTrustManager trustManager = new UnifiedTrustManager(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[]{trustManager}, null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

It is an old question, but I met the same problem, so probably it is worth posting my answer. You tried to add your certificate to KeyStore.getInstance("AndroidCAStore"), but got an exception. Actually you should have done the opposite - add entries from that keystore to the one you created.
My code is a bit different from yours, I just post it for the sake of complete answer even though only middle part matters.
KeyStore keyStore=KeyStore.getInstance("BKS");
InputStream in=activity.getResources().openRawResource(R.raw.my_ca);
try
{
keyStore.load(in,"PASSWORD_HERE".toCharArray());
}
finally
{
in.close();
}
KeyStore defaultCAs=KeyStore.getInstance("AndroidCAStore");
if(defaultCAs!=null)
{
defaultCAs.load(null,null);
Enumeration<String> keyAliases=defaultCAs.aliases();
while(keyAliases.hasMoreElements())
{
String alias=keyAliases.nextElement();
Certificate cert=defaultCAs.getCertificate(alias);
try
{
if(!keyStore.containsAlias(alias))
keyStore.setCertificateEntry(alias,cert);
}
catch(Exception e)
{
System.out.println("Error adding "+e);
}
}
}
TrustManagerFactory tmf=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
// Get a new SSL context
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(null,tmf.getTrustManagers(),new java.security.SecureRandom());
return ctx.getSocketFactory();

This might be too late but this is a tried and tested approach that helps bypass the certificate check done by Java.
I cannot claim credit for this code, it was written by one of my colleagues :) . It can be used during development to test your code. In case you don't want to deal with certificates at all, you can make Java always certificates from any host for your HttpURLConnection object. Which seems to be exactly what you're trying to do here.
Here's a class that should help you do that :
import javax.net.ssl.*;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/***
* Should only be used in development, this class will allow connections to an HTTPS server with unverified certificates.
* obviously this should not be used in the real world
*/
public class TrustModifier {
private static final TrustingHostnameVerifier TRUSTING_HOSTNAME_VERIFIER = new TrustingHostnameVerifier();
private static SSLSocketFactory factory;
/**
* Call this with any HttpURLConnection, and it will modify the trust settings if it is an HTTPS connection.
*
* #param conn the {#link HttpURLConnection} instance
* #throws KeyManagementException if an error occurs while initializing the context object for the TLS protocol
* #throws NoSuchAlgorithmException if no Provider supports a TrustManagerFactorySpi implementation for the TLS protocol.
*/
public static void relaxHostChecking(HttpURLConnection conn) throws KeyManagementException, NoSuchAlgorithmException {
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection httpsConnection = (HttpsURLConnection) conn;
SSLSocketFactory factory = prepFactory();
httpsConnection.setSSLSocketFactory(factory);
httpsConnection.setHostnameVerifier(TRUSTING_HOSTNAME_VERIFIER);
}
}
/**
* Returns an {#link SSLSocketFactory} instance for the protocol being passed, this represents a secure communication context
*
* #return a {#link SSLSocketFactory} object for the TLS protocol
* #throws NoSuchAlgorithmException if no Provider supports a TrustManagerFactorySpi implementation for the specified protocol.
* #throws KeyManagementException if an error occurs while initializing the context object
*/
static synchronized SSLSocketFactory prepFactory() throws NoSuchAlgorithmException, KeyManagementException {
if (factory == null) {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{new AlwaysTrustManager()}, null);
factory = ctx.getSocketFactory();
}
return factory;
}
private static final class TrustingHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private static class AlwaysTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}
All you need to do is call the function relaxHostChecking() like this :
if (conn instanceof HttpsURLConnection) {
TrustModifier.relaxHostChecking(conn);
}
This will result in java trusting whichever host you're trying to connect to using HttpURLConnection.

Related

Sending HTTPS Post Request in Android/Java

since
sslSocketFactory(javax.net.ssl.SSLSocketFactory)' is deprecated, what should I use instead? Thanks in regards... Deprecated. SSLSocketFactory does not expose its X509TrustManager, which is a field that OkHttp needs to build a clean certificate chain. This method instead must use reflection to extract the trust manager. Applications should prefer to call sslSocketFactory(SSLSocketFactory, X509TrustManager), which avoids such reflection.
Sets the socket factory used to secure HTTPS connections. If unset, the system default will be used.
try {
client = new OkHttpClient().newBuilder()
.sslSocketFactory(trustCert().getSocketFactory())
.build();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = new FormBody.Builder()
.build();
Request request = new Request.Builder()
.url("https://example.com")
.method("GET", null)
.addHeader("auth-token", token)
.addHeader("Authorization", "Bearer"+" "+token)
.build();
Response response = null;
try {
response = client.newCall(request).execute();
odgovor = response.body().string();
System.out.println(odgovor);
} catch (IOException e) {
e.printStackTrace();
}
private SSLContext trustCert() throws CertificateException,IOException, KeyStoreException,
NoSuchAlgorithmException, KeyManagementException {
AssetManager assetManager = getAssets();
InputStream is = getApplicationContext().getResources().openRawResource(R.raw.gdig2);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca = cf.generateCertificate(is);
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
return context;
}
Use, #sslSocketFactory(SSLSocketFactory, X509TrustManager)
client = new okHttpClient().newBuilder().sslSocketFactory(trustCert().getSocketFactory(), (X509TrustManager) tmf.trustManagers.get(0));

Is there a way to configurate a SSL certificate in Azure Kubernetes Service using WebFlux without use a Java keyStore?

I have a microservice deploy in AKS plataform and this microservice has to connect an external API that uses a SSL certificates. My doubt if there's a way to configurates the SSL certificate without use a java Keystore, my project is develop in Java language using Spring boot with WebFlux.
I found a example that how can use a jks file and Webflux but not working.
I uses the next code to generates a SslContext:
public SslContext getSslContext(){
SslContext sslContext;
try {
KeyStore ks = KeyStore.getInstance("JKS");
try (InputStream is = getClass().getResourceAsStream("/my-
truststore.jks"))
{
ks.load(is, "truststore-password".toCharArray());
}
X509Certificate[] trusted =
Collections.list(ks.aliases()).stream().map(alias -> {
try {
return (X509Certificate) ks.getCertificate(alias);
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}
}).toArray(X509Certificate[]::new);
sslContext = SslContextBuilder.forClient().trustManager(trusted).build();
} catch (GeneralSecurityException | IOException e) {
throw new RuntimeException(e);
}
}
And I uses the next to generate a WebClient:
public WebClient getSslWebClient (){
try {
sslContext = getSslContext();
} catch (Exception e) {
e.printStackTrace();
}
SslContext finalSslContext = sslContext;
TcpClient tcpClient = TcpClient.create().secure(sslContextSpec ->
sslContextSpec.sslContext(finalSslContext));
HttpClient httpClient = HttpClient.from(tcpClient);
ClientHttpConnector httpConnector = new
ReactorClientHttpConnector(httpClient);
return WebClient.builder().clientConnector(httpConnector).build();
}
I appreciate your support in advance.
Regards.
Well, after days of research, I found a way to use a certificate without using the Java KeyStore (JKS). For this, I need the certificate in PEM format, then copy this certificate as a property in the parameter file and then invoke it directly:
public class SslConfig {
#Value("${ocp.http-client.certificate}")
private String certificate;
private final static String certificateType = "X.509";
private final static String alias = "root";
private static SslContext sslContext;
public WebClient getSslWebClient (){
try {
sslContext = getSslContext();
} catch (Exception e) {
e.printStackTrace();
}
SslContext finalSslContext = sslContext;
TcpClient tcpClient = TcpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(finalSslContext));
HttpClient httpClient = HttpClient.from(tcpClient);
ClientHttpConnector httpConnector = new ReactorClientHttpConnector(httpClient);
return WebClient.builder().clientConnector(httpConnector).build();
}
//Se configura el contexto sobre el cual se trabajara la comunicacion SSL
public SslContext getSslContext(){
try {
ByteArrayInputStream is = new ByteArrayInputStream(certificate.getBytes());
final KeyStore keyStore = readKeyStore(is);
X509Certificate[] trusted = Collections.list(keyStore.aliases()).stream().map(alias -> {
try {
return (X509Certificate) keyStore.getCertificate(alias);
} catch (KeyStoreException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
}
}).toArray(X509Certificate[]::new);
sslContext = SslContextBuilder.forClient().trustManager(trusted).build();
}catch (GeneralSecurityException | SSLException e ){
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
}
return sslContext;
}
private static KeyStore readKeyStore(InputStream is) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
CertificateFactory cf = CertificateFactory.getInstance(certificateType);
Certificate cert = null;
while (is.available() > 0) {
cert = cf.generateCertificate(is);
}
ks.setCertificateEntry(alias, cert);
return ks;
}
}
After this, I can make a request and get the response what I need.

AWS MQTT Websocket issue

I am trying use AWS connection keys in Android for connection with Device using MQTT websocket but did not find a solution yet, please help me on that. If any one provide MQTT over SSL/TLS with 3 certificate AWS (ca,cert,private) android code.
final MqttAndroidClient mqttAndroidClient = new MqttAndroidClient(MainActivity.this, "ssl://" + pref.getMqttUrl(), clientId, persistence);
try {
String clientId = MqttClient.generateClientId();
MqttConnectOptions connectionOptions = new MqttConnectOptions();
connectionOptions.setCleanSession(true);
Log.e("Test", "ssl://" + pref.getMqttUrl());
try {
InputStream trustStoresIs = context.getResources().openRawResource(R.raw.ca_key);
String trustStoreType = KeyStore.getDefaultType();
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
trustStore.load(trustStoresIs, context.getString(R.string.bks_password).toCharArray());
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(trustStore);
InputStream keyStoreStream = context.getResources().openRawResource(R.raw.user_cer_key);
KeyStore keyStore = null;
keyStore = KeyStore.getInstance("BKS");
keyStore.load(keyStoreStream, context.getString(R.string.bks_password).toCharArray());
KeyManagerFactory keyManagerFactory = null;
keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, context.getString(R.string.bks_password).toCharArray());
SSLContext context = SSLContext.getInstance("SSL");
context.init(keyManagerFactory.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) context.getSocketFactory();
connectionOptions.setSocketFactory(sslsocketfactory);
} catch (KeyManagementException | CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mqttAndroidClient.connect(connectionOptions, null, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.e("Mqtt","Connection Success!");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e("Mqtt","Connection Failure!");
}
});
mqttAndroidClient.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable cause) {
Log.e("Mqtt","Connection was lost!");
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("mqtt Delivery Complete!");
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
Got error like
Mqttjavax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Thanks.
The error implies your truststore doesn't have either the right or the full certificate chain for to authenticate the server.
The following line bothers me:
InputStream trustStoresIs =
context.getResources().openRawResource(R.raw.ca_key);
It implys you are loading a key not a certificate for your CA chain. Also CA chains tend to have more than one layer (Primary CA cert signs Intermediate CA cert) so I would expect you to need to add more than one cert to the trust store.

Handshake failed Android 23

I've got a problem with Keystores in Android.
I'm trying to connect a client in android to a server in java. My code is working well with API from 15 to 22 of android, but not with the new API 23 update:
i've got the error on the android client:
javax.net.ssl.SSLHandshakeException: Handshake failed
and this error on the server:
javax.net.ssl.SSLHandshakeException: no cipher suites in common
Here's my code, that was working well with API 22 or before:
in client, R.raw.publickey is the public .bks certificate, and R.raw.publickey_v1 is the older version of .bks for compatibility with API 15.
Server:
public static SSLServerSocket getServerSocketWithCert(int port, InputStream pathToCert, String passwordFromCert) throws IOException,
KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, UnrecoverableKeyException{
TrustManager[] tmm;
KeyManager[] kmm;
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(pathToCert, passwordFromCert.toCharArray());
tmm=tm(ks);
kmm=km(ks, passwordFromCert);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmm, tmm, null);
SSLServerSocketFactory socketFactory = (SSLServerSocketFactory) ctx.getServerSocketFactory();
SSLServerSocket ssocket = (SSLServerSocket) socketFactory.createServerSocket(port);
return ssocket;
}
private static TrustManager[] tm(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustMgrFactory.init(keystore);
return trustMgrFactory.getTrustManagers();
};
private static KeyManager[] km(KeyStore keystore, String password) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
KeyManagerFactory keyMgrFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyMgrFactory.init(keystore, password.toCharArray());
return keyMgrFactory.getKeyManagers();
};
public static void main(String[] args){
SSLServerSocket ss = null;
try {
ss = getServerSocketWithCert(12345, Server.class.getResourceAsStream("/privateKey.store"), "password");
} catch(BindException e){
e.printStackTrace();
System.exit(1);
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
while(true){
SSLSocket s = ss.accept();
new DataOutputStream(s.getOutputStream()).writeUTF("test");
//TODO ERROR IS APPENING HERE
}
}
Client:
public static SSLSocket getSocketWithCert(InetAddress ip, int port, InputStream pathToCert, String passwordFromCert) throws IOException,
KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException {
TrustManager[] tmm;
KeyStore ks = KeyStore.getInstance("BKS");
ks.load(pathToCert, passwordFromCert.toCharArray());
tmm=tm(ks);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmm, null);
SSLSocketFactory SocketFactory = (SSLSocketFactory) ctx.getSocketFactory();
SSLSocket socket = (SSLSocket) SocketFactory.createSocket();
socket.connect(new InetSocketAddress(ip, port), 5000);
return socket;
}
private static TrustManager[] tm(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustMgrFactory.init(keystore);
return trustMgrFactory.getTrustManagers();
};
public static void(String[] args){
int id;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){
id = R.raw.publickey;
} else {
id = R.raw.publickey_v1;
}
try {
Socket s = SSLSocketKeystoreFactory.getSocketWithCert("myip", 12345, HackerMainActivity.this.getResources().openRawResource(id), "password");
} catch (UnknownHostException | SecurityException e) {
e.printStackTrace();
return;
} catch(SocketTimeoutException e){
e.printStackTrace();
return;
} catch (KeyManagementException | NoSuchAlgorithmException | CertificateException | KeyStoreException e) {
e.printStackTrace();
}
DataInputStream in = new DataInputStream(s.getInputStream());
//TODO ERROR IS APPENING HERE
}
Thanks a lot for you help !
I finally managed to fix it...
The error was that Android 6.0 is the version that dropped support for SHA-1.
For the one who had the same error, just re-create your certificates using SHA-256...

What is the benefit of RmiProxyFactoryBean over writing my own wrapper (or not using a wrapper)?

Suppose I have the following Spring XML declaration:
<bean id="myBeanName"
class="org.springframework.remoting.rmi.RmiProxyFactoryBean"
lazy-init="true" p:serviceInterface=
"com.org.MyInterface"
p:serviceUrl="http://myserver:1234/"
p:registryClientSocketFactory-ref="mySocketFactory"
p:refreshStubOnConnectFailure="true" p:lookupStubOnStartup="true"/>
Then I load this up with a Spring application Context and call it.
ApplicationContext factory = new ClassPathXmlApplicationContext("mySpringXML.xml");
MyInterface myInterface = (MyInterface ) factory.getBean("myBeanName");
returnValue = myInterface.invokeMyMethod(arg1, arg2);
Now contrast this with leaving out the Spring XML and just doing RMI directly using the Java Registry:
class MySslRMIClientSocketFactory implements RMIClientSocketFactory {
private SSLSocketFactory sf;
public MySslRMIClientSocketFactory(SSLSocketFactory sf) {
this.sf = sf;
}
#Override
public Socket createSocket(String host, int port) throws IOException {
return sf.createSocket(host, port);
}
}
---- inside the calling class
private static SSLContext getSSLContext(KeyStore keyStore) {
// init KeyManagerFactory
KeyManagerFactory keyManagerFactory = null;
TrustManagerFactory trustManagerFactory = null;
SSLContext sslContext = null;
try {
keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password.toCharArray());
trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
// init KeyManager
KeyManager keyManagers[] = keyManagerFactory.getKeyManagers();
TrustManager trustManagers[] = trustManagerFactory
.getTrustManagers();
// init the SSL context
sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslContext;
}
public static void main(String[] args) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, IOException {
KeyStore keystore = getAndLoadKeyStore();
SSLContext sc = getSSLContext(keystore);
SSLSocketFactory sf = sc.getSocketFactory();
try {
RMIClientSocketFactory csf = new MySslRMIClientSocketFactory(sf);
Registry registry = LocateRegistry.getRegistry("myserver", 1234, csf);
MyInterface obj = (MyInterface)registry.lookup("MyInterface");
System.out.println("Found the registry entry");
String message = obj.invokeMyMethod("arg1", 1);
System.out.println(message);
} catch (IOException | NotBoundException e) {
e.printStackTrace();
}
System.out.println("Client done");
}
My question is: What is the benefit of RmiProxyFactoryBean over writing my own wrapper (or not using a wrapper)?
I ask the question because it seems the Spring is harder to debug/triage. (Even though there are fewer lines of code - to me the difference between 5 and 15 lines for the hassle it creates is not a good tradeoff).
Assumptions
I haven't included the server side code here - but assume for the first example I have a Spring Proxy and for the second I just create a Java RMI Registry
I understand that the Spring Framework is encouraging low coupling and high cohesion - I'm interested in the benefits of this particular class
I understand that the Spring Framework is encouraging inversion of control - I'm interested in the benefits of this particular class

Categories