使用AWS IoT createCertificateFromCsr创建证书后MQTT连接失败排查
问题
之前我们通过AWS IoT SDK的IotClient.CreateKeysAndCertificate方法创建证书,使用返回的pemCert和pemPrivateKey,通过以下代码可成功实现客户端MQTT连接:
AwsIotMqtt5ClientBuilder.newDirectMqttBuilderWithMtlsFromPath(iotEndpoint, pemCert, pemPrivateKey);
现在我们希望改为自行生成密钥,仅通过IotClient.createCertificateFromCsr方法让AWS创建并注册IoT证书。我们已通过以下代码成功在AWS创建证书(证书已关联Thing并配置好连接所需策略):
// 依赖 // 'org.bouncycastle:bc-fips:1.0.2.5' // 'org.bouncycastle:bcpkix-fips:1.0.7' // 'software.amazon.awssdk:iot:2.25.52' private KeyPair generateRSAKeyPair(int keySize) throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BCFIPS"); // 初始化密钥长度 generator.initialize(keySize); // 生成密钥对 return generator.generateKeyPair(); } private String convertToPemFormat(Object keyOrRequest) throws Exception { StringWriter stringWriter = new StringWriter(); try (JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) { pemWriter.writeObject(keyOrRequest); } return stringWriter.toString(); } // .... 业务代码 KeyPair keyPair = generateRSAKeyPair(keySize); // 创建CSR X500Principal subject = new X500Principal(principleName); PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(subject, keyPair.getPublic()); JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA"); PKCS10CertificationRequest csRequest = csrBuilder.build(csBuilder.build(keyPair.getPrivate())); // 将CSR转换为PEM格式 String pemCsr = convertToPemFormat(csRequest); CreateCertificateFromCsrRequest request = CreateCertificateFromCsrRequest.builder() .certificateSigningRequest(pemCsr) .setAsActive(true) .build(); CreateCertificateFromCsrResponse cert = IotClient.builder().build().createCertificateFromCsr(request); // 客户端侧代码... // 使用依赖 'software.amazon.awssdk.iotdevicesdk:aws-iot-device-sdk:1.20.7' String privateKeyPEM = convertToPemFormat(new PemObject("RSA PRIVATE KEY", keyPair.getPrivate().getEncoded())); AwsIotMqtt5ClientBuilder builder = AwsIotMqtt5ClientBuilder.newDirectMqttBuilderWithMtlsFromMemory( ourIotEndpoint, // 需替换为你的AWS IoT环境端点 cert.certificatePem(), privateKeyPEM); builder.withPort(443L); Mqtt5Client returnClient = builder.build(); // <- 此处崩溃
但在客户端执行上述代码构建Mqtt5Client时出现崩溃,报错信息为:
TlsContext.tls_ctx_new: Failed to create new aws_tls_ctx (aws_last_error: AWS_IO_FILE_VALIDATION_FAILURE(1038), A file was read and the input did not match the expected value)
请问我们遗漏了什么步骤?
解决方法
问题出在私钥的PEM格式不匹配,以及缺少完整证书链验证,以下是具体修复步骤:
1. 修正私钥的PEM编码逻辑
你手动构造PemObject时,传入的keyPair.getPrivate().getEncoded()是PKCS#8格式的私钥,但指定的类型是"RSA PRIVATE KEY"(对应PKCS#1格式),格式不匹配导致TLS上下文验证失败。
替换私钥生成代码,直接用JcaPEMWriter写入私钥对象:
// 无需手动构造PemObject,JcaPEMWriter会自动识别格式并生成正确的PEM内容 String privateKeyPEM = convertToPemFormat(keyPair.getPrivate());
2. 添加AWS IoT根证书完成证书链
AWS返回的cert.certificatePem()仅包含设备证书本身,TLS握手需要完整的证书链(设备证书 + AWS IoT根证书)才能通过验证。
修改客户端构建代码,添加根证书参数:
// rootCaPem为你从AWS控制台下载的根证书PEM字符串(如Amazon Root CA 1) AwsIotMqtt5ClientBuilder builder = AwsIotMqtt5ClientBuilder.newDirectMqttBuilderWithMtlsFromMemory( ourIotEndpoint, cert.certificatePem(), privateKeyPEM, rootCaPem); // 补充根证书
3. 验证密钥对与证书的匹配性
可以通过OpenSSL命令确认本地私钥和AWS返回的证书是否匹配:
# 提取证书公钥 openssl x509 -in device-cert.pem -pubkey -noout > cert-pubkey.pem # 提取私钥对应的公钥 openssl rsa -in private-key.pem -pubout > key-pubkey.pem # 对比两个公钥内容是否一致 diff cert-pubkey.pem key-pubkey.pem
如果内容一致则匹配正常,若不一致需检查CSR生成流程是否有误。
内容的提问来源于stack exchange,提问作者Raziza O
相关产品推荐
相关产品推荐

