OpenSSL 签名格式全攻略:深入解析与应用要点
摘要
OpenSSL 支持多种数字签名格式,本文深入解析其常见格式及应用场景。涵盖 PEM、DER、PKCS#7/CMS、算法特定格式及 X.690 DER 编码,详述各格式结构特点,如 PEM 的 Base64 编码与文本标记,DER 的二进制紧凑表示与 TLV 结构。同时阐述签名生成验证流程及格式转换方法,助力开发者在不同场景下安全高效地利用数字签名,保障数据完整性与不可否认性。
一、PEM 格式详解
PEM(Privacy - Enhanced Mail)是一种常见的文本格式签名表示方式,基于 Base64 编码。
1.1 结构特点
- 编码方式 :将二进制 DER 编码的签名数据进行 Base64 编码,使其能以文本形式呈现,便于在文本传输场景中使用。
- 文件标记 :包含特定的开始和结束标记行,例如 “-----BEGIN SIGNATURE-----” 和 “-----END SIGNATURE-----”,这些标记明确标识了签名数据的范围,方便识别和解析。
- 标签类型 :可根据内容使用不同标签,常见的如 CERTIFICATE(证书)、PRIVATE KEY(私钥)、SIGNATURE(签名数据)等,通过不同的标签可快速区分文件所包含的具体内容类型。
1.2 应用场景
- 人类可读的配置文件 :在一些需要人工阅读和编辑的配置文件中,PEM 格式方便技术人员查看和修改签名相关信息。
- 电子邮件传输 :由于 PEM 格式是文本形式,与电子邮件文本内容兼容性好,常用于通过邮件传输签名数据,确保邮件内容的完整性和真实性。
- OpenSSL 命令行工具的默认输出格式 :OpenSSL 命令行工具在生成签名等操作时,通常默认以 PEM 格式输出,方便用户后续处理和查看。
二、DER 格式详解
DER(Distinguished Encoding Rules)是 ASN.1 标准的二进制编码格式。
2.1 结构特点
- 二进制格式 :以紧凑的二进制形式表示数据,相比文本格式的 PEM,DER 格式占用空间更小,数据存储和传输效率更高。
- 唯一编码 :对每个 ASN.1 值只有一种 DER 编码方式,保证了数据编码的唯一性和一致性,避免因编码方式不同导致的数据歧义和解析错误。
- TLV 结构 :采用 Type - Length - Value(类型 - 长度 - 值)三元组编码。其中,Type 用于标识数据类型,如整数、字符串、对象标识符等;Length 表示后续 Value 数据的长度;Value 则是实际的数据值。这种结构使得数据的组织和解析更加清晰、规范。
2.2 应用场景
- 高性能应用 :在对数据处理速度和存储效率要求较高的高性能应用中,DER 格式的紧凑二进制特性使其成为理想选择,能快速读写和处理签名数据。
- 需要紧凑存储的场景 :如在存储空间受限的嵌入式系统或对数据大小敏感的网络传输场景中,DER 格式可有效减少签名数据的存储和传输开销。
- Windows 系统和 Java 应用中常见 :Windows 系统的一些加密组件和 Java 应用在处理数字签名时,较多地采用 DER 格式,与其他系统和平台进行互操作时需注意格式兼容性。
三、PKCS#7/CMS 格式详解
PKCS#7(后发展为 CMS 标准)定义了更复杂的签名数据结构,能够满足多种高级应用场景需求。
3.1 PKCS#7 SignedData 结构
- SignedData :是一个SEQUENCE(序列)结构,包含多个组件。其中,version 表示版本号;digestAlgorithms 列出所使用的摘要算法;contentInfo 描述被签名的内容相关信息;certificates 和 crls 分别是可选的证书链和撤销列表,用于提供签名者的证书证明和证书撤销状态;signerInfos 包含具体的签名者信息。
- SignerInfo :同样是SEQUENCE结构,包含 version(版本号)、issuerAndSerialNumber(签发者信息和证书序列号)、digestAlgorithm(摘要算法标识)、authenticatedAttributes(可选的已认证属性,如签名时间等)、digestEncryptionAlgorithm(摘要加密算法标识)、encryptedDigest(加密后的摘要值)以及 unauthenticatedAttributes(可选的未认证属性)等字段,详细记录了每个签名者的签名细节。
- ContentInfo :描述被签名的内容,包括内容类型和内容本身的数据或数据的引用位置等信息。
3.2 与 CMS 的区别
- 标准 :PKCS#7 是早期标准,CMS(Cryptographic Message Syntax)则是后续发展的更完善的国际标准(RFC 5652)。
- 递归嵌套 :CMS 支持递归嵌套,允许在签名数据中包含其他签名数据或加密数据等,而 PKCS#7 不支持此功能,限制了其在复杂多层签名场景中的应用。
- 内容类型 :CMS 扩展了更多的内容类型,能够适应更广泛的应用场景和数据类型需求,如除了常见的数据签名外,还能处理带附件的消息、压缩数据等。
- 属性支持 :CMS 提供更丰富的属性集,可在签名中包含更多详细信息,如签名者证书的撤销状态、签名策略等,增强了签名数据的可验证性和可信度。
3.3 应用场景
- 复杂系统集成 :在需要处理多种数据类型和多层签名验证的复杂系统中,CMS 格式能够灵活应对,例如电子政务系统中的多部门联合签名文件、复杂的供应链系统中的产品认证信息等。
- 需高可信度的场景 :借助其丰富的属性支持,CMS 格式可用于对可信度要求高的场景,如金融交易中的电子凭证签名、法律文件的数字签名等,确保数据来源可靠、未被篡改且具有法律效力。
四、算法特定签名格式
4.1 RSA 签名格式
- PKCS#1 v1.5 :这是 RSA 签名的一种常见格式,其核心思想是直接对哈希值进行加密。具体来说,先对原始数据计算哈希值,然后使用 RSA 私钥对哈希值按 PKCS#1 v1.5 的填充规则进行加密,得到签名。在验证签名时,使用公钥解密签名数据得到哈希值,并与对原始数据重新计算的哈希值进行比对,以判断签名是否有效。
- ASN.1 结构 :通常包含 algorithm(算法标识)和 signature(签名值,为 BIT STRING 类型)两个部分。其中,algorithm 标识了所使用的哈希算法和签名算法组合,如 sha256WithRSAEncryption,让验证者清楚知道应采用何种算法进行验证;signature 则是实际的加密后的哈希值数据。
4.2 ECDSA 签名格式
- ASN.1 结构 :由 r 和 s 两个整数值组成,这两个值是通过椭圆曲线数字签名算法(ECDSA)计算得到的,分别代表了签名中的两个关键参数。在验证签名时,根据椭圆曲线的数学特性,利用 r、s 值以及签名者的公钥和原始数据的哈希值,判断签名是否有效。
- DER 编码 :严格按照 X.690 DER 规则对 ASN.1 结构进行编码,确保签名数据的标准化和一致性,便于在不同系统和平台之间进行交换和解析。
4.3 应用场景
- RSA 签名应用场景 :由于 RSA 算法的广泛应用和成熟的实现,PKCS#1 v1.5 格式的 RSA 签名常用于各种安全通信协议,如 SSL/TLS 协议中服务器证书的签名验证,以及在软件分发中对可执行文件、更新包等进行签名,确保代码来源可靠和完整性。
- ECDSA 签名应用场景 :ECDSA 算法具有在相同安全级别下密钥长度更短、签名效率更高等优点,适用于对性能和带宽要求较高的移动互联网应用、区块链技术中的交易签名等场景,既能保证安全性又能降低资源消耗。
五、X.690 DER 编码规则详解
X.690 DER 编码是 ASN.1 的一种重要编码方式,在数字签名中广泛应用,用于实现签名数据的标准化表示,确保不同系统之间能够正确理解和处理签名信息。
5.1 TLV 结构
- Tag(标签) :占用 1 字节,用于标识数据类型。例如, INTEGER(整数)、OCTET STRING(八位组字符串)、OBJECT IDENTIFIER(对象标识符)等,不同的 Tag 值对应不同类型的数据,让解析器知道如何正确解读后续的数据内容。
- Length(长度) :可占用 1 个或多个字节,用于表示 Value 部分的长度。Length 的编码方式有一定的规则,如果 Value 长度小于 128 字节,则 Length 占用 1 字节;如果长度大于等于 128 字节,则需要使用多字节编码方式,第一个字节的最高位设置为 1,后面字节表示实际长度值。
- Value(值) :是实际的数据内容,其数据类型和格式由 Tag 字段确定。例如,如果是 INTEGER 类型,则 Value 是按一定字节序编码的整数值;如果是 OCTET STRING,则是连续的字节序列。
5.2 基本规则
- 长度明确指定 :每个 TLV 结构中的 Length 字段必须明确指定 Value 的长度,这使得数据的解析过程更加准确和可靠,能够快速定位到下一个 TLV 结构的起始位置,避免数据混乱和解析错误。
- 整数最小字节数表示 :整数数据必须使用最小的字节数进行表示,这样可以节省存储空间,并且保证数据的唯一性和一致性。例如,整数值 127 应表示为 0x7F(1 字节),而不是 0x007F(2 字节)。
- 位串和八位组串填充到字节边界 :位串(BIT STRING)和八位组串(OCTET STRING)在编码时必须填充到字节边界,确保数据的对齐和完整性。对于 BIT STRING,如果实际位数不是 8 的整数倍,则需要用额外的位进行填充,并在数据中记录填充位数,以便在解码时正确还原原始位串长度和内容。
5.3 签名特定规则
- 算法标识符包含 OID 和参数 :在数字签名中,算法标识符是必不可少的部分,它必须包含对象标识符(OID)和相关参数。OID 是一个唯一的数字编码,用于标识具体的加密算法、哈希算法等,而参数则可能包括哈希算法的参数、密钥长度等信息。例如,RSA 签名算法的 OID 是 1.2.840.113549.1.1.1,其参数可能为空(对于 PKCS#1 格式的 RSA 签名)或者包含盐值等信息(对于一些增强型 RSA 签名方案)。
- 签名值必须为 BIT STRING 类型 :签名值数据在 DER 编码中必须以 BIT STRING 类型表示,这是 ASN.1 标准对签名数据的要求,确保在不同系统和平台之间的兼容性和一致性。BIT STRING 类型能够准确地表示任意长度的二进制数据,适合作为签名值的存储和传输格式。
5.4 应用场景
- 跨平台数据交换 :在不同操作系统、编程语言和设备之间进行数据交换时,X.690 DER 编码能够提供统一的数据格式,确保签名数据能够被正确解析和验证。例如,在一个由多种编程语言开发的分布式系统中,各节点通过 DER 编码的签名数据进行身份认证和数据完整性校验。
- 长期数据存档 :对于需要长期保存和后续验证的数字签名数据,如电子文档的签名、历史数据的归档等,X.690 DER 编码的标准化特性保证了数据在未来很长时间内依然能够被正确解读和验证,不会因技术和平台的变迁而失去有效性。
六、OpenSSL 中的签名生成与验证
6.1 EVP 接口签名格式
OpenSSL 的 EVP(Envelope)接口提供了一套高级的加密和签名操作函数,其生成的签名格式取决于密钥类型。
- RSA 密钥 :使用 EVP_SignFinal 函数生成的签名采用 PKCS#1 v1.5 填充的签名格式。这种格式在前面的 RSA 签名格式部分已详细介绍,其特点是通过特定的填充方式对哈希值进行加密,生成符合 PKCS#1 v1.5 标准的签名数据,便于在兼容 PKCS#1 标准的系统中进行验证和使用。
- ECDSA 密钥 :生成的签名是 DER 编码的 ASN.1 SEQUENCE(r, s)格式。这里,r 和 s 是 ECDSA 算法计算得到的两个整数参数,DER 编码确保其在不同平台和系统中的标准化表示,使得签名数据能够被正确解析和验证。
6.2 命令行工具输出格式
OpenSSL 命令行工具提供了丰富的选项,可灵活指定签名输出格式。
- 生成 PEM 格式签名 :使用 “openssl dgst -sha256 -sign private.key -out signature.pem data.txt” 命令,其中 “-sha256” 指定哈希算法为 SHA - 256,“-sign private.key” 指定使用私钥文件进行签名,“-out signature.pem” 指定输出的签名文件为 PEM 格式,“data.txt” 是待签名的数据文件。执行该命令后,生成的 signature.pem 文件将包含 PEM 格式的签名数据,以文本形式存储,包含开始和结束标记行以及 Base64 编码的签名内容。
- 生成 DER 格式签名 :通过添加 “-outform DER” 选项,如 “openssl dgst -sha256 -sign private.key -out signature.der -outform DER data.txt”,即可生成 DER 格式的签名文件 signature.der。该文件以二进制形式存储签名数据,占用空间更小,适合在对文件大小敏感的场景中使用,如嵌入式系统中的签名数据存储或网络传输中的紧凑数据表示。
6.3 应用场景
- 自动化脚本与命令行操作 :在自动化部署脚本、命令行工具链等场景中,OpenSSL 命令行工具的灵活性使其能够方便地集成到各种工作流程中。例如,在软件构建和发布过程中,通过命令行工具对可执行文件、配置文件等进行签名,确保软件分发过程中的完整性和安全性;或者在数据备份和恢复流程中,对备份数据进行签名验证,防止数据被篡改。
- 与其他系统的集成 :由于 OpenSSL 命令行工具支持多种输出格式,并且其签名格式符合广泛认可的标准,因此能够与其他加密系统、安全平台等进行无缝集成。例如,将 OpenSSL 生成的 PEM 格式签名数据导入到企业级的数字签名验证服务器中,或者将 DER 格式的签名数据提供给移动应用进行本地验证,实现跨系统的安全互操作。
七、格式转换示例
7.1 PEM 转 DER
- 命令 :“openssl base64 -d -in signature.pem -out signature.der”
- 原理 :该命令利用 OpenSSL 的 base64 解码功能,将 PEM 格式的 signature.pem 文件中的 Base64 编码数据解码为原始的二进制 DER 编码数据,并输出到 signature.der 文件中。其中,“-d” 选项表示进行解码操作,“-in” 指定输入文件,“-out” 指定输出文件。
7.2 DER 转 PEM
- 命令 :“openssl base64 -in signature.der -out signature.pem”
- 原理 :这里使用 OpenSSL 的 base64 编码功能,将 DER 格式的 signature.der 文件中的二进制数据进行 Base64 编码,转换为文本形式的 PEM 格式数据,并输出到 signature.pem 文件中。通过这种方式,可以方便地在 PEM 和 DER 格式之间进行转换,满足不同场景下对签名格式的需求。
7.3 应用场景
- 格式适配与兼容性处理 :在不同系统和应用之间进行数据交换时,有时需要对签名格式进行转换以满足接收方的要求。例如,某一系统要求以 PEM 格式提供签名数据,而签名数据最初是以 DER 格式生成的,此时通过上述转换命令可快速完成格式适配,确保数据的顺利传输和处理。
- 数据存储与传输优化 :在存储签名数据时,可根据存储介质的特点和存储策略选择合适的格式。如对于需要频繁人工查看和编辑的存储场景,可将 DER 格式的签名数据转换为 PEM 格式;而对于大量自动化存储且对空间敏感的场景,则可将 PEM 格式转换为 DER 格式以节省存储空间。在数据传输过程中,也可根据网络带宽和传输协议的要求,灵活转换签名格式,优化传输效率。
八、签名属性(SignedAttributes)详解
在 CMS 格式中,签名属性(SignedAttributes)是其重要的组成部分,提供了丰富的附加信息。
8.1 常见属性类型
- content - type(1.2.840.113549.1.9.3) :标识被签名内容的类型,如数据、证书、CRL 等。这有助于接收方了解签名所针对的对象类型,从而采取相应的处理和验证策略。例如,如果 content - type 表示的是一个可执行文件,则接收方可能会对其安全性进行更严格的审查和验证。
- message - digest(1.2.840.113549.1.9.4) :包含内容的哈希值,用于在验证签名时快速核对数据的完整性。通过将本地计算的哈希值与签名属性中的 message - digest 值进行比对,可迅速判断数据是否在传输过程中被篡改,提高了验证效率。
- signing - time(1.2.840.113549.1.9.5) :记录签名时间戳,精确到秒。这在法律和商务场景中具有重要意义,能够证明数据在特定时间点已经存在且未被修改,对于合同签署、电子证据保全等应用可提供有力的时间证明。
- countersignature(1.2.840.113549.1.9.6) :即副签名,用于对原始签名进行再次签名,通常由不同的签名者完成。副签名可用于扩展签名的可信度和权威性,例如在一个企业内部审批流程中,先由部门负责人对文件进行签名,然后由法务部门进行副签名,以确保文件同时符合业务和法律要求。
8.2 应用场景
- 复杂的业务流程与审批环节 :在涉及多个部门、多个环节的复杂业务流程中,通过使用签名属性中的副签名等功能,能够清晰地记录每个环节的审批和签名情况,确保业务流程的完整性和可追溯性。例如,在一个大型项目的合同签署过程中,可能需要经过技术、商务、法务等多个部门的审核和签名,每个部门的签名及其时间戳等信息都可通过签名属性进行记录和验证。
- 电子证据保全与司法鉴定 :在电子证据保全和司法鉴定领域,签名属性中的内容类型、消息摘要、签名时间戳等信息是判断证据真实性和可信度的重要依据。通过这些属性,能够准确还原电子证据的产生、传输和存储过程,为司法鉴定提供可靠的技术支持,确保电子证据在法律程序中的有效性和权威性。
综上所述,OpenSSL 支持的多种数字签名格式各有特点和适用场景。在实际应用中,开发者应根据具体需求,如数据存储和传输的效率、系统的兼容性、签名的复杂性和可信度要求等因素,合理选择和使用签名格式,并借助 OpenSSL 提供的丰富接口和工具进行签名的生成、验证和格式转换,以实现安全、高效、可靠的数字签名应用,保障数据的安全性和完整性。