[virt-tools-list] [PATCH virtio-win-pkg-scripts v3 1/2] add parser for driver catalog files

Roman Kagan rkagan at virtuozzo.com
Mon Jan 25 19:57:46 UTC 2016


This script parses ASN.1 structure of the Windows driver catalog files,
and extracts information about what architecture and windows flavor the
driver is suitable for.

Signed-off-by: Roman Kagan <rkagan at virtuozzo.com>
---
changes since v2:
 - add extracting of catalog timestamp and signing time
 - minor refactoring for better readability

changes since v1:
 - fix pep8 warnings

 util/parsecat.py | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 290 insertions(+)
 create mode 100644 util/parsecat.py

diff --git a/util/parsecat.py b/util/parsecat.py
new file mode 100644
index 0000000..bcfaaaf
--- /dev/null
+++ b/util/parsecat.py
@@ -0,0 +1,290 @@
+#!/usr/bin/python
+#
+# Copyright 2016 Parallels IP Holdings GmbH
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+"""
+Parse relevant items in the ASN.1 structure of a Windows driver catalog file
+"""
+
+import sys
+from pprint import pprint
+from itertools import chain
+from datetime import datetime
+from pyasn1_modules import rfc2315
+from pyasn1.type import tag, namedtype, namedval, univ, char, useful
+from pyasn1.codec.der.decoder import decode
+from pyasn1 import debug
+
+
+# rfc2315 allowed only two certificate types here; later versions of CMS
+# (rfc3852) allowed more, and recent catalogs use those.  As we aren't doing
+# security verifications stub it with ANY type and igore the content.
+class CertificateSet(univ.SetOf):
+    componentType = univ.Any()
+
+
+# redefine rfc2315.SignedData with rfc3852-compatible
+class SignedData(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('version', rfc2315.Version()),
+        namedtype.NamedType('digestAlgorithms',
+                            rfc2315.DigestAlgorithmIdentifiers()),
+        namedtype.NamedType('contentInfo', rfc2315.ContentInfo()),
+        namedtype.OptionalNamedType('certificates', CertificateSet().subtype(
+            implicitTag=tag.Tag(tag.tagClassContext,
+                                tag.tagFormatConstructed, 0))),
+        namedtype.OptionalNamedType(
+            'crls', rfc2315.CertificateRevocationLists().subtype(
+                implicitTag=tag.Tag(tag.tagClassContext,
+                                    tag.tagFormatConstructed, 1))),
+        namedtype.NamedType('signerInfos', rfc2315.SignerInfos())
+        )
+
+
+class CatalogList(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('oid', univ.ObjectIdentifier())
+        )
+
+
+class CatalogListMemberId(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('oid', univ.ObjectIdentifier()),
+        namedtype.NamedType('null', univ.Null())
+        )
+
+
+class CatalogNameValue(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('name', char.BMPString()),
+        namedtype.NamedType('someInt', univ.Integer()),
+        namedtype.NamedType('value', univ.OctetString(encoding='utf-16-le'))
+        )
+
+
+class SpcKind(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('oid', univ.ObjectIdentifier()),
+        namedtype.NamedType('someTh', univ.Any())
+        )
+
+
+class SpcIndirectData(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('spcKind', SpcKind()),
+        namedtype.NamedType('digest', rfc2315.DigestInfo())
+        )
+
+
+class MemberAttributeContent(univ.SetOf):
+    componentType = univ.Any()
+
+
+class MemberAttribute(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('oid', univ.ObjectIdentifier()),
+        namedtype.NamedType('content', MemberAttributeContent())
+        )
+
+
+class MemberAttributes(univ.SetOf):
+    componentType = MemberAttribute()
+
+
+class CatalogListMember(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('referenceTag', univ.OctetString()),
+        namedtype.NamedType('attributes', MemberAttributes())
+        )
+
+
+class CatalogMembers(univ.SequenceOf):
+    componentType = CatalogListMember()
+
+
+class CatalogAttribute(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('oid', univ.ObjectIdentifier()),
+        namedtype.NamedType('content', univ.OctetString())
+        )
+
+
+class CatalogAttributes(univ.SequenceOf):
+    componentType = CatalogAttribute()
+    tagSet = univ.SequenceOf.tagSet.tagExplicitly(tag.Tag(tag.tagClassContext,
+                                                  tag.tagFormatConstructed, 0))
+
+
+class TimeChoice(univ.Choice):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('utcTime', useful.UTCTime()),
+        namedtype.NamedType('genTime', useful.GeneralizedTime())
+        )
+
+
+class TSTInfo(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('version', rfc2315.Version()),
+        namedtype.NamedType('policy', univ.ObjectIdentifier()),
+        namedtype.NamedType('messageImprint', univ.Any()),
+        namedtype.NamedType('serialNumber', univ.Integer()),
+        namedtype.NamedType('genTime', useful.GeneralizedTime()),
+        namedtype.OptionalNamedType('accuracy', univ.Any()),
+        namedtype.OptionalNamedType('ordering', univ.Boolean()),
+        namedtype.OptionalNamedType('nonce', univ.Integer()),
+        namedtype.OptionalNamedType('tsa', rfc2315.GeneralName().subtype(
+            explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+        namedtype.OptionalNamedType('extensions', rfc2315.Extensions().subtype(
+            implicitTag=tag.Tag(tag.tagClassContext,
+                                tag.tagFormatConstructed, 1)))
+        )
+
+
+class CertTrustList(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('catalogList', CatalogList()),
+        namedtype.NamedType('someStr0', univ.OctetString()),
+        namedtype.NamedType('utcTime', useful.UTCTime()),
+        namedtype.NamedType('catalogListMemberId', CatalogListMemberId()),
+        namedtype.NamedType('members', CatalogMembers()),
+        namedtype.OptionalNamedType('attributes', CatalogAttributes())
+        )
+
+
+def parseNameValue(attr):
+    nv, _ = decode(attr, asn1Spec=CatalogNameValue())
+    strtype = type(u'')    # python2/3 compat
+    name, value = str(strtype(nv['name'])), str(strtype(nv['value']))
+    assert value[-1] == '\x00'
+    return name, value[:-1]
+
+
+spcKindMap = {
+    univ.ObjectIdentifier('1.3.6.1.4.1.311.2.1.15'): 'spcPEImageData',
+    univ.ObjectIdentifier('1.3.6.1.4.1.311.2.1.25'): 'spcLink',
+}
+
+
+digestAlgoMap = {
+    univ.ObjectIdentifier('1.3.14.3.2.26'): 'sha1',
+    univ.ObjectIdentifier('2.16.840.1.101.3.4.2.1'): 'sha256',
+}
+
+
+def parseSpcIndirectData(attr):
+    sid, _ = decode(attr, asn1Spec=SpcIndirectData())
+    spcKind, digest = sid['spcKind'], sid['digest']
+    algo = digestAlgoMap[digest['digestAlgorithm']['algorithm']]
+    return 'signature', {
+        'kind': spcKindMap[spcKind['oid']],
+        'digestAlgorithm': algo,
+        'digest': digest['digest'].asOctets()
+    }
+
+
+memberAttrMap = {
+    univ.ObjectIdentifier('1.3.6.1.4.1.311.12.2.1'): parseNameValue,
+    univ.ObjectIdentifier('1.3.6.1.4.1.311.12.2.2'): None,
+    univ.ObjectIdentifier('1.3.6.1.4.1.311.12.2.3'): None,
+    univ.ObjectIdentifier('1.3.6.1.4.1.311.2.1.4'): parseSpcIndirectData,
+}
+
+
+def parseCatMember(member):
+    for attr in member['attributes']:
+        meth = memberAttrMap[attr['oid']]
+        if meth:
+            yield meth(attr['content'][0])
+
+
+def parsePKCS7SignedData(data):
+    container, _ = decode(data, asn1Spec=rfc2315.ContentInfo())
+    assert container['contentType'] == rfc2315.signedData
+    content, _ = decode(container['content'], SignedData())
+    return content
+
+
+def parseNameValueObj(nameValue):
+    assert nameValue['oid'] == univ.ObjectIdentifier('1.3.6.1.4.1.311.12.2.1')
+    return parseNameValue(nameValue['content'])
+
+
+def parseUTCTime(utcTime):
+    return datetime.strptime(str(utcTime), '%y%m%d%H%M%SZ')
+
+
+def parseGeneralizedTime(genTime):
+    return datetime.strptime(str(genTime), '%Y%m%d%H%M%S.%fZ')
+
+
+def parseTimeChoice(timeChoice):
+    utcTime = timeChoice['utcTime']
+    if utcTime:
+        return parseUTCTime(utcTime)
+    return parseGeneralizedTime(signingTime['genTime'])
+
+
+def getSigningTimeAuthenticode(data):
+    signerInfo, _ = decode(data, asn1Spec=rfc2315.SignerInfo())
+    attrs = signerInfo['authenticatedAttributes']
+    if not attrs:
+        return
+    for attr in attrs:
+        if attr['type'] == univ.ObjectIdentifier('1.2.840.113549.1.9.5'):
+            signingTime, _ = decode(attr['values'][0], asn1Spec=TimeChoice())
+            return parseTimeChoice(signingTime)
+
+
+def getSigningTimeRFC3161(data):
+    content = parsePKCS7SignedData(data)
+    contentInfo = content['contentInfo']
+    contentType = contentInfo['contentType']
+    assert (contentInfo['contentType'] ==
+            univ.ObjectIdentifier('1.2.840.113549.1.9.16.1.4'))
+    ostr, _ = decode(contentInfo['content'], asn1Spec=univ.OctetString())
+    tSTInfo, _ = decode(ostr, asn1Spec=TSTInfo())
+    return parseGeneralizedTime(tSTInfo['genTime'])
+
+
+def getSigningTimes(signerInfo):
+    attrs = signerInfo['unauthenticatedAttributes']
+    if not attrs:
+        return
+    for attr in attrs:
+        if attr['type'] == univ.ObjectIdentifier('1.2.840.113549.1.9.6'):
+            for val in attr['values']:
+                yield getSigningTimeAuthenticode(val)
+
+        if attr['type'] == univ.ObjectIdentifier('1.3.6.1.4.1.311.3.3.1'):
+            for val in attr['values']:
+                yield getSigningTimeRFC3161(val)
+
+
+def parseCat(fname):
+    cat = open(fname, "rb").read()
+    content = parsePKCS7SignedData(cat)
+    contentInfo = content['contentInfo']
+    assert (contentInfo['contentType'] ==
+            univ.ObjectIdentifier('1.3.6.1.4.1.311.10.1'))
+
+    ctl, _ = decode(contentInfo['content'], asn1Spec=CertTrustList())
+    assert (ctl['catalogList']['oid'] ==
+            univ.ObjectIdentifier('1.3.6.1.4.1.311.12.1.1'))
+    assert (ctl['catalogListMemberId']['oid'] in (
+        univ.ObjectIdentifier('1.3.6.1.4.1.311.12.1.2'),
+        univ.ObjectIdentifier('1.3.6.1.4.1.311.12.1.3')
+        ))
+
+    members = [dict(parseCatMember(member)) for member in ctl['members']]
+    attributes = dict(parseNameValueObj(attr) for attr in ctl['attributes'])
+
+    attributes['timestamp'] = parseUTCTime(ctl['utcTime'])
+    attributes['signingTimes'] = list(chain.from_iterable(
+        getSigningTimes(si) for si in content['signerInfos']))
+
+    return attributes, members
+
+if __name__ == "__main__":
+    pprint(parseCat(sys.argv[1]))
-- 
2.5.0




More information about the virt-tools-list mailing list