python ssl x509 asn.1

python - ¿Cómo analizo los datos de la extensión subjectAltName usando pyasn1?



ssl x509 (1)

Tengo algunos datos que pyOpenSSL me dio, ''0/r/x82/x0bexample.com'' . Este debería ser el valor de una extensión subjectAltName X509. Traté de codificar las partes necesarias de la especificación ASN1 para esta extensión usando pyasn1 (y en base a uno de los ejemplos de 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())

Claramente, me aburrí un poco cerca del final y no especifiqué por completo el tipo de nombre general. Sin embargo, la cadena de prueba debe contener un dNSName , no uno de los valores omitidos, así que espero que no importe.

Cuando se ejecuta el programa, falla con un error que no puedo interpretar:

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()}

Me gustaría mucho cualquier consejo sobre dónde me equivoqué y cómo analizar correctamente este tipo de extensión con pyasn1.


Publiqué esta pregunta en la lista de usuarios de pyasn1 e Ilya Etingof (el autor de pyasn1) señaló mi error. En resumen, cada NamedType en GeneralName.componentType necesita recibir información de etiqueta. Esto se hace con el método de subtype . Por ejemplo, en lugar de:

namedtype.NamedType(''rfc822Name'', char.IA5String()),

la definición debería ser:

namedtype.NamedType(''rfc822Name'', char.IA5String().subtype( implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),

donde 1 proviene de la definición ASN.1 de GeneralName :

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 }

Después de definir una etiqueta para cada uno de estos campos del componentType , el análisis tiene éxito:

(GeneralNames().setComponentByPosition( 0, GeneralName().setComponentByPosition(1, IA5String(''example.com''))), '''')