標籤:
在開發java版mosquitto用戶端程式時需要使用paho庫,如果開發的java用戶端要用ssl功能,則需要Bouncy Castle庫;在使用ssl功能時,需要認證檔案進行進行身份認證,但在測試過程中,只自己製作ca並進行認證簽發即可。在測試過程中首先建立一個統一的ca,該ca包括一個crt檔案,一個key檔案(例如ca.crt、ca.key);測試過程中,要使用該ca為每個測試的機子簽發認證,例如:mosquitto伺服器運行在192.168.4.223的linux機子上,java版的用戶端運行在192.168.4.69的windows機子上,則需要將該ca(即檔案ca.crt、ca.key)分別拷貝到mosquitto伺服器啟動並執行192.168.4.223上,java版用戶端啟動並執行192.168.4.69機子上,然後用openssl使用ca為這兩該機子分別簽發認證檔案,為伺服器端簽發的認證檔案為server.crt和server.key,為用戶端簽發的認證檔案為client.crt和client.key;在上述過程中可能需要用到下面四點內容:
(1)在linux系統下製作ca並使用ca簽發認證,該過程可以參考文檔:
http://blog.csdn.net/houjixin/article/details/24305613
或者:
http://houjixin.blog.163.com/blog/static/35628410201432205042955/
(2)使用openssl製作ca過程中所需使用的openssl命令,可以參考:http://mosquitto.org/man/mosquitto-tls-7.html
(3)在windows平台下製作用戶端的認證檔案,其中ca要與伺服器端和其他測試用戶端保持一致。Windows平台下製作認證可參考文檔:
http://blog.csdn.net/houjixin/article/details/25806151
或:
http://houjixin.blog.163.com/blog/static/3562841020144143494875/
(4)開發過程中需要用到庫“bcprov-jdk16-139.jar”,
其為:http://www.bouncycastle.org/latest_releases.html
ssl功能只是在用戶端和伺服器通訊之前的身分識別驗證,後續的通訊過程中的加密操作由ssl內部完成,因此具備的ssl功能的java版mosquitto用戶端與普通的java版mosquitto用戶端相比,只需修改開始部分的相關代碼即可。在windows系統下開發java版用戶端時,按照下面的步驟進行操作即可:
(1)使用openss根據提供ca簽發用戶端認證檔案,簽發認證過程中將產生三個檔案:client.crt,client.csr和client.key;其中client.csr主要是為了向ca申請產生client.key檔案時產生的“認證申請檔案”,一旦產生client.crt和client.key之後就不再需要,實際測試過程中只有client.crt、client.key這兩個檔案被用戶端用於和mosquitto伺服器程式進行通訊時的身分識別驗證。
(2)封裝對ssl的相關操作到一個java類中,例如SslUtil,在該類中完成所有ssl相關功能,例如:載入ca.crt、client.crt和client.key這三個檔案,與mosquitto的伺服器端進行ssl身份認證。在該類中只有一個函數getSocketFactory,最終該函數將返回一個ssl相關的socket factory執行個體。該類在附件”SsUtil.java”附件檔案中提供。
(3)在使用paho建立mosquitto用戶端之前需先建立一個MqttConnectOptions對象,在該對象中調用函數setSocketFactory,並傳入第二步中SslUtil所返回的sockt factory執行個體。相關代碼如下所示:
m_conOpt = new MqttConnectOptions();……try {m_conOpt.setSocketFactory(SslUtil.getSocketFactory(caFilePath, clientCrtFilePath, clientKeyFilePath, sspwd));} catch (Exception e) {e.printStackTrace();}
(4)建立一個MqttClient對象,並在該對象串連mosquitto伺服器之前先設定第三步中建立的MqttConnectOptions對象。
(5)修改傳給MqttClient對象的url參數,使其最前面的協議標誌修改為ssl,例如:
String serverUrl = "ssl://192.168.4.223:8883";
注意:
1)在win7系統下製作認證檔案時可能會出現:Unable to write ‘random state’的問題,該問題的解決辦法可參考文檔:
http://houjixin.blog.163.com/blog/static/356284102014420104455237/
或:
http://blog.csdn.net/houjixin/article/details/26347375
2)使用paho串連mosquitto時需要將url中的協議名改成ssl,例如:
StringserverUrl = "ssl://192.168.4.223:8883"
參考內容:
[1] https://gist.github.com/sharonbn/4104301
[2]http://stackoverflow.com/questions/18896087/mosquitto-mqtt-broker-and-java-client-with-ssl-tls
附:SslUtil.java的源碼:
package test.com.browan.mqtt;import java.io.*;import java.nio.file.*;import java.security.*;import java.security.cert.*;import javax.net.ssl.*; import org.bouncycastle.jce.provider.*;import org.bouncycastle.openssl.*; public class SslUtil{static SSLSocketFactory getSocketFactory (final String caCrtFile, final String crtFile, final String keyFile, final String password) throws Exception{Security.addProvider(new BouncyCastleProvider()); // load CA certificatePEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));X509Certificate caCert = (X509Certificate)reader.readObject();reader.close(); // load client certificatereader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));X509Certificate cert = (X509Certificate)reader.readObject();reader.close(); // load client private keyreader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),new PasswordFinder() {@Overridepublic char[] getPassword() {return password.toCharArray();}});KeyPair key = (KeyPair)reader.readObject();reader.close(); // CA certificate is used to authenticate serverKeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());caKs.load(null, null);caKs.setCertificateEntry("ca-certificate", caCert);TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());tmf.init(caKs); // client key and certificates are sent to server so it can authenticate usKeyStore 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 factorySSLContext context = SSLContext.getInstance("TLSv1");context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return context.getSocketFactory();}}
java版mosquitto用戶端使用SSL功能的具體操作總結