今回の例では、mosquittoのテストサーバに接続します。
証明書を取得する
mosquittoの証明書は公開されていので取得します。
$ wget http://test.mosquitto.org/ssl/mosquitto.org.crt
keytool(Java付属の鍵・証明書管理用ツール)で証明書の内容を確認できます。
$ keytool -printcert -file mosquitto.org.crt
keytool -printcert -file mosquitto.org.crt
所有者: EMAILADDRESS=roger@atchoo.org, CN=mosquitto.org, OU=CA, O=Mosquitto, L=Derby, ST=United Kingdom, C=GB
発行者: EMAILADDRESS=roger@atchoo.org, CN=mosquitto.org, OU=CA, O=Mosquitto, L=Derby, ST=United Kingdom, C=GB
シリアル番号: e0fadcf9578c98bc
有効期間の開始日: Sat Jun 30 07:11:59 JST 2012終了日: Tue Jun 28 07:11:59 JST 2022
証明書のフィンガプリント:
MD5: AB:F2:AF:A0:94:9E:08:64:F7:1D:5F:9B:EE:88:D1:8F
SHA1: A2:79:92:D3:42:0C:89:F2:93:D3:51:37:8B:A5:F5:67:5F:74:FE:3C
SHA256: D1:56:59:4D:32:A9:9D:0C:72:66:5B:5F:94:3C:30:34:D0:7C:DB:A3:60:51:A4:62:56:13:7F:63:1D:2D:F4:E6
署名アルゴリズム名: SHA1withRSA
バージョン: 3
(省略)
証明書をキーストアにインポートする
Javaで秘密鍵や証明書を扱う場合、キーストアという鍵や証明書を管理するデータベースに入れる必要があります。
$ keytool \
-import \
-alias rootCA \
-trustcacerts \
-keystore ./crt.jks \
-storetype jks \
-storepass testtest \
-file ./mosquitto.org.crt
ここでは以下を行っています。
- インポートする証明書としてmosquitto.org.crtを指定。
- 上記証明書にrootCAというエイリアスをつける。
- インポート先のキーストア名はcrt.jks
- キーストアの形式はjks(Java Key Store)
- キーストアのパスワードはtesttest
以下でキーストアに証明書がインポートされているか確認できます。
$ keytool \
-list \
-keystore ./crt.jks \
-alias rootCA \
-storepass testtest
rootCA,2016/11/30, trustedCertEntry,
証明書のフィンガプリント(SHA1): A2:79:92:D3:42:0C:89:F2:93:D3:51:37:8B:A5:F5:67:5F:74:FE:3C
Paho JavaでMQTTS(MQTT over TLS)接続する
通常のTCP接続のサンプルは以下のURLを参照ください。
以下がTLS接続版のサンプルコードです。
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import java.util.Properties;
public class MqttPublishSample {
void run () {
String topic = "MQTT Examples";
String content = "Message from MqttPublishSample";
int qos = 2;
String broker = "ssl://test.mosquitto.org:8883";
String clientId = "JavaSample";
MemoryPersistence persistence = new MemoryPersistence();
String trustStore = this.getClass().getResource("crt.jks").getPath();
try {
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
Properties prop = new Properties();
prop.setProperty("com.ibm.ssl.trustStore", trustStore);
connOpts.setSSLProperties(prop);
System.out.println("Connecting to broker: "+broker);
sampleClient.connect(connOpts);
System.out.println("Connected");
System.out.println("Publishing message: "+content);
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
System.out.println("Message published");
sampleClient.disconnect();
System.out.println("Disconnected");
System.exit(0);
} catch(MqttException me) {
System.out.println("reason "+me.getReasonCode());
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
me.printStackTrace();
}
}
public static void main(String[] args) {
MqttPublishSample sample = new MqttPublishSample();
sample.run();
}
}
TCP接続の場合との違いが2点あります。
1つ目はブローカのURI。
- スキームとしてsslを指定します。
- デフォルトポートは8883です(これはブローカの設定によります)。
String broker = "ssl://test.mosquitto.org:8883";
2つ目はSSL設定を行っていること。
- Propertiesを作成し、MqttConnectOptions.setSslPropertiesで設定します。
- 最低限、リモートホストの証明書(あるいは証明書チェーン)を含むキーストアのファイルパスを"com.ibm.ssl.trustStore"で指定します。
- なお、keytoolでキーストアを扱う場合は完全性の維持のため、パスワードを指定する必要があります。ただし、Java API で扱う証明書を扱う場合はパスワードの指定が不要のようです。
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
Properties prop = new Properties();
prop.setProperty("com.ibm.ssl.trustStore", trustStore);
connOpts.setSSLProperties(prop);
実際に実行するとうまく接続できました。
Connecting to broker: ssl://test.mosquitto.org:8883
Connected
Publishing message: Message from MqttPublishSample
Message published
Disconnected