Last active
April 4, 2016 19:44
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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