【问题标题】:How to parse ASN1 in Ruby如何在 Ruby 中解析 A​​SN1
【发布时间】:2018-12-18 20:13:56
【问题描述】:

仍然对 ASN1 有点困惑。我正在使用 ruby​​ openssl 解析 RFC3161 时间戳响应,所以我知道规范。我很确定结构已正确加载,但我对如何找到我想要的部件/键感到困惑。我知道有序列(有序)和集合(无序/唯一)。

我知道我们可以调用 asn1_object.value[0].value[0],但这很笨拙,我希望如果我知道键或标题,我可以将其视为 JSON 或 YAML,然后调用 asn1_object['TSTInfo']['serialNumber']这样不行吗?

我们是否应该使用预期有序的序列属性并且已经知道它们的位置,因为我们也有规范和长度?这对我来说很奇怪,但也许那是因为我以前没有使用过很多 TLV 格式。不幸的是,openssl 的文档很少,只是如何使用OpenSSL::ASN1.decode(der) 加载对象并通过索引访问值。还有traverse 方法,但这不会产生标题名称或我认为在这种情况下使用的任何东西。

                #<OpenSSL::ASN1::Sequence:0x000055fdee1a2c68
                   @indefinite_length=false,
                   @tag=16,
                   @tag_class=:UNIVERSAL,
                   @tagging=nil,
                   @value=
                    [#<OpenSSL::ASN1::ObjectId:0x000055fdee1a2ec0
                      @indefinite_length=false,
                      @tag=6,
                      @tag_class=:UNIVERSAL,
                      @tagging=nil,
                      @value="1.2.840.113549.1.9.52">,
                     #<OpenSSL::ASN1::Set:0x000055fdee1a2c90
                      @indefinite_length=false,
                      @tag=17,
                      @tag_class=:UNIVERSAL,
                      @tagging=nil,
                      @value=
                       [#<OpenSSL::ASN1::Sequence:0x000055fdee1a2cb8
                         @indefinite_length=false,
                         @tag=16,
                         @tag_class=:UNIVERSAL,
                         @tagging=nil,
                         @value=
                        [#<OpenSSL::ASN1::Sequence:0x000055fdee1a2da8
                            @indefinite_length=false,
                            @tag=16,
                            @tag_class=:UNIVERSAL,
                            @tagging=nil,
                            @value=

                   @value=
                    [#<OpenSSL::ASN1::ObjectId:0x000055fdee1a3190
                      @indefinite_length=false,
                      @tag=6,
                      @tag_class=:UNIVERSAL,
                      @tagging=nil,
                      @value="signingTime">,
                     #<OpenSSL::ASN1::Set:0x000055fdee1a30f0
                      @indefinite_length=false,
                      @tag=17,
                      @tag_class=:UNIVERSAL,
                      @tagging=nil,
                      @value=
                       [#<OpenSSL::ASN1::UTCTime:0x000055fdee1a3118
                         @indefinite_length=false,
                         @tag=23,
                         @tag_class=:UNIVERSAL,
                         @tagging=nil,
                         @value=2018-12-19 01:49:08 UTC>]>]>

【问题讨论】:

  • 你能告诉我们定义ans1_object的代码吗?
  • @SaraTibbetts 我从here使用asn1 = OpenSSL::ASN1.decode(der)
  • 我认为主要问题是它们是否应该像 JSON/YAML 那样被访问(可能不是)。如果没有,我不熟悉在 ASN1 结构中找到所需内容的最佳方法。

标签: ruby serialization openssl tlv asn.1


【解决方案1】:

您链接到的示例中的 Openssl.ASN1.decode(der) 正在利用 DER 的规范性质从有线数据重建结构,并且根本不使用 ASN.1 模式。因此,虽然它可以从它从有线数据中读取的内容中推断出该结构的形状、组成和内容(特别是如果它使用显式标记进行编码,这也给出了数据类型),但它不知道字段名称是什么在原始模式中(这些不是有线格式数据)。

如果您查看 RFC3161 时间戳的原始 ASN.1 架构,您可以计算出哪些字段在哪里。

将 ASN.1 与 C/C++、Java 和 C# 一起使用通常使用 ASN.1 编译器来生成源代码。此源代码定义的类包含字段名称取自模式的字段。抱歉,我不知道这在 Ruby 的 Openssl.ASN1 中是否可行

隐式/显式。

您提供链接的示例与隐式标记示例略有不同。它将值解释为整数;严格来说它应该被解释为更多的 ASN.1 被解码。这些字节恰好是整数。

【讨论】:

  • 感谢您浏览此处。你怎么知道它是 DER 编码的(不是更受欢迎的选择)?这是在 java bouncy castle 中创建的,但它没有说明 getEncoded() 的编码 here
  • 另见更新打印输出。这是从数据的大约一半开始,我可以挑选出一些数据,但它仍然接近无意义。我还没有找到 'serialNumber' 或 'genTime',虽然有 'signingTIme'.... 并且 signingTime 值比声明低两个。奇怪。
  • @user8897013,不用担心。碰巧我不知道 RFC3161 使用了 DER,尽管查看了 RFC 本身,似乎使用的是 DER。您链接到的示例代码正在处理 DER,这就是我主要指的,看来我很幸运!
  • @user8897013 如果您查看ietf.org/rfc/rfc3161.txt 的附录 C,您可以看到 RFC3161 的整个 ASN.1 架构。 ASN.1 模式语法很容易遵循。此模式中定义的类型之一将用于您正在解码的数据:TimeStampResp?请注意,此架构从其他架构导入内容,我猜这些架构在更广泛的 PKI 规范中的其他地方定义。
【解决方案2】:

让我在这里澄清一点;我只是发现了一个矛盾。 OP说他knows the specification但也提到the signingTime value is two below the declarationstrange
这使我得出结论,OP 意味着他知道格式是由于规范,但实际上并不知道规范本身。

让我们一起阅读其中的一些内容,以便了解相关知识。
让我们回答一下为什么会有时间价值的问题?

签名时间在RFC5652 section 11.3中提到;从那里,我们将知道它是一种属性(因为它在第 11 节下)。属性类型的结构在section 5.3的同一篇文档中也有提及

属性 ::= SEQUENCE {
attrType 对象标识符,
attrValues SET OF AttributeValue }

所以它基本上是一个对象标识符后跟一个集合的序列。
Section 11.3 还指定该集合必须恰好包含 1 个成员。

这正是我们在这里看到的:

[
  #<OpenSSL::ASN1::ObjectId:0x000055fdee1a3190
    @indefinite_length=false,
    @tag=6,
    @tag_class=:UNIVERSAL,
    @tagging=nil,
    @value="signingTime">,
  #<OpenSSL::ASN1::Set:0x000055fdee1a30f0
    @indefinite_length=false,
    @tag=17,
    @tag_class=:UNIVERSAL,
    @tagging=nil,
    @value=[
      #<OpenSSL::ASN1::UTCTime:0x000055fdee1a3118
        @indefinite_length=false,
        @tag=23,
        @tag_class=:UNIVERSAL,
        @tagging=nil,
        @value=2018-12-19 01:49:08 UTC>
    ]>
]

如前所述,OpenSSL::ASN1.decode 将 der 解码为结构化的 ruby​​ 对象,并没有考虑每个字段的含义。因此,您需要阅读规范并自己计算字段。这很乏味,但无论如何都不是不可能的。

由于官方库提供的遍历函数基本没用,所以我自己实现了。不过,它仍然只是一个工作原型。

class TraverseASN1
  class StopIteration < ::StandardError
    def initialize(result = nil)
      super(nil)
      @result = result
    end

    attr_reader :result
  end

  def call(
    decoded,
    _depth: 0,
    _sequence: nil,
    _parents: [],
    &traversal_block
  )
    traversal_block.call(
      decoded,
      depth: _depth,
      sequence: _sequence,
      parents: _parents
    )
    value = decoded.value
    return unless value.is_a?(::Array)
    value.each_with_index do |sub_token, sequence|
      call(
        sub_token,
        _depth: (_depth + 1),
        _sequence: sequence,
        _parents: [*_parents, decoded],
        &traversal_block
      )
    end
  end
end

这就是我使用它的方式:

target_element = begin
  TraverseASN1.new.call(asn1) do |current, depth:, parents:, **_unused_args|
    next unless depth == 2
    next unless current.is_a?(::OpenSSL::ASN1::ObjectId)
    next unless current.value == 'pkcs7-signedData'
    raise TraverseASN1::StopIteration.new(parents.last)
  end
rescue TraverseASN1::StopIteration => e
  e.result
end

一旦你知道了格式,就很容易开始破解了。

【讨论】:

    猜你喜欢
    • 2011-02-22
    • 2010-09-17
    • 2011-07-30
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 2017-04-27
    相关资源
    最近更新 更多