Ruby 2.4
OpenSSL

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; }