私たちはAndroid用のプッシュ通知プラットフォーム(GoogleのC2DMのフェイルオーバー)を調査しています。EclipsePaho Javaクライアントを使用して、Mosquittoブローカー(1.0.3)に接続しています。ブローカーはUbuntu 12.04(AWS EC2インスタンス)にインストールされています。暗号化されていないTCP接続を使用してクライアントをサーバーに正常に接続しました。ちなみに、カーネルパラメータを微調整した後、中規模のEC2マシン上の1つのブローカーインスタンスに対して100Kの同時クライアントを開くことができました。いい仕事、蚊!
現在、SSLを使用して安全な接続を設定しようとしています。クライアント証明書を使用してクライアントを認証したい。私はmosquito_tlsページの説明に従い、サーバーとクライアントのキーと自己署名証明書を生成しました。SSLを使用するようにサーバーを構成しました。
クライアント部分については、mosquitto_tls_setの署名を調べ、CA証明書、クライアントキー、および証明書ファイルが必要であることに注意しました。私は、クライアントがサーバーを認証するためにCA証明書が使用され、サーバーがクライアントを認証するためにクライアントキーと証明書が使用されることを理解しました。私は正しいですか?
だから私はここで私がJava側でやったことです:
接続すると、mosquittoから次のエラーが表示されます
OpenSSL Error: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
Socket read error on client (null), disconnecting.
編集:クライアント側で次の例外が表示されます
javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca
これが完全なコードです
static SSLSocketFactory getSocketFactory (final String caCrtFile, final String crtFile, final String keyFile, final String password) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
X509Certificate caCert = (X509Certificate)reader.readObject();
reader.close();
reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
X509Certificate cert = (X509Certificate)reader.readObject();
reader.close();
reader = new PEMReader(
new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),
new PasswordFinder() {
public char[] getPassword() {
return password.toCharArray();
}
}
);
KeyPair key = (KeyPair)reader.readObject();
reader.close();
KeyStore caKs = KeyStore.getInstance("JKS");
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(caKs);
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null, null);
ks.setCertificateEntry("certificate", cert);
ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
//ks.setKeyEntry("public-key", key.getPublic(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password.toCharArray());
SSLContext context = SSLContext.getInstance("SSLv3");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
mosquito.confは次のようになります
# general options
pid_file /home/ubuntu/mosquitto.pid
# persistence
queue_qos0_messages false
persistence false
# logging
log_dest stdout
connection_messages true
log_timestamp false
# default listener
# disable default listener (open only SSL listener)
#port 1883
#max_connections -1
# SSL listener
listener 1883
cafile /home/ubuntu/etc/ca.crt
certfile /home/ubuntu/etc/server.crt
keyfile /home/ubuntu/etc/server.key
require_certificate true
use_identity_as_username true
max_connections -1
了解しました。蚊の開発者(thx、Roger Light)からのサポートを受けて、問題を突き止めました。証明書の生成時に提供する詳細(会社、組織単位、共通名)は、CA、クライアント、およびサーバーの証明書で異なっている必要があります。それ以外の場合、コードはいくつかの小さな変更で動作します。わかりやすくするために、いくつかのコメントを付けて正しいコードをここに再投稿します。
import java.io.*;
import java.nio.file.*;
import java.security.*;
import java.security.cert.*;
import java.security.interfaces.*;
import javax.net.ssl.*;
import org.bouncycastle.jce.provider.*;
import org.bouncycastle.openssl.*;
static SSLSocketFactory getSocketFactory (final String caCrtFile, final String crtFile, final String keyFile, final String password) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
X509Certificate caCert = (X509Certificate)reader.readObject();
reader.close();
// load client certificate
reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
X509Certificate cert = (X509Certificate)reader.readObject();
reader.close();
// load client private key
reader = new PEMReader(
new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),
new PasswordFinder() {
public char[] getPassword() {
return password.toCharArray();
}
}
);
KeyPair key = (KeyPair)reader.readObject();
reader.close();
// CA certificate is used to authenticate server
KeyStore caKs = KeyStore.getInstance("JKS");
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(caKs);
// client key and certificates are sent to server so it can authenticate us
KeyStore ks = KeyStore.getInstance("JKS");
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("PKIX");
kmf.init(ks, password.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加