Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 177 additions & 90 deletions tools/PccsAdminTool/lib/intelsgx/pckcert.py
Original file line number Diff line number Diff line change
@@ -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) :
Expand All @@ -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('<H', tcb['tCB-pCESVN'])
return pcesvn.hex()
tcb= self.data(id_ce_sGXExtensions_tCB)
ent= list(filter(lambda e: e['tCBId'] == id_ce_tCB_pCESVN, tcb))[0]
return int(ent["tCBValue"]).to_bytes(2, byteorder='little').hex()