finally found a solution to this.
based on this documentation, TLS 1.1 and TLS 1.2 is supported from android API level 16 (Android 4.1, Jelly Bean). But it is'nt enabled by default until API level 20+ (Android 4.4 for watch, Kitkat Watch and Android 5.0 for phone, Lollipop).
so all we need is to enable them parogrammatically in code. how we gonna do this ? there is a solution for this problem here BUT it just resolves the problem for the case that you want to accept any certificate instead.
what we need is do the same thing but with our own self signed certificate. so we do it like below. the first part is just like what i did before : (keyStoreInputStream
is input stream of a .pfx file)
connection = createConnection(mqttCallback);
MqttConnectOptions connOpts = optionsFromModel(connectionModel);
connOpts.setSocketFactory(getSSLSocketFactory(keyStoreInputStream, keyStorePassword));
connection.addConnectionOptions(connOpts);
the getSSLSocketFactory
method changes to:
public SSLSocketFactory getSSLSocketFactory (InputStream keyStore, String password) throws MqttSecurityException {
try{
SSLContext ctx = null;
SSLSocketFactory sslSockFactory=null;
KeyStore ks;
ks = KeyStore.getInstance("PKCS12");
ks.load(keyStore, password.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(ks);
TrustManager[] tm = tmf.getTrustManagers();
ctx = SSLContext.getInstance("TLS");
ctx.init(null, tm, null);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
sslSockFactory = new TLSSocketFactory(tm);
} else {
sslSockFactory = ctx.getSocketFactory();
}
return sslSockFactory;
} catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException | KeyManagementException e) {
throw new MqttSecurityException(e);
}
}
and the TLSSocketFactory
class is like below:
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
public class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactory(TrustManager[] trustManagers) throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, null);
internalSSLSocketFactory = context.getSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1"});
}
return socket;
}
}