Android mqtt ssl单双向验证(非自签名)
程序员文章站
2022-04-23 11:49:27
...
Android与MQTT实现单向认证。
需要的包:
implementation'org.bouncycastle:bcpkix-jdk15on:1.59'
BouncyCastle(轻量级密码术包)是一种用于 Java 平台的开放源码的轻量级密码术包;验证的时候需要服务器提供中间证书。中间证书为.pem格式无需转换为.bks格式,将中间证书放入设备中。创建SSLSocketFactory,代码如下:
/**
*
* @param caCrtFile 中间证书地址
* @return
* @throws Exception
*/
private SSLSocketFactory getSingleSocketFactory(final String caCrtFile)throws Exception {
Security.addProvider(new BouncyCastleProvider());
X509Certificate caCert =null;
FileInputStream fis =new FileInputStream(caCrtFile);
BufferedInputStream bis =new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() >0) {
caCert = (X509Certificate) cf.generateCertificate(bis);
}
KeyStore caKs =
KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null,null);
caKs.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf =
TrustManagerFactory.getInstance("X509");
tmf.init(caKs);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, tmf.getTrustManagers(),null);
return sslContext.getSocketFactory();
}
将socketFactory设到options中
SSLSocketFactory socketFactory = getSingleSocketFactory(caFilePath);
options.setSocketFactory(socketFactory);
单向验证完成
双向验证
双向验证需客户端证书和私钥(证书为.pem格式无需转换,私钥为.key格式)
密码设null 就好
代码如下:
/**
* @param caCrtFile 中间证书地址
* @param crtFile 客户端证书地址
* @param keyFile 私钥地址
* @param password 密码
* @return
* @throws Exception
*/
private SSLSocketFactory getSocketFactory(final String caCrtFile,
final String crtFile, final String keyFile,
final String password)
throws Exception {
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
X509Certificate caCert = null;
FileInputStream fis = new FileInputStream(caCrtFile);
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
caCert = (X509Certificate) cf.generateCertificate(bis);
}
// load client certificate
bis = new BufferedInputStream(new FileInputStream(crtFile));
X509Certificate cert = null;
while (bis.available() > 0) {
cert = (X509Certificate) cf.generateCertificate(bis);
}
// load client private key
PEMParser pemParser = new PEMParser(new FileReader(keyFile));
Object object = pemParser.readObject();
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder()
.build(password.toCharArray());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter()
.setProvider("BC");
KeyPair key;
if (object instanceof PEMEncryptedKeyPair) {
LogUtils.e("Encrypted key - we will use provided password");
key = converter.getKeyPair(((PEMEncryptedKeyPair) object)
.decryptKeyPair(decProv));
} else {
LogUtils.e("Unencrypted key - no password needed");
key = converter.getKeyPair((PEMKeyPair) object);
}
pemParser.close();
// CA certificate is used to authenticate server
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(caKs);
// client key and certificates are sent to server so it can authenticate
// us
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry("certificate", cert);
ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),
new java.security.cert.Certificate[]{cert});
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
自此单双向验证完成。
上一篇: netty-socketio 示例代码