仍然与ASN1混淆。我正在使用ruby openssl解析RFC3161时间戳响应,因此我知道该规范。我很确定结构可以正确加载,但是我对如何找到想要的片段/键感到困惑。我知道有序列(有序)和集合(无序/唯一)。
我看到我们可以调用asn1_object.value[0].value[0]
,但这很笨拙,我希望如果我知道键或标头,就可以将其视为JSON或YAML并只需调用 {{ 1}}。 这种方式行不通吗?
我们是否应该使用序列的属性,因为我们也有规范和长度,所以它们应该顺序排列并知道它们的位置?这对我来说很奇怪,但这也许是因为我之前没有使用过很多TLV格式。不幸的是,openssl的文档很少,只是如何使用asn1_object['TSTInfo']['serialNumber']
加载对象并按索引访问值。还有OpenSSL::ASN1.decode(der)
方法,但这不会产生标头名称或在这种情况下我想使用的任何名称。
traverse
答案 0 :(得分:0)
Openssl.ASN1.decode(der)正在利用DER的规范性质从线路数据中重建结构,并且根本不使用ASN.1模式。因此,虽然它可以根据从导线数据中读取的内容推断出该结构的形状,组成和内容(特别是如果使用显式标记进行编码,并且还给出了数据类型),但是却不知道字段名称是什么在原始模式中(这些不在有线格式数据中)。
如果您查看RFC3161时间戳的原始ASN.1模式,则可以确定哪些字段在哪里。
将ASN.1与C / C ++,Java和C#一起使用通常使用ASN.1编译器生成源代码。此源代码定义了包含具有字段名称的类的类,这些字段名称取自架构。抱歉,我不知道这在Ruby的Openssl.ASN1中是否可行
隐式/显式。
您提供的链接示例在隐式标记示例中略有自由。它将值解释为整数;严格来说,应将其解释为要解码的更多ASN.1。碰巧这些字节是整数。
答案 1 :(得分:0)
让我在这里澄清一些事情;我刚刚发现了一个矛盾。
OP 说他 knows the specification
但也提到 the signingTime value is two below the declaration
是 strange
。
这使我得出结论,OP 意味着他知道格式是由规范引起的,但实际上并不知道规范本身。
让我们一起阅读其中的一些内容,以便您掌握诀窍。
让我们回答一下为什么会有时间价值?
签署时间在RFC5652 section 11.3中提到;从那里,我们将知道它是一种属性(因为它在第 11 节下)。属性类型的结构在section 5.3
的同一个文档中也有提到 <块引用>属性::=序列{
attrType 对象标识符,
attrValues 属性值集 }
所以它基本上是一个对象标识符后跟一个集合的序列。
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
一旦你知道了格式,就可以开始破解了。