Skip to content

Instantly share code, notes, and snippets.

@awood
Last active April 4, 2016 19:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save awood/1a2086aae8e092da809941a13daf45fe to your computer and use it in GitHub Desktop.
Save awood/1a2086aae8e092da809941a13daf45fe to your computer and use it in GitHub Desktop.
ASN1 Reader that examines X509 certificates for extensions under OID 1.3.6.1.4.1.2312
#! /usr/bin/env python3
import sys
import base64
import binascii
import re
from pyasn1.type import univ, namedtype, tag, constraint, namedval
from pyasn1.codec.der import decoder
try:
# pyasn1_modules isn't available in RHEL 6
from pyasn1_modules.pem import readPemFromFile
except ImportError:
# TODO This is a relatively naive implementation
def readPemFromFile(f):
try:
b64 = []
lines = f.readlines()
for l in lines:
if not re.match('^-----', l):
b64.append(l.rstrip())
pem = "".join(b64)
return base64.b64decode(pem)
finally:
f.close()
class Version(univ.Integer):
namedValues = namedval.NamedValues(
('v1', 0), ('v2', 1), ('v3', 2)
)
class CertificateSerialNumber(univ.Integer):
pass
class UniqueIdentifier(univ.BitString):
pass
# The univ.Any classes below are just generic placeholders for the ASN1
# in that section of the certificate. We don't care about that data at
# all, so we just dump it into a generic type.
class Signature(univ.Any):
pass
class Name(univ.Any):
pass
class Validity(univ.Any):
pass
class SubjectPublicKeyInfo(univ.Any):
pass
class AlgorithmIdentifier(univ.Any):
pass
class Extension(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('extnID', univ.ObjectIdentifier()),
namedtype.DefaultedNamedType('critical', univ.Boolean().subtype(value=0)),
namedtype.NamedType('extnValue', univ.OctetString())
)
class Extensions(univ.SequenceOf):
componentType = Extension()
subtypeSpec = constraint.ValueSizeConstraint(1, 64)
class TBSCertificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.DefaultedNamedType(
'version',
Version('v1').subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)
)),
namedtype.NamedType('serialNumber', CertificateSerialNumber()),
namedtype.NamedType('signature', AlgorithmIdentifier()),
namedtype.NamedType('issuer', Name()),
namedtype.NamedType('validity', Validity()),
namedtype.NamedType('subject', Name()),
namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
namedtype.OptionalNamedType(
'issuerUniqueID',
UniqueIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)
)),
namedtype.OptionalNamedType(
'subjectUniqueID',
UniqueIdentifier().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)
)),
namedtype.OptionalNamedType(
'extensions',
Extensions().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)
))
)
class Certificate(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('tbsCertificate', TBSCertificate()),
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
namedtype.NamedType('signature', univ.BitString()))
REDHAT_OID = '1.3.6.1.4.1.2312'
def parse_asn1(cert_file):
der = readPemFromFile(open(cert_file, 'r'))
cert, other = decoder.decode(der, asn1Spec=Certificate())
tbsCert = cert.getComponentByName('tbsCertificate')
extensions = tbsCert.getComponentByName('extensions')
for ext in extensions:
oid = ext.getComponentByName('extnID').prettyPrint()
if oid.startswith(REDHAT_OID):
print(oid)
# This is a little ugly to maintain compatibility with pyasn1 on
# RHEL 6. On newer versions, prettyPrint() does the right thing.
val = ext.getComponentByName('extnValue')._value
print(binascii.hexlify(val))
if __name__ == "__main__":
sys.argv.pop(0)
if len(sys.argv) != 1:
print("Usage: reader.py <entitlement_certificate_pem_file>")
else:
parse_asn1(sys.argv[0])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment