如何强制openssl cms工具不为自定义签名内容封装OCTET_STRING
Openssl CMS自定义类型签名的OCTET_STRING封装问题排查与解决
问题根源
- 你观察到的多余OCTET_STRING封装,是
openssl cms命令行工具的硬编码默认行为,并非参数配置错误。该工具最初面向S/MIME邮件签名场景设计,默认会将-in参数指向文件的全部原始字节,统一封装为OCTET_STRING类型,哪怕通过-econtent_type指定了自定义内容类型OID,这套封装逻辑也不会跳过。 - 你一直在找的封装逻辑,存在于OpenSSL源码
crypto/cms/cms_smime.c文件的cms_copy_binary_content函数中:读取完输入文件的字节后,函数会直接初始化一个新的ASN1_OCTET_STRING结构体,将文件字节赋值给该结构体,再把它作为CMS ContentInfo的content字段实际值传入签名流程。这就是最终生成的结构里会多出04(OCTET_STRING类型标记)的核心原因。
可行的解决办法
用OpenSSL API写最简流程跳过封装
- 现有各个版本的
openssl cms命令行,没有提供直接关闭OCTET_STRING封装的开关,所有通过命令行传入的输入内容都会被强制走封装流程。如果需要严格符合RFC 5652的结构要求,让最终的内嵌内容直接承载你的IA5String DER值(也就是把当前生成的结构a0 05 04 03 16 01 61变为a0 03 16 01 61,去掉中间的OCTET_STRING层),可以直接调用OpenSSL的CMS相关接口写几行简单代码实现:- 初始化一个空的
CMS_ContentInfo结构体 - 将自定义OID
2.999.1设置为contentType字段的值 - 把你手里的原始DER编码内容
16 01 61直接包装为ASN1_TYPE结构体,赋值给content字段的[0] EXPLICIT标记内容值,全程不创建ASN1_OCTET_STRING结构体做中间套壳 - 按正常流程加载签名证书、私钥,执行签名操作,将最终的CMS结构编码为DER格式输出即可。
- 初始化一个空的
临时用命令行绕路的方法
- 如果必须使用命令行完成操作,可以提前按照ASN.1编码规则拼好完整的预编码内容流,通过管道传入
openssl cms的内容解析入口,让工具跳过自动读取文件并封装的步骤。不过这种方式需要对ASN.1编码规则非常熟悉,后续维护成本很高,不推荐长期使用。
注意事项
- 所有现有的命令行参数,包括
-nodetach、-outform、-econtent_type,都无法改变输入内容的默认封装逻辑。调整这些参数只会影响输出格式、签名是否与内容分离,根本跳不过中间的OCTET_STRING封装层。
内容的提问来源于stack exchange,提问作者majkrzak
相关产品推荐
相关产品推荐

