如何在OpenSSL CMS签名中添加指定OID的signedAttr?
如何在OpenSSL CMS签名中添加OID 1.2.840.113635.100.9.1的Signed Attribute
这个OID对应的是Apple的apple-application-identifier属性,通常用于iOS/macOS生态的代码签名场景。常规的CMS_sign()高层API确实不会直接暴露添加自定义Signed Attribute的入口,你需要手动操作底层的CMS结构来实现。下面是具体的步骤和代码示例:
核心思路
OpenSSL的CMS签名结构中,每个CMS_SignerInfo包含一组Signed Attributes。要添加自定义属性,你需要:
- 创建并初始化CMS签名的基础结构
- 定位到目标
CMS_SignerInfo对象 - 构造指定OID的
X509_ATTRIBUTE对象 - 将该属性添加到Signed Attributes集合
- 重新计算签名(因为Signed Attributes是签名覆盖的内容,修改后必须重新签名)
代码示例(C语言API)
#include <openssl/cms.h> #include <openssl/x509.h> #include <openssl/pem.h> int add_apple_app_id_attr(CMS_ContentInfo *cms, EVP_PKEY *pkey, const char *app_id) { // 获取第一个SignerInfo(如果有多个签名者,需要遍历处理) STACK_OF(CMS_SignerInfo) *si_stack = CMS_get0_signerInfos(cms); if (!si_stack || sk_CMS_SignerInfo_num(si_stack) == 0) { fprintf(stderr, "No signer info found in CMS structure\n"); return 0; } CMS_SignerInfo *si = sk_CMS_SignerInfo_value(si_stack, 0); // 创建OID对象 ASN1_OBJECT *oid = OBJ_txt2obj("1.2.840.113635.100.9.1", 1); if (!oid) { fprintf(stderr, "Failed to create OID\n"); return 0; } // 创建属性值(UTF-8字符串类型) ASN1_UTF8STRING *attr_val = ASN1_UTF8STRING_new(); if (!attr_val || !ASN1_STRING_set(attr_val, app_id, -1)) { fprintf(stderr, "Failed to set attribute value\n"); ASN1_OBJECT_free(oid); ASN1_UTF8STRING_free(attr_val); return 0; } // 创建X509_ATTRIBUTE对象 X509_ATTRIBUTE *attr = X509_ATTRIBUTE_create_by_OBJ(NULL, oid, V_ASN1_UTF8STRING, attr_val); if (!attr) { fprintf(stderr, "Failed to create X509 attribute\n"); ASN1_OBJECT_free(oid); ASN1_UTF8STRING_free(attr_val); return 0; } // 获取或初始化Signed Attributes集合 STACK_OF(X509_ATTRIBUTE) *signed_attrs = CMS_SignerInfo_get0_attrs(si); if (!signed_attrs) { signed_attrs = sk_X509_ATTRIBUTE_new_null(); if (!signed_attrs || !CMS_SignerInfo_set_attrs(si, signed_attrs)) { fprintf(stderr, "Failed to initialize signed attributes\n"); X509_ATTRIBUTE_free(attr); ASN1_OBJECT_free(oid); ASN1_UTF8STRING_free(attr_val); return 0; } } // 添加属性到集合 if (!sk_X509_ATTRIBUTE_push(signed_attrs, attr)) { fprintf(stderr, "Failed to push attribute to signed attrs\n"); X509_ATTRIBUTE_free(attr); ASN1_OBJECT_free(oid); ASN1_UTF8STRING_free(attr_val); return 0; } // 重新计算签名(因为Signed Attributes被修改,必须重新签名) if (!CMS_SignerInfo_sign(si, pkey, NULL, NULL, 0)) { fprintf(stderr, "Failed to re-sign CMS signer info\n"); return 0; } // 释放临时对象(attr已经被栈接管,不需要手动释放) ASN1_OBJECT_free(oid); ASN1_UTF8STRING_free(attr_val); return 1; } // 使用示例 int main() { // 假设你已经有输入数据in、签名密钥pkey、证书cert BIO *in = BIO_new_file("data.txt", "r"); EVP_PKEY *pkey = PEM_read_PrivateKey(BIO_new_file("private.key", "r"), NULL, NULL, NULL); X509 *cert = PEM_read_X509(BIO_new_file("cert.pem", "r"), NULL, NULL, NULL); // 创建基础CMS签名结构(DETACHED表示分离式签名,根据你的需求调整) CMS_ContentInfo *cms = CMS_sign(cert, pkey, NULL, in, CMS_DETACHED); // 添加apple-application-identifier属性 if (!add_apple_app_id_attr(cms, pkey, "com.yourcompany.yourapp")) { fprintf(stderr, "Failed to add apple app id attribute\n"); CMS_ContentInfo_free(cms); return 1; } // 输出CMS签名到文件 BIO *out = BIO_new_file("signed.cms", "w"); i2d_CMS_bio(out, cms); // 资源释放 BIO_free(in); BIO_free(out); EVP_PKEY_free(pkey); X509_free(cert); CMS_ContentInfo_free(cms); return 0; }
注意事项
- 如果你有多个签名者,需要遍历
STACK_OF(CMS_SignerInfo)中的每个CMS_SignerInfo对象,为每个签名者添加该属性。 - 内存管理要注意:
X509_ATTRIBUTE被添加到栈后,不需要手动释放,栈会在CMS结构释放时一起清理;但OID和属性值需要手动释放。 - 确保使用的OpenSSL版本支持这些API(OpenSSL 1.1.0及以上版本都没问题)。
- 验证属性是否添加成功,可以用
openssl cms -verify -in signed.cms -inform DER -noverify命令查看CMS结构的详细内容。
内容的提问来源于stack exchange,提问作者Umang Raghuvanshi
相关产品推荐
相关产品推荐

