首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用pyasn1解析subjectAltName扩展数据?

如何使用pyasn1解析subjectAltName扩展数据?
EN

Stack Overflow用户
提问于 2011-04-02 07:36:10
回答 2查看 6.3K关注 0票数 17

我有pyOpenSSL给我的一些数据'0\r\x82\x0bexample.com'这应该是subjectAltName X509扩展的值。我尝试使用pyasn1编码这个扩展的ASN1规范的必要部分(并基于一个pyasn1示例):

代码语言:javascript
复制
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,而不是跳过的值之一,所以我希望这无关紧要。

当程序运行时,它失败了,出现了一个我无法解释的错误:

代码语言:javascript
复制
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成功解析这种扩展类型的提示都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-04-03 21:44:13

我把这个问题发布在pyasn1-users列表上,然后Ilya Etingof (pyasn1的作者)指出了我的错误。简而言之,GeneralName.componentType中的每个NamedType都需要提供标签信息。这是通过subtype方法完成的。例如,而不是:

代码语言:javascript
复制
namedtype.NamedType('rfc822Name', char.IA5String()),

定义应该是:

代码语言:javascript
复制
namedtype.NamedType('rfc822Name', char.IA5String().subtype(
        implicitTag=tag.Tag(tag.tagClassContext,
                            tag.tagFormatSimple, 1))),

其中1来自ASN.1 .1对GeneralName的定义

代码语言:javascript
复制
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
}

componentType的每个字段定义标记后,解析成功:

代码语言:javascript
复制
(GeneralNames().setComponentByPosition(
    0, GeneralName().setComponentByPosition(1, IA5String('example.com'))), '')
票数 15
EN

Stack Overflow用户

发布于 2018-08-07 23:55:01

这个答案来得有点晚,但您也可以使用pyasn1-modules (也是Ilya Etingof编写的)中提供的RF2459模块,而不是手动编写ASN.1Schema。

最低限度,这段代码应该可以工作,并有望足以让您开始使用更复杂的ANS.1构造。确保你已经运行了pip install pyasn1pip install pyasn1-modulespip install pyopenssl,否则你会得到导入错误。

代码语言:javascript
复制
# Import pyasn and the proper decode function
import pyasn1
from pyasn1.codec.der.decoder import decode as asn1_decoder

# Import SubjectAltName from rfc2459 module
from pyasn1_modules.rfc2459 import SubjectAltName

# Import native Python type encoder
from pyasn1.codec.native.encoder import encode as nat_encoder

# Import OpenSSL tools for working with certs.
from OpenSSL import crypto
# Read raw certificate file
with open('PATH/TO/CERTIFICATE.crt', 'r') as cert_f:
    raw_cert = cert_f.read()

cert = crypto.load_certificate(crypto.FILETYPE_PEM, raw_cert)

# Note this example assumes SubjectAltName is the only Extension for this cert. 
raw_alt_names = cert.get_extension(0).get_data()

decoded_alt_names, _ = asn1_decoder(raw_alt_names, asn1Spec=SubjectAltName())

# Unless a raw string of ASN.1 is what you need encode back to native Python types
py_alt_names = nat_encoder(decoded_alt_names)

# And Finally a plain Python list of UTF-8 encoded strings representing the SubjectAltNames
subject_alt_names = [ x['dNSName'].decode('utf-8') for x in py_alt_names]

其输出将如下所示

代码语言:javascript
复制
['cdn1.example.com', 'cdn2.example.com']

如果您正在处理的证书有多个扩展,那么您将需要使用来自X509对象的get_extension_count和来自pyopenssl中提供的X509Extension对象的get_short_name

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5519958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档