diff --git a/tools/PccsAdminTool/lib/intelsgx/pckcert.py b/tools/PccsAdminTool/lib/intelsgx/pckcert.py index 97aa2783..eaed331b 100644 --- a/tools/PccsAdminTool/lib/intelsgx/pckcert.py +++ b/tools/PccsAdminTool/lib/intelsgx/pckcert.py @@ -1,76 +1,171 @@ from cryptography import x509 from cryptography.x509.oid import ObjectIdentifier from cryptography.hazmat.backends import default_backend -import asn1 -import struct +import pyasn1 +from pyasn1.codec.der.decoder import decode as der_decoder +from pyasn1.type import namedtype +from pyasn1.type import namedval +from pyasn1.type import opentype +from pyasn1.type import univ + + +id_cdp_extensionStr = '2.5.29.31' +id_ce_sGXExtensionsStr = '1.2.840.113741.1.13.1' + +id_ce_sGXExtensions = univ.ObjectIdentifier(id_ce_sGXExtensionsStr) + +id_ce_sGXExtensions_pPID = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".1") +id_ce_sGXExtensions_tCB = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2") +id_ce_sGXExtensions_pCE_ID = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".3") +id_ce_sGXExtensions_fMSPC = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".4") +id_ce_sGXExtensions_sGXType = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".5") +id_ce_sGXExtensions_platformInstanceID = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".6") +id_ce_sGXExtensions_configuration = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".7") + +id_ce_tCB_sGXTCBComp01SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.1") +id_ce_tCB_sGXTCBComp02SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.2") +id_ce_tCB_sGXTCBComp03SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.3") +id_ce_tCB_sGXTCBComp04SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.4") +id_ce_tCB_sGXTCBComp05SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.5") +id_ce_tCB_sGXTCBComp06SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.6") +id_ce_tCB_sGXTCBComp07SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.7") +id_ce_tCB_sGXTCBComp08SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.8") +id_ce_tCB_sGXTCBComp09SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.9") +id_ce_tCB_sGXTCBComp10SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.10") +id_ce_tCB_sGXTCBComp11SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.11") +id_ce_tCB_sGXTCBComp12SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.12") +id_ce_tCB_sGXTCBComp13SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.13") +id_ce_tCB_sGXTCBComp14SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.14") +id_ce_tCB_sGXTCBComp15SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.15") +id_ce_tCB_sGXTCBComp16SVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.16") +id_ce_tCB_pCESVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.17") +id_ce_tCB_cPUSVN = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".2.18") + +id_ce_configuration_dynamicPlatform = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".7.1") +id_ce_configuration_cachedKeys = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".7.2") +id_ce_configuration_sMTEnabled = univ.ObjectIdentifier(id_ce_sGXExtensionsStr + ".7.3") + + +class SgxExtensionPPID(univ.OctetString): + pass + + +class SgxCPUSVN(univ.OctetString): + pass + + +tcbAttributeMap = { + id_ce_tCB_sGXTCBComp01SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp02SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp03SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp04SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp05SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp06SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp07SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp08SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp09SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp10SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp11SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp12SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp13SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp14SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp15SVN: univ.Integer(), + id_ce_tCB_sGXTCBComp16SVN: univ.Integer(), + id_ce_tCB_pCESVN: univ.Integer(), + id_ce_tCB_cPUSVN: SgxCPUSVN(), +} + + +class SgxExtensionTCBEntry(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('tCBId', univ.ObjectIdentifier()), + namedtype.NamedType('tCBValue', univ.Any(), + openType=opentype.OpenType('tCBId', + tcbAttributeMap)) + ) + + +class SgxExtensionTCB(univ.SequenceOf): + componentType = SgxExtensionTCBEntry() + + +class SgxExtensionPCEID(univ.OctetString): + pass + + +class SgxExtensionFMSPC(univ.OctetString): + pass + + +class SgxExtensionSGXType(univ.Enumerated): + namedValues = namedval.NamedValues( + ('standard', 0), + ('scalable', 1), + ('scalableWithIntegrity', 2) + ) + + +class SgxExtensionPlatformInstanceID(univ.OctetString): + pass + + +configurationAttributeMap = { + id_ce_configuration_dynamicPlatform: univ.Boolean(), + id_ce_configuration_cachedKeys: univ.Boolean(), + id_ce_configuration_sMTEnabled: univ.Boolean(), +} + + +class SgxExtensionConfigurationEntry(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('configurationId', univ.ObjectIdentifier()), + namedtype.NamedType('configurationValue', univ.Any(), + openType=opentype.OpenType('configurationId', + configurationAttributeMap)) + ) + + +class SgxExtensionConfiguration(univ.SequenceOf): + componentType = SgxExtensionConfigurationEntry() + + +extensionAttributeMap = { + id_ce_sGXExtensions_pPID: SgxExtensionPPID(), + id_ce_sGXExtensions_tCB: SgxExtensionTCB(), + id_ce_sGXExtensions_pCE_ID: SgxExtensionPCEID(), + id_ce_sGXExtensions_fMSPC: SgxExtensionFMSPC(), + id_ce_sGXExtensions_sGXType: SgxExtensionSGXType(), + id_ce_sGXExtensions_platformInstanceID: SgxExtensionPlatformInstanceID(), + id_ce_sGXExtensions_configuration: SgxExtensionConfiguration(), +} + + +class SgxExtensionEntry(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('sGXExtensionId', univ.ObjectIdentifier()), + namedtype.NamedType('sGXExtensionValue', univ.Any(), + openType=opentype.OpenType('sGXExtensionId', + extensionAttributeMap)) + ) + + +class SgxExtension(univ.SequenceOf): + componentType = SgxExtensionEntry() -# This is a very simplistic ASN1 parser. Production code should use -# something like ans1c to build a parser from the ASN1 spec file so -# that it can check and enforce data validity. class SgxPckCertificateExtensions: - id_ce_sGXExtensions = '1.2.840.113741.1.13.1' - id_ce_sGXExtensions_tCB= id_ce_sGXExtensions+".2" - id_ce_sGXExtensions_configuration= id_ce_sGXExtensions+".7" - id_cdp_extension = '2.5.29.31' - decoder= asn1.Decoder() - _data= {} - ca= '' - oids= { - id_ce_sGXExtensions: 'sGXExtensions', - id_ce_sGXExtensions+".1": 'pPID', - id_ce_sGXExtensions_tCB: 'tCB', - id_ce_sGXExtensions_tCB+".1": 'tCB-sGXTCBComp01SVN', - id_ce_sGXExtensions_tCB+".2": 'tCB-sGXTCBComp02SVN', - id_ce_sGXExtensions_tCB+".3": 'tCB-sGXTCBComp03SVN', - id_ce_sGXExtensions_tCB+".4": 'tCB-sGXTCBComp04SVN', - id_ce_sGXExtensions_tCB+".5": 'tCB-sGXTCBComp05SVN', - id_ce_sGXExtensions_tCB+".6": 'tCB-sGXTCBComp06SVN', - id_ce_sGXExtensions_tCB+".7": 'tCB-sGXTCBComp07SVN', - id_ce_sGXExtensions_tCB+".8": 'tCB-sGXTCBComp08SVN', - id_ce_sGXExtensions_tCB+".9": 'tCB-sGXTCBComp09SVN', - id_ce_sGXExtensions_tCB+".10": 'tCB-sGXTCBComp10SVN', - id_ce_sGXExtensions_tCB+".11": 'tCB-sGXTCBComp11SVN', - id_ce_sGXExtensions_tCB+".12": 'tCB-sGXTCBComp12SVN', - id_ce_sGXExtensions_tCB+".13": 'tCB-sGXTCBComp13SVN', - id_ce_sGXExtensions_tCB+".14": 'tCB-sGXTCBComp14SVN', - id_ce_sGXExtensions_tCB+".15": 'tCB-sGXTCBComp15SVN', - id_ce_sGXExtensions_tCB+".16": 'tCB-sGXTCBComp16SVN', - id_ce_sGXExtensions_tCB+".17": 'tCB-pCESVN', - id_ce_sGXExtensions_tCB+".18": 'tCB-cPUSVN', - id_ce_sGXExtensions+".3": 'pCE-ID', - id_ce_sGXExtensions+".4": 'fMSPC', - id_ce_sGXExtensions+".5": 'sGXType', - id_ce_sGXExtensions+".6": 'platformInstanceID', - id_ce_sGXExtensions_configuration: 'configuration', - id_ce_sGXExtensions_configuration+".1": 'dynamicPlatform', - id_ce_sGXExtensions_configuration+".2": 'cachedKeys', - id_ce_sGXExtensions_configuration+".3": 'sMTEnabled' - } - - def _parse_asn1(self, d, oid, lnr=asn1.Numbers.ObjectIdentifier): - tag= self.decoder.peek() - while tag: - if tag.typ == asn1.Types.Constructed: - self.decoder.enter() - if ( lnr == asn1.Numbers.ObjectIdentifier ): - d[self.oids[oid]]= {} - self._parse_asn1(d[self.oids[oid]], oid, tag.nr) - else: - self._parse_asn1(d, oid, tag.nr) - self.decoder.leave() - elif tag.typ == asn1.Types.Primitive: - tag, value= self.decoder.read() - if ( tag.nr == asn1.Numbers.ObjectIdentifier ): - oid= value - else: - d[self.oids[oid]]= value - lnr= tag.nr - tag= self.decoder.peek() - return + + def __init__(self): + self.ca= '' + self._data= None + + def _parse_asn1(self, extensionData): + parsed, extra= der_decoder(extensionData, + asn1Spec=SgxExtension(), + decodeOpenTypes=True) + return parsed def parse_pem_certificate(self, pem): - self._data= {} cert= x509.load_pem_x509_certificate(pem, default_backend()) issuerCN = cert.issuer.rfc4514_string() if (issuerCN.find('Processor') != -1) : @@ -81,63 +176,55 @@ def parse_pem_certificate(self, pem): self.ca = None sgxext= cert.extensions.get_extension_for_oid( - ObjectIdentifier(self.id_ce_sGXExtensions) + ObjectIdentifier(id_ce_sGXExtensionsStr) ) - self.decoder.start(sgxext.value.value) - self._parse_asn1(self._data, self.id_ce_sGXExtensions) + self._data= self._parse_asn1(sgxext.value.value) def get_root_ca_crl(self, pem): - self._data= {} cert= x509.load_pem_x509_certificate(pem, default_backend()) cdpext= cert.extensions.get_extension_for_oid( - ObjectIdentifier(self.id_cdp_extension) + ObjectIdentifier(id_cdp_extensionStr) ) return getattr(getattr(cdpext.value[0], "_full_name")[0], "value") - def data(self, field=None): - if 'sGXExtensions' not in self._data: - return None - - d= self._data['sGXExtensions'] - - if field: - if field in d: - return d[field] + def data(self, field): + if self._data is None: return None - return d + ent = list(filter(lambda e: e['sGXExtensionId'] == field, self._data))[0] + return ent['sGXExtensionValue'] def _hex_data(self, field): val= self.data(field) if val is None: return None - return val.hex() + return bytes(val).hex() # Commonly-needed data fields #------------------------------ def get_fmspc(self): - return self._hex_data('fMSPC') + return self._hex_data(id_ce_sGXExtensions_fMSPC) def get_ca(self): return self.ca def get_tcbm(self): - tcb= self.data('tCB') + tcb= self.data(id_ce_sGXExtensions_tCB) if tcb is None: return None - return tcb['tCB-cPUSVN'].hex() + self.get_pcesvn() + ent= list(filter(lambda e: e['tCBId'] == id_ce_tCB_cPUSVN, tcb))[0] + return bytes(ent["tCBValue"]).hex() + self.get_pcesvn() def get_pceid(self): - return self._hex_data('pCE-ID') + return self._hex_data(id_ce_sGXExtensions_pCE_ID) def get_ppid(self): - return self._hex_data('pPID') + return self._hex_data(id_ce_sGXExtensions_pPID) def get_pcesvn(self): - tcb= self.data('tCB') - # pCESVN should be packed little-endian - pcesvn= struct.pack('