Rust中用openssl crate生成CMS签名无法通过OpenSSL终端验证问题
Rust生成CMS签名无法通过OpenSSL验证的问题
我是Rust新手,正在尝试为PNG文件生成CMS签名,使用的cargo openssl版本为"0.10.62"。编写的Rust代码如下:
use openssl::cms::{CmsContentInfo, CMSOptions}; use openssl::pkey::PKey; use openssl::x509::X509; use std::fs::{self}; fn main() { let certificate_contents = fs::read("files/certificate.pem").unwrap(); let private_key_contents = fs::read("files/private_key.pem").unwrap(); let image_contents = fs::read("files/image.png").unwrap(); let signcert = X509::from_pem(&certificate_contents).unwrap(); let pkey = PKey::private_key_from_pem(&private_key_contents).unwrap(); let flags = CMSOptions::DETACHED; let cms = CmsContentInfo::sign( Some(&signcert), Some(&pkey), None, Some(&image_contents), flags ).unwrap(); fs::write("files/signature.pem", cms.to_pem().unwrap()).unwrap(); }
问题
生成的signature.pem无法通过终端的OpenSSL验证命令校验,验证命令如下:
openssl cms -verify -in signature.pem -inform PEM -content image.png -CAfile certificate.pem -out verified_content -noverify
而直接用终端OpenSSL命令生成的signature.pem可以正常验证,签名命令如下:
openssl cms -sign -in image.png -signer certificate.pem -inkey private_key.pem -outform PEM -out signature.pem -nodetach
终端使用的OpenSSL版本为:OpenSSL 3.1.4 24 Oct 2023 (Library: OpenSSL 3.1.4 24 Oct 2023)
问题原因及解决方法
核心差异在于签名的模式:
- 终端命令使用
-nodetach,生成的是非分离式CMS签名(签名文件中包含原始PNG内容) - Rust代码中设置了
CMSOptions::DETACHED,生成的是分离式CMS签名(签名文件仅包含签名数据,不包含原始内容)
方案1:生成和终端命令一致的非分离式签名
修改代码中的flags为CMSOptions::empty(),去掉分离式标记:
let flags = CMSOptions::empty();
此时生成的签名会包含原始PNG内容,验证时无需指定-content image.png,可以用以下命令验证:
openssl cms -verify -in signature.pem -inform PEM -CAfile certificate.pem -out verified_content -noverify
方案2:修正分离式签名的生成逻辑
如果需要生成分离式签名,需将CmsContentInfo::sign的第四个参数(内容)设为None(根据openssl 0.10.62文档,当content为None时才会生成分离式签名):
let cms = CmsContentInfo::sign( Some(&signcert), Some(&pkey), None, None, // 此处改为None flags ).unwrap();
修改后即可用你原来的验证命令正常校验。
内容的提问来源于stack exchange,提问作者Kherel
相关产品推荐
相关产品推荐

