模块 OpenSSL::ASN1

抽象语法表示法一 (ASN.1) 是一种用于描述数据结构的表示法语法,定义于 ITU-T X.680。ASN.1 本身不强制任何编码或解析规则,但通常 ASN.1 数据结构使用 ITU-T X.690 中描述的“可区分”编码规则 (DER) 或较少使用的基本编码规则 (BER) 进行编码。与 XML、JSON 等其他流行的类似数据描述格式相比,DER 和 BER 编码是相当简洁的二进制标签-长度-值 (TLV) 编码。ASN.1 数据结构在加密应用中非常常见,例如 X.509 公钥证书或证书撤销列表 (CRL) 都是在 ASN.1 中定义并进行 DER 编码的。ASN.1、DER 和 BER 是应用密码学的基石。ASN1 模块提供了必要的类,允许生成 ASN.1 数据结构并使用 DER 编码对它们进行编码。decode 方法允许将任意 BER/DER 编码的数据解析为 Ruby 对象,然后可以随意修改和重新编码。

ASN.1 类层次结构

表示 ASN.1 结构体的基类是 ASN1DataASN1Data 提供属性来读取和设置特定 ASN.1 项的tagtag_class 和最终的value。在解析时,任何标记的值(隐式或显式)都将由 ASN1Data 实例表示,因为它们的“真实类型”只能使用来自 ASN.1 类型声明的带外信息来确定。由于此信息在编码类型时通常已知,因此 ASN1Data 的所有子类都提供一个额外的属性 tagging,允许隐式 (:IMPLICIT) 或显式 (:EXPLICIT) 编码值。

Constructive

Constructive,顾名思义,是所有构造编码的基类,即由多个值组成的编码,与只有一个值的“基本”编码相反。Constructive 的值始终是 Array

ASN1::Set 和 ASN1::Sequence

最常见的构造编码是 SET 和 SEQUENCE,这就是为什么有两个 Constructive 的子类来表示它们每个的原因。

Primitive

这是所有基本值的超类。解析 ASN.1 数据时不会使用 Primitive 本身,所有值都是 Primitive 的相应子类的实例,或者如果值是隐式或显式标记的,则它们是 ASN1Data 的实例。请参阅 Primitive 文档,了解有关子类及其各自的 ASN.1 数据类型到 Ruby 对象映射的详细信息。

tagging 的可能值

在构造 ASN1Data 对象时,ASN.1 类型定义可能要求某些元素被隐式或显式标记。这可以通过手动设置 ASN1Data 子类的 tagging 属性来实现。如果元素需要显式标记,请使用符号 :IMPLICIT 进行隐式标记,使用 :EXPLICIT

tag_class 的可能值

可以创建也支持 PRIVATE 或 APPLICATION 标签类的任意 ASN1Data 对象。tag_class 属性的可能值是

标签常量

为每个通用标签定义了一个常量

UNIVERSAL_TAG_NAME 常量

一个 Array,用于存储给定标签号的名称。这些名称与另外定义的标签常量的名称相同,例如 UNIVERSAL_TAG_NAME[2] = "INTEGER"OpenSSL::ASN1::INTEGER = 2

用法示例

解码和查看 DER 编码的文件

require 'openssl'
require 'pp'
der = File.binread('data.der')
asn1 = OpenSSL::ASN1.decode(der)
pp der

创建 ASN.1 结构并进行 DER 编码

require 'openssl'
version = OpenSSL::ASN1::Integer.new(1)
# Explicitly 0-tagged implies context-specific tag class
serial = OpenSSL::ASN1::Integer.new(12345, 0, :EXPLICIT, :CONTEXT_SPECIFIC)
name = OpenSSL::ASN1::PrintableString.new('Data 1')
sequence = OpenSSL::ASN1::Sequence.new( [ version, serial, name ] )
der = sequence.to_der