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
相关产品推荐
相关产品推荐

