You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:37:09