android与mqtt双向SSL认证
04 Mar 2016Android与MQTT实现双向认证。
需要的工具:
- bcprov-ext-jdk14-1.54.jar
- portecle-1.9
- UnlimitedJCEPolicyJDK8
生成ca.bks完成对服务器的自签名单向认证
$ keytool -import \
    -alias mqtt.broker \
    -file ca.crt \
    -keypass passw0rd \
    -keystore ca.bks  \
    -storetype BKS \
    -storepass passw0rd \
    -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider \
    -providerpath bcprov-ext-jdk14-1.54.jar
MqttAndroidClient clint = ...
MqttConnectOptions options = new MqttConnectOptions();
InputStream input = this.getApplicationContext().getAssets().open("ca.bks");
options.setSocketFactory(client.getSSLSocketFactory(input, "passw0rd"));
生成client.bks完成对客户端的认证,需要借portecle工具把pfx转成bks
$ openssl pkcs12 -export -inkey client.key -in client.crt -out client.pfx
$ java -jar portecle.jar
File -> New Keystore -> BKS-V1 -> Tools -> Import Key Pair -> choose -> client.pfx
如果提示错误就安装UnlimitedJCEPolicyJDK8
private SSLSocketFactory getSSLSocketFactory(Context context, String password) throws MqttSecurityException {
    try {
        InputStream keyStore = context.getResources().getAssets().open("client.bks");
        KeyStore km = KeyStore.getInstance("BKS");
        km.load(keyStore, password.toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
        kmf.init(km, password.toCharArray());
        InputStream trustStore = context.getResources().getAssets().open("ca.bks");
        KeyStore ts = KeyStore.getInstance("BKS");
        ts.load(trustStore, password.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(ts);
        SSLContext ctx = SSLContext.getInstance("SSL");
        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        return ctx.getSocketFactory();
    } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException e) {
        throw new MqttSecurityException(e);
    }
}
options.setSocketFactory(getSSLSocketFactory(context, "passw0rd"));
参考: