OpenSSL::ASN1
模块 OpenSSL :: ASN1
抽象语法记法一(或 ASN.1)是一种用于描述数据结构的记法语法,并在 ITU-T X.680 中进行了定义。ASN.1 本身并不要求任何编码或解析规则,但通常 ASN.1数据结构使用专有编码规则(DER)进行编码,或者通常使用 ITU-T X.690中描述的基本编码规则(BER)进行编码。DER 和 BER 编码是二进制标签长度值(TLV)编码,与其他流行的数据描述格式(如XML,JSON等)相比,编码非常简洁。ASN.1 数据结构在密码应用中非常常见,例如X.509 public密钥证书或证书撤销列表(CRL)都在ASN.1和DER编码中定义。ASN.1,DER 和 BER 是应用密码学的基石。ASN1 模块提供了允许生成 ASN 的必要类。1数据结构以及使用 DER 编码对它们进行编码的方法。解码方法允许将任意的 BER / DER 编码数据解析到 Ruby 对象,然后可以随意修改和重新编码。
ASN.1 类层次结构
表示 ASN.1结构的基类是 ASN1Data。ASN1Data 提供属性读取和设置tag
,在tag_class
最后的value
一个特定的 ASN.1项目。解析后,任何标记值(隐式或显式)将由 ASN1Data 实例表示,因为它们的“真实类型”只能使用来自 ASN.1类型声明的带外信息来确定。由于这种信息在编码类型时通常是已知的,所以 ASN1Data 的所有子类都提供了一个附加属性tagging
,允许隐式地(:IMPLICIT
)或显式地(:EXPLICIT
)对一个值进行编码。
建设性
顾名思义,构造型就是所有构造编码的基类,即那些由多个值组成的编码,与只有一个单一值的“原始”编码相反。通常构造以“无限长度”编码的原始值(它们的值以多个块形式出现),并且因此由建构性的实例表示。一个 Constructive 的值总是一个 Array。
ASN1 :: Set 和 ASN1 :: Sequence
最常见的建设性编码是 SET 和 SEQUENCE,这就是为什么有两个表示它们的 Constructive 的子类。
原始
这是所有原始值的超类。在解析 ASN.1数据时,不使用 Primitive 本身,所有值都是 Primitive 相应子类的实例,或者如果值隐式或显式标记,则它们是 ASN1Data 的实例。请参阅 本原始文档详细介绍子类及其各自映射到 Ruby 对象的 ASN.1数据类型。
可能的值 tagging
在构建 ASN1Data 对象时,ASN.1 类型定义可能需要某些元素隐式或显式标记。这可以通过tagging
为 ASN1Data 的子类手动设置属性来实现。使用该符号:IMPLICIT
进行隐式标记,:EXPLICIT
并且该元素需要显式标记。
tag_class可能的值
可以创建也支持 PRIVATE 或 APPLICATION 标记类的任意 ASN1Data 对象。该tag_class
属性的可能值为:
:UNIVERSAL
(未标记值的默认值)
:CONTEXT_SPECIFIC
(标记值的默认值)
:APPLICATION
:PRIVATE
标记常量
每个通用标签都有一个常数定义:
- OpenSSL::ASN1::EOC (0)
- OpenSSL::ASN1::BOOLEAN (1)
- OpenSSL::ASN1::INTEGER (2)
- OpenSSL::ASN1::BIT_STRING (3)
- OpenSSL::ASN1::OCTET_STRING (4)
- OpenSSL::ASN1::NULL (5)
- OpenSSL::ASN1::OBJECT (6)
- OpenSSL::ASN1::ENUMERATED (10)
- OpenSSL::ASN1::UTF8STRING (12)
- OpenSSL::ASN1::SEQUENCE (16)
- OpenSSL::ASN1::SET (17)
- OpenSSL::ASN1::NUMERICSTRING (18)
- OpenSSL::ASN1::PRINTABLESTRING (19)
- OpenSSL::ASN1::T61STRING (20)
- OpenSSL::ASN1::VIDEOTEXSTRING (21)
- OpenSSL::ASN1::IA5STRING (22)
- OpenSSL::ASN1::UTCTIME (23)
- OpenSSL::ASN1::GENERALIZEDTIME (24)
- OpenSSL::ASN1::GRAPHICSTRING (25)
- OpenSSL::ASN1::ISO64STRING (26)
- OpenSSL::ASN1::GENERALSTRING (27)
- OpenSSL::ASN1::UNIVERSALSTRING (28)
- OpenSSL::ASN1::BMPSTRING (30)UNIVERSAL_TAG_NAME constantAn Array that stores the name of a given tag number. These names are the same as the name of the tag constant that is additionally defined, e.g. UNIVERSAL_TAG_NAME = “INTEGER” and OpenSSL::ASN1::INTEGER = 2.Example usageDecoding and viewing a DER-encoded filerequire 'openssl' require 'pp' der = File.binread('data.der') asn1 = OpenSSL::ASN1.decode(der) pp derCreating an ASN.1 structure and DER-encoding itrequire '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_derConstantsUNIVERSAL_TAG_NAME Array storing tag names at the tag's index.Public Class Methods OpenSSL::ASN1.decode(der) → ASN1Data Show source Decodes a BER- or DER-encoded value and creates an ASN1Data instance. der may be a String or any object that features a #to_der method transforming it into a BER-/DER-encoded String.Exampleder = File.binread('asn1data') asn1 = OpenSSL::ASN1.decode(der)static VALUE ossl_asn1_decode(VALUE self, VALUE obj) { VALUE ret; unsigned char *p; VALUE tmp; long len, read = 0, offset = 0; obj = ossl_to_der_if_possible(obj tmp = rb_str_new4(StringValue(obj) p = (unsigned char *)RSTRING_PTR(tmp len = RSTRING_LEN(tmp ret = ossl_asn1_decode0(&p, len, &offset, 0, 0, &read RB_GC_GUARD(tmp int_ossl_decode_sanity_check(len, read, offset return ret; } OpenSSL::ASN1.decode_all(der) → Array of ASN1Data Show source Similar to decode with the difference that decode expects one distinct value represented in der. decode_all on the contrary decodes a sequence of sequential BER/DER values lined up in der and returns them as an array.Exampleders = File.binread('asn1data_seq') asn1_ary = OpenSSL::ASN1.decode_all(ders)static VALUE ossl_asn1_decode_all(VALUE self, VALUE obj) { VALUE ary, val; unsigned char *p; long len, tmp_len = 0, read = 0, offset = 0; VALUE tmp; obj = ossl_to_der_if_possible(obj tmp = rb_str_new4(StringValue(obj) p = (unsigned char *)RSTRING_PTR(tmp len = RSTRING_LEN(tmp tmp_len = len; ary = rb_ary_new( while (tmp_len > 0) { long tmp_read = 0; val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read rb_ary_push(ary, val read += tmp_read; tmp_len -= tmp_read; } RB_GC_GUARD(tmp int_ossl_decode_sanity_check(len, read, offset return ary; } OpenSSL::ASN1.traverse(asn1) → nil Show source If a block is given, it prints out each of the elements encountered. Block parameters are (in that order):
- 深度:递归深度,加上遇到的每个构造的值(数字)
- 偏移量:当前字节偏移量(数字)
- 标题长度:标记和长度标题的组合长度(以字节为单位)。(数)
- 长度:整个数据的总体剩余长度(数量)
- 构造:该值是否构造(布尔)
- tag_class:当前标签类(符号)
- 标签:当前标签(数量)
示例
der = File.binread('asn1data.der')
OpenSSL::ASN1.traverse(der) do | depth, offset, header_len, length, constructed, tag_class, tag|
puts "Depth: #{depth} Offset: #{offset} Length: #{length}"
puts "Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}"
end
static VALUE
ossl_asn1_traverse(VALUE self, VALUE obj)
{
unsigned char *p;
VALUE tmp;
long len, read = 0, offset = 0;
obj = ossl_to_der_if_possible(obj
tmp = rb_str_new4(StringValue(obj)
p = (unsigned char *)RSTRING_PTR(tmp
len = RSTRING_LEN(tmp
ossl_asn1_decode0(&p, len, &offset, 0, 1, &read
RB_GC_GUARD(tmp
int_ossl_decode_sanity_check(len, read, offset
return Qnil;
}