如何使用 pyasn1 解析 subjectAltName 扩展数据?
我有 pyOpenSSL 给我的一些数据,'0\r\x82\x0bexample.com'
。这应该是 subjectAltName X509 扩展的值。我尝试使用 pyasn1 对此扩展的 ASN1 规范的必要部分进行编码(并基于 pyasn1 示例之一):
from pyasn1.type import univ, constraint, char, namedtype
from pyasn1.codec.der.decoder import decode
MAX = 64
class DirectoryString(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType(
'teletexString', char.TeletexString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'printableString', char.PrintableString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'universalString', char.UniversalString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'utf8String', char.UTF8String().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'bmpString', char.BMPString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'ia5String', char.IA5String().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
)
class AttributeValue(DirectoryString):
pass
class AttributeType(univ.ObjectIdentifier):
pass
class AttributeTypeAndValue(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('value', AttributeValue()),
)
class RelativeDistinguishedName(univ.SetOf):
componentType = AttributeTypeAndValue()
class RDNSequence(univ.SequenceOf):
componentType = RelativeDistinguishedName()
class Name(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('', RDNSequence()),
)
class Extension(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('extnID', univ.ObjectIdentifier()),
namedtype.DefaultedNamedType('critical', univ.Boolean('False')),
namedtype.NamedType('extnValue', univ.OctetString()),
)
class Extensions(univ.SequenceOf):
componentType = Extension()
sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
class GeneralName(univ.Choice):
componentType = namedtype.NamedTypes(
# namedtype.NamedType('otherName', AnotherName()),
namedtype.NamedType('rfc822Name', char.IA5String()),
namedtype.NamedType('dNSName', char.IA5String()),
# namedtype.NamedType('x400Address', ORAddress()),
namedtype.NamedType('directoryName', Name()),
# namedtype.NamedType('ediPartyName', EDIPartyName()),
namedtype.NamedType('uniformResourceIdentifier', char.IA5String()),
namedtype.NamedType('iPAddress', univ.OctetString()),
namedtype.NamedType('registeredID', univ.ObjectIdentifier()),
)
class GeneralNames(univ.SequenceOf):
componentType = GeneralName()
sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
class SubjectAltName(GeneralNames):
pass
print decode('0\r\x82\x0bexample.com', asn1Spec=GeneralNames())
显然,我在接近尾声时感到有点无聊,并且没有完全指定 GeneralName
类型。但是,测试字符串应该包含一个 dNSName,而不是跳过的值之一,所以我希望这并不重要。
当程序运行时,它失败并出现我无法解释的错误:
Traceback (most recent call last):
File "x509.py", line 94, in <module>
print decode('0\r\x82\x0bexample.com', asn1Spec=GeneralNames())
File "/usr/lib/pymodules/python2.6/pyasn1/v1/codec/ber/decoder.py", line 493, in __call__
length, stGetValueDecoder, decodeFun
File "/usr/lib/pymodules/python2.6/pyasn1/v1/codec/ber/decoder.py", line 202, in valueDecoder
substrate, asn1Spec
File "/usr/lib/pymodules/python2.6/pyasn1/v1/codec/ber/decoder.py", line 453, in __call__
__chosenSpec.getTypeMap().has_key(tagSet):
File "/usr/lib/pymodules/python2.6/pyasn1/v1/type/univ.py", line 608, in getTypeMap
return Set.getComponentTypeMap(self)
File "/usr/lib/pymodules/python2.6/pyasn1/v1/type/univ.py", line 535, in getComponentTypeMap
def getComponentTypeMap(self): return self._componentType.getTypeMap(1)
File "/usr/lib/pymodules/python2.6/pyasn1/v1/type/namedtype.py", line 126, in getTypeMap
'Duplicate type %s in map %s'%(k,self.__typeMap)
pyasn1.error.PyAsn1Error: Duplicate type TagSet(Tag(tagClass=0, tagFormat=0, tagId=22)) in map {TagSet(Tag(tagClass=0, tagFormat=0, tagId=22)): IA5String()}
任何有关我出错的地方以及如何使用 pyasn1 成功解析此扩展类型的提示将不胜感激。
I have some data that pyOpenSSL gave me, '0\r\x82\x0bexample.com'
. This should be the value of a subjectAltName X509 extension. I tried to encode the necessary parts of the ASN1 specification for this extension using pyasn1 (and based on one of the pyasn1 examples):
from pyasn1.type import univ, constraint, char, namedtype
from pyasn1.codec.der.decoder import decode
MAX = 64
class DirectoryString(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType(
'teletexString', char.TeletexString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'printableString', char.PrintableString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'universalString', char.UniversalString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'utf8String', char.UTF8String().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'bmpString', char.BMPString().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
namedtype.NamedType(
'ia5String', char.IA5String().subtype(
subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
)
class AttributeValue(DirectoryString):
pass
class AttributeType(univ.ObjectIdentifier):
pass
class AttributeTypeAndValue(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', AttributeType()),
namedtype.NamedType('value', AttributeValue()),
)
class RelativeDistinguishedName(univ.SetOf):
componentType = AttributeTypeAndValue()
class RDNSequence(univ.SequenceOf):
componentType = RelativeDistinguishedName()
class Name(univ.Choice):
componentType = namedtype.NamedTypes(
namedtype.NamedType('', RDNSequence()),
)
class Extension(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('extnID', univ.ObjectIdentifier()),
namedtype.DefaultedNamedType('critical', univ.Boolean('False')),
namedtype.NamedType('extnValue', univ.OctetString()),
)
class Extensions(univ.SequenceOf):
componentType = Extension()
sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
class GeneralName(univ.Choice):
componentType = namedtype.NamedTypes(
# namedtype.NamedType('otherName', AnotherName()),
namedtype.NamedType('rfc822Name', char.IA5String()),
namedtype.NamedType('dNSName', char.IA5String()),
# namedtype.NamedType('x400Address', ORAddress()),
namedtype.NamedType('directoryName', Name()),
# namedtype.NamedType('ediPartyName', EDIPartyName()),
namedtype.NamedType('uniformResourceIdentifier', char.IA5String()),
namedtype.NamedType('iPAddress', univ.OctetString()),
namedtype.NamedType('registeredID', univ.ObjectIdentifier()),
)
class GeneralNames(univ.SequenceOf):
componentType = GeneralName()
sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
class SubjectAltName(GeneralNames):
pass
print decode('0\r\x82\x0bexample.com', asn1Spec=GeneralNames())
Clearly I got a little bored near the end and didn't fully specify the GeneralName
type. However, the test string should contain a dNSName
, not one of the skipped values, so I hope it doesn't matter.
When the program is run, it fails with an error I'm not able to interpret:
Traceback (most recent call last):
File "x509.py", line 94, in <module>
print decode('0\r\x82\x0bexample.com', asn1Spec=GeneralNames())
File "/usr/lib/pymodules/python2.6/pyasn1/v1/codec/ber/decoder.py", line 493, in __call__
length, stGetValueDecoder, decodeFun
File "/usr/lib/pymodules/python2.6/pyasn1/v1/codec/ber/decoder.py", line 202, in valueDecoder
substrate, asn1Spec
File "/usr/lib/pymodules/python2.6/pyasn1/v1/codec/ber/decoder.py", line 453, in __call__
__chosenSpec.getTypeMap().has_key(tagSet):
File "/usr/lib/pymodules/python2.6/pyasn1/v1/type/univ.py", line 608, in getTypeMap
return Set.getComponentTypeMap(self)
File "/usr/lib/pymodules/python2.6/pyasn1/v1/type/univ.py", line 535, in getComponentTypeMap
def getComponentTypeMap(self): return self._componentType.getTypeMap(1)
File "/usr/lib/pymodules/python2.6/pyasn1/v1/type/namedtype.py", line 126, in getTypeMap
'Duplicate type %s in map %s'%(k,self.__typeMap)
pyasn1.error.PyAsn1Error: Duplicate type TagSet(Tag(tagClass=0, tagFormat=0, tagId=22)) in map {TagSet(Tag(tagClass=0, tagFormat=0, tagId=22)): IA5String()}
Any tips on where I went wrong and how to successfully parse this extension type with pyasn1 would be much appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在 pyasn1-users 列表上发布了这个问题,Ilya Etingof(pyasn1 的作者)指出了我的错误。简而言之,
GeneralName.componentType
中的每个NamedType
都需要被赋予标签信息。这是通过subtype
方法完成的。例如,定义不应为:
其中
1
来自 GeneralName 的 ASN.1 定义:为
的每个字段定义标签后>componentType
,解析成功:I posted this question on the pyasn1-users list and Ilya Etingof (the author of pyasn1) pointed out my mistake. In brief, each
NamedType
inGeneralName.componentType
needs to be given tag information. This is done with thesubtype
method. For example, instead of:the definition should be:
where
1
comes from the ASN.1 definition of GeneralName:After defining a tag for each of these fields of the
componentType
, parsing succeeds:这个答案来得太晚了,但您也可以使用 pyasn1-modules (也是由 Ilya Etingof 创作)
这段代码至少应该可以工作,并且希望足以让您开始构建更复杂的 ANS.1 结构。确保您已运行
pip install pyasn1
、pip install pyasn1-modules
和pip install pyopenssl
否则您将收到导入错误。其输出将类似于
如果您正在处理的证书有多个扩展,您将需要使用 get_extension_count 来自 X509 对象和 get_short_name 来自 pyopenssl 中提供的 X509Extension 对象。
Coming in way late with this answer but instead of writing the ASN.1 Schema by hand you can also use the RF2459 module provided in pyasn1-modules (also authored by Ilya Etingof)
Minimally this code should work and will hopefully be enough to get you started on more complex ANS.1 constructs. Make sure you have run
pip install pyasn1
,pip install pyasn1-modules
andpip install pyopenssl
otherwise you'll get import errors.The output of this will be something like
If the cert you are working on has multiple extensions you will need to use get_extension_count from the X509 object and get_short_name from the X509Extension object provided in pyopenssl.