0

仍然对 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>]>]>
4

2 回答 2

0

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

让我们一起阅读其中一些,这样你就会知道如何做。
让我们回答为什么有时间价值的问题?

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

属性 ::= SEQUENCE {
attrType OBJECT IDENTIFIER,
attrValues SET OF AttributeValue }

所以它基本上是一个对象标识符的序列,后跟一个集合。
第 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

一旦你知道了格式,开始破解东西就相当简单了。

于 2021-02-09T16:59:25.093 回答
0

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

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

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

含蓄的,明确的。

您提供链接的示例对隐式标记示例稍有随意性。它将值解释为整数;严格来说它应该被解释为更多的 ASN.1 被解码。碰巧这些字节是一个整数。

于 2018-12-18T23:35:07.730 回答