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

Swift 4+OpenSSL Linux环境下CMS签名验证错误求助

Hey there! 看到你在Linux上用Swift 4结合OpenSSL做CMS签名验证时卡壳了,先给你点个赞——毕竟跨平台搞密码学确实容易踩坑。既然你已经搞定了签名创建,那咱们就聚焦在验证环节的常见问题上,一步步排查:

常见排查方向

1. 先通过OpenSSL命令行排除基础问题

先别着急看代码,用命令行手动验证你的CMS签名文件,先确认签名本身是否有效:

# 先跳过证书链验证,只检查签名是否匹配原始数据
openssl cms -verify -in signed_data.cms -inform der -certfile signing_cert.pem -noverify -in test_message.txt

# 如果上面成功了,再去掉-noverify检查证书链完整性
openssl cms -verify -in signed_data.cms -inform der -certfile signing_cert.pem -in test_message.txt

如果命令行验证都失败,那问题大概率出在签名创建环节或者原始数据/证书不匹配;如果命令行能过,那就是Swift代码调用OpenSSL的细节有问题。

2. 检查验证代码的关键细节

编码格式对应

确认签名创建时输出的是DER还是PEM格式,验证时必须对应:

  • 如果签名是DER二进制格式,Swift里解析要用d2i_CMS_bio;如果是PEM格式,要用PEM_read_bio_CMS,别搞混了。

证书与签名的匹配性

  • 你用来验证的证书,必须是签名时使用的私钥对应的公钥证书,不能用其他证书凑数。
  • 如果签名时包含了证书链,验证时要把整个证书链都传入OpenSSL的证书栈,不能只传根证书或者中间证书。

OpenSSL API调用的标志位

CMS_verify函数的最后一个标志参数很关键,比如:

  • 如果你暂时不想验证证书链的有效性,只想确认签名本身和数据匹配,可以传入CMS_NO_SIGNER_CERT_VERIFY;
  • 如果你需要验证证书链,要确保你的系统信任证书链里的根证书,或者手动指定信任的证书栈。

给你一个基础的Swift验证代码模板参考,你可以对比自己的代码找差异:

func verifyCMSSignature(signedData: Data, originalMessage: Data, signingCert: Data) -> Bool {
    // 加载签名证书
    guard let certBio = BIO_new_mem_buf(UnsafeRawPointer(signingCert.bytes), Int32(signingCert.count)) else {
        print("Failed to create certificate BIO")
        return false
    }
    defer { BIO_free(certBio) }
    
    guard let x509Cert = PEM_read_bio_X509(certBio, nil, nil, nil) else {
        print("Failed to parse X509 certificate")
        return false
    }
    defer { X509_free(x509Cert) }
    
    // 初始化CMS内容
    guard let cmsBio = BIO_new_mem_buf(UnsafeRawPointer(signedData.bytes), Int32(signedData.count)) else {
        print("Failed to create CMS data BIO")
        return false
    }
    defer { BIO_free(cmsBio) }
    
    guard let cmsContent = d2i_CMS_bio(cmsBio, nil) else {
        print("Failed to parse CMS content")
        return false
    }
    defer { CMS_ContentInfo_free(cmsContent) }
    
    // 创建证书栈
    let certStack = sk_X509_new_null()
    sk_X509_push(certStack, x509Cert)
    defer { sk_X509_free(certStack) }
    
    // 加载原始消息到BIO
    guard let msgBio = BIO_new_mem_buf(UnsafeRawPointer(originalMessage.bytes), Int32(originalMessage.count)) else {
        print("Failed to create message BIO")
        return false
    }
    defer { BIO_free(msgBio) }
    
    // 执行验证:这里用CMS_NO_SIGNER_CERT_VERIFY先跳过证书链验证,测试签名有效性
    let verifyResult = CMS_verify(cmsContent, certStack, nil, msgBio, nil, CMS_NO_SIGNER_CERT_VERIFY)
    return verifyResult == 1
}

3. 确认原始消息完全一致

验证时用的test_message.txt和签名时用的必须是完全相同的文件——哪怕多了一个换行符、空格,或者编码格式不一样(比如UTF-8带BOM和不带BOM),都会导致签名验证失败。可以分别计算两者的SHA256哈希值对比,确认数据完全一致。

内容的提问来源于stack exchange,提问作者Shadowman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:30:49