如何使用 pyasn1 创建一个 GeneralName?
How to create a GeneralName with pyasn1?
作为 pyasn1(pyasn1 0.4.8,pyasn1-modules 0.2.8)和 ASN.1 的新手,我正在尝试构建一个 GeneralName
:
>>> from pyasn1.codec.der.encoder import encode
>>> from pyasn1.type import char
>>> from pyasn1_modules import rfc2459
>>> from pyasn1_modules.rfc2459 import (
... AttributeTypeAndValue, GeneralName, Name, RelativeDistinguishedName, RDNSequence)
>>>
>>> rdn = RelativeDistinguishedName()
>>> attr_type_and_value = AttributeTypeAndValue()
>>> attr_type_and_value['type'] = rfc2459.id_at_countryName
>>> attr_type_and_value['value'] = encode(char.UTF8String('DE'))
>>> rdn.append(attr_type_and_value)
>>>
>>> rdn_sequence = RDNSequence()
>>> rdn_sequence.append(rdn)
>>>
>>> name = Name()
>>> name[0] = rdn_sequence
>>>
>>> general_name = GeneralName()
>>> general_name['directoryName'] = name
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2246, in __setitem__
self.setComponentByName(idx, value)
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2413, in setComponentByName
idx, value, verifyConstraints, matchTags, matchConstraints
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 3119, in setComponentByPosition
Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints)
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2601, in setComponentByPosition
raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType))
pyasn1.error.PyAsn1Error: Component value is tag-incompatible: <Name value object, tagSet=<TagSet object, untagged>, [...]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2250, in __setitem__
raise KeyError(sys.exc_info()[1])
KeyError: PyAsn1Error('Component value is tag-incompatible: <Name value object, tagSet=<TagSet object, untagged>, [...]
我截断了很长的异常消息。据我了解,本质是提供的 Name 对象未标记,而某些标记是预期的。我可以通过使用 general_name.setComponentByName('directoryName', name, matchTags=False)
来解决异常,但我不确定这是否会关闭 desired/important 检查并在稍后会咬我。 pyasn1 Tag
和 TagSet
文档没有启发我,但这可能是因为我还没有真正理解 ASN.1 中标签的用途。
所以,我的主要问题是:如何使用 pyasn1 正确创建 GeneralName
?子问题:
- ASN.1 中标签的用途是什么?我将它们视为类型说明符(如:"this is an integer, boolean, sequence, etc."),但显然我遗漏了一些东西。
- 我用的是
UTF8String
。解码使用 OpenSSL 创建的时间戳响应,我发现在 GeneralName
中使用了 PrintableString
。我凭直觉选择了前者,但这会导致问题吗(取决于使用环境)?
我认为这是 pyasn1 的错误或限制
不知是否与此有关:https://github.com/etingof/pyasn1/issues/179
spec 说
GeneralName ::= CHOICE {
otherName [0] OtherName,
rfc822Name [1] IA5String,
dNSName [2] IA5String,
x400Address [3] ORAddress,
directoryName [4] Name,
ediPartyName [5] EDIPartyName,
uniformResourceIdentifier [6] IA5String,
iPAddress [7] OCTET STRING,
registeredID [8] OBJECT IDENTIFIER}
Name ::= CHOICE { -- only one possibility for now --
rdnSequence RDNSequence }
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
对于 ASN.1,通常有一个生成一些代码的编译步骤。使用 pyasn1,您要么自己编写代码,要么包含一些模块。
当您包含 pyasn1_modules.rfc2459 时,唯一的工作就是使用 类。
你的文看起来很合法
>>> rdn_sequence = RDNSequence()
>>> rdn_sequence.append(rdn)
>>>
>>> name = Name()
>>> name[0] = rdn_sequence
>>>
>>> general_name = GeneralName()
>>> general_name['directoryName'] = name
但是pyasn1好像只允许shorthand访问
>>> rdn_sequence = RDNSequence()
>>> rdn_sequence.append(rdn)
>>>
>>> general_name = GeneralName()
>>> general_name['directoryName'][''] = rdn_sequence
我认为两者都应该被允许...
关于标签:因为您使用的是 pyasn1 模块,所以您不必担心它们。当编码形式为Tag/Length/Value(So,BER、CER 和 DER ASN.1 编码规则)时,需要它们对消息进行编码。
至于类型(如 UTF8String):您不能更改它们,它们必须是您从 ASN.1 规范中读取的类型。他们有一个与之关联的(所谓的通用)标签,接收者不会理解您的编码消息。
请注意,Name 的实现与规范之间存在细微差异(规范具有命名的 Type,而实现没有名称)。这在过去是允许的。
class Name(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('', RDNSequence())
)
但我认为这不是问题。
作为 pyasn1(pyasn1 0.4.8,pyasn1-modules 0.2.8)和 ASN.1 的新手,我正在尝试构建一个 GeneralName
:
>>> from pyasn1.codec.der.encoder import encode
>>> from pyasn1.type import char
>>> from pyasn1_modules import rfc2459
>>> from pyasn1_modules.rfc2459 import (
... AttributeTypeAndValue, GeneralName, Name, RelativeDistinguishedName, RDNSequence)
>>>
>>> rdn = RelativeDistinguishedName()
>>> attr_type_and_value = AttributeTypeAndValue()
>>> attr_type_and_value['type'] = rfc2459.id_at_countryName
>>> attr_type_and_value['value'] = encode(char.UTF8String('DE'))
>>> rdn.append(attr_type_and_value)
>>>
>>> rdn_sequence = RDNSequence()
>>> rdn_sequence.append(rdn)
>>>
>>> name = Name()
>>> name[0] = rdn_sequence
>>>
>>> general_name = GeneralName()
>>> general_name['directoryName'] = name
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2246, in __setitem__
self.setComponentByName(idx, value)
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2413, in setComponentByName
idx, value, verifyConstraints, matchTags, matchConstraints
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 3119, in setComponentByPosition
Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints)
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2601, in setComponentByPosition
raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType))
pyasn1.error.PyAsn1Error: Component value is tag-incompatible: <Name value object, tagSet=<TagSet object, untagged>, [...]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/site-packages/pyasn1/type/univ.py", line 2250, in __setitem__
raise KeyError(sys.exc_info()[1])
KeyError: PyAsn1Error('Component value is tag-incompatible: <Name value object, tagSet=<TagSet object, untagged>, [...]
我截断了很长的异常消息。据我了解,本质是提供的 Name 对象未标记,而某些标记是预期的。我可以通过使用 general_name.setComponentByName('directoryName', name, matchTags=False)
来解决异常,但我不确定这是否会关闭 desired/important 检查并在稍后会咬我。 pyasn1 Tag
和 TagSet
文档没有启发我,但这可能是因为我还没有真正理解 ASN.1 中标签的用途。
所以,我的主要问题是:如何使用 pyasn1 正确创建 GeneralName
?子问题:
- ASN.1 中标签的用途是什么?我将它们视为类型说明符(如:"this is an integer, boolean, sequence, etc."),但显然我遗漏了一些东西。
- 我用的是
UTF8String
。解码使用 OpenSSL 创建的时间戳响应,我发现在GeneralName
中使用了PrintableString
。我凭直觉选择了前者,但这会导致问题吗(取决于使用环境)?
我认为这是 pyasn1 的错误或限制
不知是否与此有关:https://github.com/etingof/pyasn1/issues/179
spec 说
GeneralName ::= CHOICE {
otherName [0] OtherName,
rfc822Name [1] IA5String,
dNSName [2] IA5String,
x400Address [3] ORAddress,
directoryName [4] Name,
ediPartyName [5] EDIPartyName,
uniformResourceIdentifier [6] IA5String,
iPAddress [7] OCTET STRING,
registeredID [8] OBJECT IDENTIFIER}
Name ::= CHOICE { -- only one possibility for now --
rdnSequence RDNSequence }
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
对于 ASN.1,通常有一个生成一些代码的编译步骤。使用 pyasn1,您要么自己编写代码,要么包含一些模块。
当您包含 pyasn1_modules.rfc2459 时,唯一的工作就是使用 类。
你的文看起来很合法
>>> rdn_sequence = RDNSequence()
>>> rdn_sequence.append(rdn)
>>>
>>> name = Name()
>>> name[0] = rdn_sequence
>>>
>>> general_name = GeneralName()
>>> general_name['directoryName'] = name
但是pyasn1好像只允许shorthand访问
>>> rdn_sequence = RDNSequence()
>>> rdn_sequence.append(rdn)
>>>
>>> general_name = GeneralName()
>>> general_name['directoryName'][''] = rdn_sequence
我认为两者都应该被允许...
关于标签:因为您使用的是 pyasn1 模块,所以您不必担心它们。当编码形式为Tag/Length/Value(So,BER、CER 和 DER ASN.1 编码规则)时,需要它们对消息进行编码。
至于类型(如 UTF8String):您不能更改它们,它们必须是您从 ASN.1 规范中读取的类型。他们有一个与之关联的(所谓的通用)标签,接收者不会理解您的编码消息。
请注意,Name 的实现与规范之间存在细微差异(规范具有命名的 Type,而实现没有名称)。这在过去是允许的。
class Name(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('', RDNSequence())
)
但我认为这不是问题。