[英]AWS IOT Just-in-Time Registration of Certificate in Android
我正在按照这篇文章整合 JITR。
https://aws.amazon.com/blogs/iot/just-in-time-registration-of-device-certificates-on-aws-iot/
我完成了所有这些步骤,并且能够通过命令行“mosquitto_pub”验证证书。
第一次运行“mosquitto_pub”命令时,它调用 lambda 函数对其进行授权并附加策略,第二次它成功地将消息发布到 IOT。
这是我正在使用的命令。
mosquitto_pub --cafile ../root.cert --cert hassanAndCACert.crt --key hassan.key -h <###>.iot.us-east-1.amazonaws.com
-p 8883 -q 1 -t topic5 -i 123456789 --tls-version tlsv1.2 -m '{"hello":"3"}' -d
但是,当我尝试在 android SDK 中对此进行身份验证时,出现“握手”失败错误。 这是我得到的例外。
MqttException (0) - javax.net.ssl.SSLHandshakeException:握手在 org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)at org.eclipse.paho.client.mqttv3.internal 失败。 ClientComms$ConnectBG.run(ClientComms.java:664)at java.lang.Thread.run(Thread.java:818)Caused by: javax.net.ssl.SSLHandshakeException: Handshake failedat com.android.org.conscrypt.OpenSSLSocketImpl。开始握手(OpenSSLSocketImpl.java:441)在 org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule.start(SSLNetworkModule.java:93)在 org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run( ClientComms.java:650)... 1 moreCaused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0xb91e9b40: Failure in SSL library, usually a protocol errorerror:100c5416:SSL routines:ssl3_read_bytes:SSLV3_ALERT_CERTIFICATE_UNKNOWN (外部/ boringssl/src/ssl/s3_pkt.c:972 0xb9215530:0x00000001)at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(本地方法)a t com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:353)
有趣的是,如果设备证书已经激活并且我们尝试通过 android 发布消息,它就会成功发布。 唯一的问题是在第一次调用时验证证书。 如果我的代码有问题,它不应该发送针对激活证书的消息。
我在 mosquitto 调用和 android 代码之间看到的区别是 mosquitto 正在执行一个命令来连接和发布消息,而 AWS SDK 中的 PAHO-MQTT 需要在发布之前先连接,我在“连接”中遇到异常'. 我什至没有在 AWS 日志中得到任何日志。
SSL/TLS 握手可能因各种原因而失败,而不仅仅是证书验证问题。
它可能是为了:
找出问题所在的最佳方法是安装Wireshark并查看握手消息。 然后根据从服务器发送到客户端的 SSL 警报消息,您可以获得有关 SSL 握手失败的更多信息,具体发生在何处。
制作您自己的 KeyStoreHelper 将 CA 证书放入您的 KeyStore,并使用它代替 AWS IoT SDK 的KeyStoreHelper 。
注意:我在下面的代码中省略了所有异常处理,createKeyPair()、createCSR()、parsePemObject() 和 signCSR() 是我的方法。
public class MyKeystoreHelper {
public KeyStore createKeystoreJIT(String certId, String keystorePath,
String keystoreName, String keystorePassword, HashMap<String, String> directory) {
// Generate KeyPair
KeyPair key = createKeyPair();
// Generate CSR
PKCS10CertificationRequest csr = createCSR(key, directory);
// Read CA Private key
PEMKeyPair pemKey = (PEMKeyPair)parsePemObject(context, PATH_TO_CAROOT_KEY_FILE);
KeyPair caKey = new JcaPEMKeyConverter().getKeyPair(pemKey);
// Read CA Cert
X509CertificateHolder pemCert = (X509CertificateHolder)parsePemObject(context, PATH_TO_CAROOT_CERT_FILE);
X509Certificate caCert = new JcaX509CertificateConverter().getCertificate(pemCert);
X500Name issuer = pemCert.getIssuer();
// Generate CA Signed CSR
X509Certificate cert = signCSR(csr, caKey.getPrivate(), caCert, issuer);
// Create Key Store
saveKeystore(certId, cert, caCert, key.getPrivate(), keystorePath, keystoreName, keystorePassword); // <-- HERE!! Pass CA Cert
KeyStore keystore = getKeystore(certId, keystorePath, keystoreName, keystorePassword);
return keystore;
}
....
private boolean saveKeystore(String certId, X509Certificate cert, X509Certificate caCert,
PrivateKey privatekey, String keystorePath, String keystoreName, String keystorePassword) {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
File keystoreFile = new File(keystorePath, keystoreName);
if( ! keystoreFile.exists()) {
createKeystore(keystorePath, keystoreName, keystorePassword);
}
FileInputStream fis = new FileInputStream(keystoreFile);
keystore.load(fis, keystorePassword.toCharArray());
fis.close();
keystore.setCertificateEntry(certId, cert);
keystore.setKeyEntry(certId, privatekey, keystorePassword.toCharArray(), new Certificate[] { cert, caCert }); // <-- HERE!! put CA Cert
String caCertId = certId + "_CA";
keystore.setCertificateEntry(caCertId, caCert);
keystore.setKeyEntry(caCertId, privatekey, keystorePassword.toCharArray(), new Certificate[] { caCert });
String keystoreFileAndPath;
if(keystorePath.endsWith("/")) {
keystoreFileAndPath = keystorePath + keystoreName;
} else {
keystoreFileAndPath = keystorePath + "/" + keystoreName;
}
FileOutputStream fos = new FileOutputStream(keystoreFileAndPath);
keystore.store(fos, keystorePassword.toCharArray());
fos.close();
return true;
}
....
private KeyStore getMemoryKeystore(KeyStore customerKeystore, String certId, String customerKeystorePassword) {
KeyStore memoryKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
memoryKeystore.load(null);
X509Certificate cert = (X509Certificate) customerKeystore.getCertificate(certId);
memoryKeystore.setCertificateEntry("cert-alias", cert);
Key key = customerKeystore.getKey(certId, customerKeystorePassword.toCharArray());
String caCertId = certId + "_CA";
X509Certificate caCert = (X509Certificate) customerKeystore.getCertificate(caCertId); // Pull CA Cert
memoryKeystore.setCertificateEntry("cacert-alias", caCert);
memoryKeystore.setKeyEntry("key-alias", key, AWS_IOT_INTERNAL_KEYSTORE_PASSWORD.toCharArray(), new Certificate[] { cert, caCert }); // <-- HERE!!
return memoryKeystore;
}
....
}
在连接和发布 MQTT 之前,获取链接在 KeyStore 中的 CSR 和 CA 证书,如下所示:
keystoreHelper = new MyKeystoreHelper(...);
if(keystoreHelper.isKeystorePresent(keystorePath, KEYSTORE_NAME)) {
keystore = keystoreHelper.getKeystore(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD);
} else {
// Create your own KeyStroe if it is not exist yet.
HashMap<String, String> directory = getDirectory(); // X.500 directory items for CSR
keystoreHelper.createKeystoreJIT(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD, directory);
keystore = keystoreHelper.getKeystore(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD);
}
一旦您首次向端点发布任何消息,AWS IoT Core 将自动创建一个“事物”。
我希望这可以帮助你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.