linux-sgx/0121-pccsadmin-convert-from-asn1-to-pyasn1-python-module.patch
Daniel P. Berrangé 3c00769e65 Fix pccs npm security flaws
Sync patches from Fedora 43, to fix multiple pccs npm security flaws,
and fix typo in pccsadmin help text.

CVE-2026-23745, CVE-2026-23950, CVE-2026-24842, CVE-2025-13465, CVE-2025-15284

Resolves: RHEL-145005, RHEL-144190, RHEL-142482, RHEL-138075, RHEL-140108
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2026-02-05 11:52:25 +00:00

342 lines
12 KiB
Diff

From b9954581944446455876728bdab816090d773715 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Thu, 4 Dec 2025 13:54:19 +0000
Subject: [PATCH 121/136] pccsadmin: convert from asn1 to pyasn1 python module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The pyasn1 module decodes using a formal object model so is more robust,
as well as being more widely available in distros.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
tools/PccsAdminTool/lib/intelsgx/pckcert.py | 267 +++++++++++++-------
1 file changed, 177 insertions(+), 90 deletions(-)
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 @@ class SgxPckCertificateExtensions:
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()
--
2.52.0