import keylime-6.5.1-1.el9_1.4
This commit is contained in:
parent
6dc174d7f0
commit
443bb1fa5a
@ -0,0 +1,42 @@
|
||||
From de8bbb63dca836bcf07586186218c3227749d2e7 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Berger <stefanb@linux.ibm.com>
|
||||
Date: Fri, 4 Nov 2022 11:20:15 -0400
|
||||
Subject: [PATCH] ima: Fix log evaluation on quick-succession execution of
|
||||
scripts
|
||||
|
||||
In case the attested-to host quickly executes files measured by IMA we may
|
||||
run into the case that the keylime agent retrieved the state of the PCR at
|
||||
'state n' but then IMA appended the log with several entries leading to a
|
||||
log representing 'state n + x' (with x>=1), which may not just be the
|
||||
previously anticipated single additional entry (state n+1). Therefore,
|
||||
remove the check for the number of entries in the log and always compare
|
||||
the running_hash that iterative attestation was resumed with against the
|
||||
provided PCR value from 'state n'.
|
||||
|
||||
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
|
||||
---
|
||||
keylime/ima/ima.py | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/keylime/ima/ima.py b/keylime/ima/ima.py
|
||||
index b88b1af..c4c2ae6 100644
|
||||
--- a/keylime/ima/ima.py
|
||||
+++ b/keylime/ima/ima.py
|
||||
@@ -299,9 +299,11 @@ def _process_measurement_list(
|
||||
|
||||
# Iterative attestation may send us no log [len(lines) == 1]; compare last know PCR 10 state
|
||||
# against current PCR state.
|
||||
- # Since IMA log append and PCR extend is not atomic, we may get a quote that does not yet take
|
||||
- # into account the next appended measurement's [len(lines) == 2] PCR extension.
|
||||
- if not found_pcr and len(lines) <= 2:
|
||||
+ # Since IMA's append to the log and PCR extend as well as Keylime's retrieval of the quote, reading
|
||||
+ # of PCR 10 and retrieval of the log are not atomic, we may get a quote that does not yet take into
|
||||
+ # account the next-appended measurements' [len(lines) >= 2] PCR extension(s). In fact, the value of
|
||||
+ # the PCR may lag the log by several entries.
|
||||
+ if not found_pcr:
|
||||
found_pcr = running_hash == pcrval_bytes
|
||||
|
||||
for linenum, line in enumerate(lines):
|
||||
--
|
||||
2.37.3
|
||||
|
@ -0,0 +1,70 @@
|
||||
From 2fee03637d3a1d0c9c004b958af69f4b0e4b57f3 Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Fri, 4 Nov 2022 17:41:31 +0100
|
||||
Subject: [PATCH 2/2] tpm_bootlog_enrich: Get DevicePath length from
|
||||
LengthOfDevicePath
|
||||
|
||||
In enrich_device_path(), get the length of DevicePath from the field
|
||||
LengthOfDevicePath instead of calculating the length from the bytes
|
||||
array.
|
||||
|
||||
This avoids a segmentation fault when processing the measured boot event
|
||||
log in create_mb_refstate script.
|
||||
|
||||
This is called for the events "EV_EFI_BOOT_SERVICES_APPLICATION",
|
||||
"EV_EFI_BOOT_SERVICES_DRIVER", and "EV_EFI_RUNTIME_SERVICES_DRIVER".
|
||||
|
||||
Fixes: #1153
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
keylime/tpm_bootlog_enrich.py | 11 ++++++-----
|
||||
1 file changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/keylime/tpm_bootlog_enrich.py b/keylime/tpm_bootlog_enrich.py
|
||||
index ef8e9f7..621bc67 100644
|
||||
--- a/keylime/tpm_bootlog_enrich.py
|
||||
+++ b/keylime/tpm_bootlog_enrich.py
|
||||
@@ -46,14 +46,14 @@ yaml.add_representer(hexint, representer)
|
||||
efivarlib_functions = CDLL(config.LIBEFIVAR)
|
||||
|
||||
|
||||
-def getDevicePath(b):
|
||||
- ret = efivarlib_functions.efidp_format_device_path(0, 0, b, len(b))
|
||||
+def getDevicePath(b, l):
|
||||
+ ret = efivarlib_functions.efidp_format_device_path(0, 0, b, l)
|
||||
if ret < 0:
|
||||
raise Exception(f"getDevicePath: efidp_format_device_path({b}) returned {ret}")
|
||||
|
||||
s = create_string_buffer(ret + 1)
|
||||
|
||||
- ret = efivarlib_functions.efidp_format_device_path(s, ret + 1, b, len(b))
|
||||
+ ret = efivarlib_functions.efidp_format_device_path(s, ret + 1, b, l)
|
||||
if ret < 0:
|
||||
raise Exception(f"getDevicePath: efidp_format_device_path({b}) returned {ret}")
|
||||
|
||||
@@ -174,7 +174,7 @@ def getVar(event, b):
|
||||
c = w.decode("utf-16", errors="ignore")
|
||||
description += c
|
||||
r["Description"] = description
|
||||
- devicePath = getDevicePath(b[i:])
|
||||
+ devicePath = getDevicePath(b[i:], len(b[i:]))
|
||||
r["DevicePath"] = devicePath
|
||||
return r
|
||||
return None
|
||||
@@ -184,10 +184,11 @@ def enrich_device_path(d: dict) -> None:
|
||||
if isinstance(d.get("DevicePath"), str):
|
||||
try:
|
||||
b = bytes.fromhex(d["DevicePath"])
|
||||
+ l = int(d["LengthOfDevicePath"])
|
||||
except Exception:
|
||||
return
|
||||
try:
|
||||
- p = getDevicePath(b)
|
||||
+ p = getDevicePath(b, l)
|
||||
# Deal with garbage devicePath
|
||||
except Exception:
|
||||
return
|
||||
--
|
||||
2.38.1
|
||||
|
672
SOURCES/0003-Backport-upsteam-PR-1156.patch
Normal file
672
SOURCES/0003-Backport-upsteam-PR-1156.patch
Normal file
@ -0,0 +1,672 @@
|
||||
From 57c67e2b359e9544ecd5a0ba264adf7aa7c67991 Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Mon, 14 Nov 2022 21:47:40 -0300
|
||||
Subject: [PATCH 3/3] Backport upsteam PR#1156
|
||||
|
||||
From: https://github.com/keylime/keylime/pull/1156
|
||||
|
||||
We had partially addressed the issue we encountered when parsing some
|
||||
certificates with python-cryptography by writing cert_utils module that
|
||||
provided a single helper to parse the pubkey from a certificate.
|
||||
|
||||
However, we still were doing the EK validation in tpm_main using
|
||||
python-cryptography, which means we would fall into the same parsing
|
||||
problem again, since during the validation it would read all the certs
|
||||
in the tpm cert store to check if it is signing the presented EK.
|
||||
|
||||
We address this issue by moving the EK cert verification to cert_utils:
|
||||
we use the same approach as before, i.e. we parse the cert with pyasn1
|
||||
when python-cryptography fails, and then use python-cryptography to do
|
||||
the actual signature verification, as before.
|
||||
|
||||
By moving the method to cert_utils, it also becomes simpler to test it,
|
||||
so in this commit we more tests to verify the methods work as expected.
|
||||
|
||||
Additionally, the updated EK verification is also capable of handling
|
||||
ECDSA signatures
|
||||
---
|
||||
keylime.conf | 2 +
|
||||
keylime/cert_utils.py | 144 ++++++++++++++++++++++++++++++++++--
|
||||
keylime/registrar_common.py | 7 +-
|
||||
keylime/tenant.py | 21 ++----
|
||||
keylime/tpm/tpm_main.py | 47 +-----------
|
||||
keylime/tpm_ek_ca.py | 10 +--
|
||||
scripts/ek-openssl-verify | 98 ++++++++++++++++++++++++
|
||||
test/run_tests.sh | 8 +-
|
||||
test/test_cert_utils.py | 142 ++++++++++++++++++++++++++++++-----
|
||||
9 files changed, 380 insertions(+), 99 deletions(-)
|
||||
create mode 100755 scripts/ek-openssl-verify
|
||||
|
||||
diff --git a/keylime.conf b/keylime.conf
|
||||
index 331e57a..d896f9f 100644
|
||||
--- a/keylime.conf
|
||||
+++ b/keylime.conf
|
||||
@@ -501,6 +501,8 @@ require_ek_cert = True
|
||||
# PROVKEYS - contains a json document containing EK, EKcert, and AIK from the
|
||||
# provider. EK and AIK are in PEM format. The EKcert is in base64 encoded
|
||||
# DER format.
|
||||
+# TPM_CERT_STORE - contains the path to the TPM certificates store, e.g.:
|
||||
+# "/var/lib/keylime/tpm_cert_store".
|
||||
#
|
||||
# Set to blank to disable this check. See warning above if require_ek_cert
|
||||
# is "False".
|
||||
diff --git a/keylime/cert_utils.py b/keylime/cert_utils.py
|
||||
index d014aed..d2fc54d 100644
|
||||
--- a/keylime/cert_utils.py
|
||||
+++ b/keylime/cert_utils.py
|
||||
@@ -1,13 +1,143 @@
|
||||
-from cryptography.hazmat.primitives.serialization import load_der_public_key
|
||||
+import io
|
||||
+import os.path
|
||||
+import subprocess
|
||||
+import sys
|
||||
+
|
||||
+from cryptography import exceptions as crypto_exceptions
|
||||
+from cryptography import x509
|
||||
+from cryptography.hazmat.backends import default_backend
|
||||
+from cryptography.hazmat.primitives.asymmetric import ec, padding
|
||||
+from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
|
||||
+from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
-from pyasn1_modules import rfc2459
|
||||
+from pyasn1_modules import pem, rfc2459
|
||||
|
||||
+from keylime import config, keylime_logging, tpm_ek_ca
|
||||
|
||||
# Issue #944 -- python-cryptography won't parse malformed certs,
|
||||
# such as some Nuvoton ones we have encountered in the field.
|
||||
# Unfortunately, we still have to deal with such certs anyway.
|
||||
-# Let's read the EK cert with pyasn1 instead of python-cryptography.
|
||||
-def read_x509_der_cert_pubkey(der_cert_data):
|
||||
- """Returns the public key of a DER-encoded X.509 certificate"""
|
||||
- der509 = decoder.decode(der_cert_data, asn1Spec=rfc2459.Certificate())[0]
|
||||
- return load_der_public_key(encoder.encode(der509["tbsCertificate"]["subjectPublicKeyInfo"]))
|
||||
+
|
||||
+# Here we provide some helpers that use pyasn1 to parse the certificates
|
||||
+# when parsing them with python-cryptography fails, and in this case, we
|
||||
+# try to read the parsed certificate again into python-cryptograhy.
|
||||
+
|
||||
+logger = keylime_logging.init_logging("cert_utils")
|
||||
+
|
||||
+
|
||||
+def x509_der_cert(der_cert_data: bytes):
|
||||
+ """Load an x509 certificate provided in DER format
|
||||
+ :param der_cert_data: the DER bytes of the certificate
|
||||
+ :type der_cert_data: bytes
|
||||
+ :returns: cryptography.x509.Certificate
|
||||
+ """
|
||||
+ try:
|
||||
+ return x509.load_der_x509_certificate(data=der_cert_data, backend=default_backend())
|
||||
+ except Exception as e:
|
||||
+ logger.warning("Failed to parse DER data with python-cryptography: %s", e)
|
||||
+ pyasn1_cert = decoder.decode(der_cert_data, asn1Spec=rfc2459.Certificate())[0]
|
||||
+ return x509.load_der_x509_certificate(data=encoder.encode(pyasn1_cert), backend=default_backend())
|
||||
+
|
||||
+
|
||||
+def x509_pem_cert(pem_cert_data: str):
|
||||
+ """Load an x509 certificate provided in PEM format
|
||||
+ :param pem_cert_data: the base-64 encoded PEM certificate
|
||||
+ :type pem_cert_data: str
|
||||
+ :returns: cryptography.x509.Certificate
|
||||
+ """
|
||||
+ try:
|
||||
+ return x509.load_pem_x509_certificate(data=pem_cert_data.encode("utf-8"), backend=default_backend())
|
||||
+ except Exception as e:
|
||||
+ logger.warning("Failed to parse PEM data with python-cryptography: %s", e)
|
||||
+ # Let's read the DER bytes from the base-64 PEM.
|
||||
+ der_data = pem.readPemFromFile(io.StringIO(pem_cert_data))
|
||||
+ # Now we can load it as we do in x509_der_cert().
|
||||
+ pyasn1_cert = decoder.decode(der_data, asn1Spec=rfc2459.Certificate())[0]
|
||||
+ return x509.load_der_x509_certificate(data=encoder.encode(pyasn1_cert), backend=default_backend())
|
||||
+
|
||||
+
|
||||
+def verify_ek(ekcert, tpm_cert_store=config.get("tenant", "tpm_cert_store")):
|
||||
+ """Verify that the provided EK certificate is signed by a trusted root
|
||||
+ :param ekcert: The Endorsement Key certificate in DER format
|
||||
+ :returns: True if the certificate can be verified, False otherwise
|
||||
+ """
|
||||
+ try:
|
||||
+ trusted_certs = tpm_ek_ca.cert_loader(tpm_cert_store)
|
||||
+ except Exception as e:
|
||||
+ logger.warning("Error loading trusted certificates from the TPM cert store: %s", e)
|
||||
+ return False
|
||||
+
|
||||
+ try:
|
||||
+ ek509 = x509_der_cert(ekcert)
|
||||
+ for cert_file, pem_cert in trusted_certs.items():
|
||||
+ signcert = x509_pem_cert(pem_cert)
|
||||
+ if ek509.issuer != signcert.subject:
|
||||
+ continue
|
||||
+
|
||||
+ signcert_pubkey = signcert.public_key()
|
||||
+ try:
|
||||
+ if isinstance(signcert_pubkey, RSAPublicKey):
|
||||
+ signcert_pubkey.verify(
|
||||
+ ek509.signature,
|
||||
+ ek509.tbs_certificate_bytes,
|
||||
+ padding.PKCS1v15(),
|
||||
+ ek509.signature_hash_algorithm,
|
||||
+ )
|
||||
+ elif isinstance(signcert_pubkey, EllipticCurvePublicKey):
|
||||
+ signcert_pubkey.verify(
|
||||
+ ek509.signature,
|
||||
+ ek509.tbs_certificate_bytes,
|
||||
+ ec.ECDSA(ek509.signature_hash_algorithm),
|
||||
+ )
|
||||
+ else:
|
||||
+ logger.warning("Unsupported public key type: %s", type(signcert_pubkey))
|
||||
+ continue
|
||||
+ except crypto_exceptions.InvalidSignature:
|
||||
+ continue
|
||||
+
|
||||
+ logger.debug("EK cert matched cert: %s", cert_file)
|
||||
+ return True
|
||||
+ except Exception as e:
|
||||
+ # Log the exception so we don't lose the raw message
|
||||
+ logger.exception(e)
|
||||
+ raise Exception("Error processing ek/ekcert. Does this TPM have a valid EK?").with_traceback(sys.exc_info()[2])
|
||||
+
|
||||
+ logger.error("No Root CA matched EK Certificate")
|
||||
+ return False
|
||||
+
|
||||
+
|
||||
+def verify_ek_script(script, env, cwd):
|
||||
+ if script is None:
|
||||
+ logger.warning("External check script (%s) not specified", script)
|
||||
+ return False
|
||||
+
|
||||
+ script_path = os.path.abspath(script)
|
||||
+ if not os.path.isfile(script_path):
|
||||
+ if cwd is None or not os.path.isfile(os.path.abspath(os.path.join(cwd, script))):
|
||||
+ logger.warning("External check script (%s) not found; please make sure its path is correct", script)
|
||||
+ return False
|
||||
+ script_path = os.path.abspath(os.path.join(cwd, script))
|
||||
+
|
||||
+ try:
|
||||
+ proc = subprocess.run(
|
||||
+ [script_path],
|
||||
+ env=env,
|
||||
+ shell=False,
|
||||
+ cwd=cwd,
|
||||
+ stderr=subprocess.STDOUT,
|
||||
+ stdout=subprocess.PIPE,
|
||||
+ check=False,
|
||||
+ )
|
||||
+ if proc.returncode != 0:
|
||||
+ errmsg = ""
|
||||
+ if proc.stdout is not None:
|
||||
+ errmsg = proc.stdout.decode("utf-8")
|
||||
+ logger.error("External check script failed to validate EK: %s", errmsg)
|
||||
+ return False
|
||||
+ logger.debug("External check script successfully to validated EK")
|
||||
+ if proc.stdout is not None:
|
||||
+ logger.info("ek_check output: %s", proc.stdout.decode("utf-8"))
|
||||
+ except subprocess.CalledProcessError as e:
|
||||
+ logger.error("Error while trying to run external check script to validate EK: %s", e)
|
||||
+ return False
|
||||
+ return True
|
||||
diff --git a/keylime/registrar_common.py b/keylime/registrar_common.py
|
||||
index 2c32d19..fb37e5b 100644
|
||||
--- a/keylime/registrar_common.py
|
||||
+++ b/keylime/registrar_common.py
|
||||
@@ -261,11 +261,8 @@ class UnprotectedHandler(BaseHTTPRequestHandler, SessionManager):
|
||||
# Note, we don't validate the EKCert here, other than the implicit
|
||||
# "is it a valid x509 cert" check. So it's still untrusted.
|
||||
# This will be validated by the tenant.
|
||||
- ek_tpm = base64.b64encode(
|
||||
- tpm2_objects.ek_low_tpm2b_public_from_pubkey(
|
||||
- cert_utils.read_x509_der_cert_pubkey(base64.b64decode(ekcert))
|
||||
- )
|
||||
- ).decode()
|
||||
+ cert = cert_utils.x509_der_cert(base64.b64decode(ekcert))
|
||||
+ ek_tpm = base64.b64encode(tpm2_objects.ek_low_tpm2b_public_from_pubkey(cert.public_key())).decode()
|
||||
|
||||
aik_attrs = tpm2_objects.get_tpm2b_public_object_attributes(
|
||||
base64.b64decode(aik_tpm),
|
||||
diff --git a/keylime/tenant.py b/keylime/tenant.py
|
||||
index cc53623..dd9c09c 100644
|
||||
--- a/keylime/tenant.py
|
||||
+++ b/keylime/tenant.py
|
||||
@@ -5,7 +5,6 @@ import io
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
-import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
@@ -15,7 +14,7 @@ import requests
|
||||
from cryptography.hazmat.primitives import serialization as crypto_serialization
|
||||
|
||||
from keylime import api_version as keylime_api_version
|
||||
-from keylime import ca_util, config, crypto, keylime_logging, registrar_client, signing, web_util
|
||||
+from keylime import ca_util, cert_utils, config, crypto, keylime_logging, registrar_client, signing, web_util
|
||||
from keylime.agentstates import AgentAttestState
|
||||
from keylime.cli import options, policies
|
||||
from keylime.cmd import user_data_encrypt
|
||||
@@ -516,19 +515,11 @@ class Tenant:
|
||||
env["EK_CERT"] = ""
|
||||
|
||||
env["PROVKEYS"] = json.dumps(self.registrar_data.get("provider_keys", {}))
|
||||
- with subprocess.Popen(
|
||||
- script, env=env, shell=True, cwd=config.WORK_DIR, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||
- ) as proc:
|
||||
- retval = proc.wait()
|
||||
- if retval != 0:
|
||||
- raise UserError("External check script failed to validate EK")
|
||||
- logger.debug("External check script successfully to validated EK")
|
||||
- while True:
|
||||
- line = proc.stdout.readline().decode()
|
||||
- if line == "":
|
||||
- break
|
||||
- logger.debug("ek_check output: %s", line.strip())
|
||||
- return True
|
||||
+
|
||||
+ # Define the TPM cert store for the external script.
|
||||
+ env["TPM_CERT_STORE"] = config.get("tenant", "tpm_cert_store")
|
||||
+
|
||||
+ return cert_utils.verify_ek_script(script, env, config.WORK_DIR)
|
||||
|
||||
def do_cv(self):
|
||||
"""Initiate v, agent_id and ip and initiate the cloudinit sequence"""
|
||||
diff --git a/keylime/tpm/tpm_main.py b/keylime/tpm/tpm_main.py
|
||||
index 7bab4fd..35f0a2f 100644
|
||||
--- a/keylime/tpm/tpm_main.py
|
||||
+++ b/keylime/tpm/tpm_main.py
|
||||
@@ -12,14 +12,10 @@ import time
|
||||
import typing
|
||||
import zlib
|
||||
|
||||
-from cryptography import exceptions as crypto_exceptions
|
||||
-from cryptography import x509
|
||||
-from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization as crypto_serialization
|
||||
-from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from packaging.version import Version
|
||||
|
||||
-from keylime import cmd_exec, config, keylime_logging, secure_mount, tpm_ek_ca
|
||||
+from keylime import cert_utils, cmd_exec, config, keylime_logging, secure_mount
|
||||
from keylime.agentstates import TPMClockInfo
|
||||
from keylime.common import algorithms, retry
|
||||
from keylime.failure import Component, Failure
|
||||
@@ -785,46 +781,7 @@ class tpm(tpm_abstract.AbstractTPM):
|
||||
:param ekcert: The Endorsement Key certificate in DER format
|
||||
:returns: True if the certificate can be verified, false otherwise
|
||||
"""
|
||||
- # openssl x509 -inform der -in certificate.cer -out certificate.pem
|
||||
- try:
|
||||
- tpm_ek_ca.check_tpm_cert_store()
|
||||
-
|
||||
- ek509 = x509.load_der_x509_certificate(
|
||||
- data=ekcert,
|
||||
- backend=default_backend(),
|
||||
- )
|
||||
-
|
||||
- trusted_certs = tpm_ek_ca.cert_loader()
|
||||
- for cert in trusted_certs:
|
||||
- signcert = x509.load_pem_x509_certificate(
|
||||
- data=cert.encode(),
|
||||
- backend=default_backend(),
|
||||
- )
|
||||
-
|
||||
- if ek509.issuer.rfc4514_string() != signcert.subject.rfc4514_string():
|
||||
- continue
|
||||
-
|
||||
- try:
|
||||
- signcert.public_key().verify(
|
||||
- ek509.signature,
|
||||
- ek509.tbs_certificate_bytes,
|
||||
- padding.PKCS1v15(),
|
||||
- ek509.signature_hash_algorithm,
|
||||
- )
|
||||
- except crypto_exceptions.InvalidSignature:
|
||||
- continue
|
||||
-
|
||||
- logger.debug("EK cert matched cert: %s", cert)
|
||||
- return True
|
||||
- except Exception as e:
|
||||
- # Log the exception so we don't lose the raw message
|
||||
- logger.exception(e)
|
||||
- raise Exception("Error processing ek/ekcert. Does this TPM have a valid EK?").with_traceback(
|
||||
- sys.exc_info()[2]
|
||||
- )
|
||||
-
|
||||
- logger.error("No Root CA matched EK Certificate")
|
||||
- return False
|
||||
+ return cert_utils.verify_ek(ekcert)
|
||||
|
||||
def get_tpm_manufacturer(self, output=None):
|
||||
vendorStr = None
|
||||
diff --git a/keylime/tpm_ek_ca.py b/keylime/tpm_ek_ca.py
|
||||
index 3695f0b..fb66c07 100644
|
||||
--- a/keylime/tpm_ek_ca.py
|
||||
+++ b/keylime/tpm_ek_ca.py
|
||||
@@ -7,8 +7,7 @@ logger = keylime_logging.init_logging("tpm_ek_ca")
|
||||
trusted_certs = {}
|
||||
|
||||
|
||||
-def check_tpm_cert_store():
|
||||
- tpm_cert_store = config.get("tenant", "tpm_cert_store")
|
||||
+def check_tpm_cert_store(tpm_cert_store=config.get("tenant", "tpm_cert_store")):
|
||||
if not os.path.isdir(tpm_cert_store):
|
||||
logger.error("The directory %s does not exist.", tpm_cert_store)
|
||||
raise Exception(f"The directory {tpm_cert_store} does not exist.")
|
||||
@@ -21,11 +20,10 @@ def check_tpm_cert_store():
|
||||
raise Exception(f"The directory {tpm_cert_store} does not contain " f"any .pem files")
|
||||
|
||||
|
||||
-def cert_loader():
|
||||
- tpm_cert_store = config.get("tenant", "tpm_cert_store")
|
||||
+def cert_loader(tpm_cert_store=config.get("tenant", "tpm_cert_store")):
|
||||
file_list = glob.glob(os.path.join(tpm_cert_store, "*.pem"))
|
||||
- my_trusted_certs = []
|
||||
+ my_trusted_certs = {}
|
||||
for file_path in file_list:
|
||||
with open(file_path, encoding="utf-8") as f_input:
|
||||
- my_trusted_certs.append(f_input.read())
|
||||
+ my_trusted_certs[file_path] = f_input.read()
|
||||
return my_trusted_certs
|
||||
diff --git a/scripts/ek-openssl-verify b/scripts/ek-openssl-verify
|
||||
new file mode 100755
|
||||
index 0000000..f91e9b5
|
||||
--- /dev/null
|
||||
+++ b/scripts/ek-openssl-verify
|
||||
@@ -0,0 +1,98 @@
|
||||
+#!/bin/sh
|
||||
+
|
||||
+# This script can be used as the `ek_check_script' (tenant configuration),
|
||||
+# to attempt to verify a provided EK_CERT via env var using openssl.
|
||||
+
|
||||
+# EK - contains a PEM-encoded version of the public EK
|
||||
+# EK_CERT - contains a base64 DER-encoded EK certificate if one is
|
||||
+# available.
|
||||
+# PROVKEYS - contains a json document containing EK, EKcert, and AIK
|
||||
+# from the provider. EK and AIK are in PEM format. The
|
||||
+# EKcert is in base64-encoded DER format
|
||||
+# TPM_CERT_STORE - contains the path of the TPM certificate store.
|
||||
+EK=${EK:-}
|
||||
+EK_CERT=${EK_CERT:-}
|
||||
+PROVKEYS=${PROVKEYS:-}
|
||||
+
|
||||
+EK_VERIFICATION_LOG=${EK_VERIFICATION_LOG:-/var/log/keylime/ek-verification.log}
|
||||
+LOG="${EK_VERIFICATION_LOG}"
|
||||
+
|
||||
+# Setting log fallback in case we cannot write to the specified file.
|
||||
+touch "${LOG}" 2>/dev/null || LOG=/dev/stderr
|
||||
+
|
||||
+log() {
|
||||
+ _stderr=${2:-}
|
||||
+ echo "[$(date)] ${1}" >&2 >> "${LOG}"
|
||||
+ [ -n "${_stderr}" ] && [ "${LOG}" != '/dev/stderr' ] && echo "${1}" >&2
|
||||
+}
|
||||
+
|
||||
+die() {
|
||||
+ log "ERROR: ${1}" _
|
||||
+ exit 1
|
||||
+}
|
||||
+
|
||||
+command -v openssl >/dev/null \
|
||||
+ || die "openssl CLI was not found in the PATH; please make sure it is installed"
|
||||
+
|
||||
+[ -n "${EK_CERT}" ] || die "EK_CERT was not provided as an env var"
|
||||
+
|
||||
+# Cert store directory. If one is not provided via TPM_CERT_STORE env var,
|
||||
+# we start by attempting to read tenant.conf.
|
||||
+CERT_STORE=${TPM_CERT_STORE:-}
|
||||
+
|
||||
+if [ -z "${CERT_STORE}" ]; then
|
||||
+ KEYLIME_CONFIG_DIR=${KEYLIME_CONFIG_DIR:-/etc/keylime}
|
||||
+ [ -d "${KEYLIME_CONFIG_DIR}" ] \
|
||||
+ || die "KEYLIME_CONFIG_DIR (${KEYLIME_CONFIG_DIR}) does not seem to exist"
|
||||
+
|
||||
+ if [ -r "${KEYLIME_CONFIG_DIR}"/tenant.conf ]; then
|
||||
+ CERT_STORE="$(grep -w ^tpm_cert_store "${KEYLIME_CONFIG_DIR}"/tenant.conf \
|
||||
+ | tail -1 | cut -d'=' -f2 | tr -d "[:blank:]")"
|
||||
+ fi
|
||||
+
|
||||
+ # Next we try to read any snippets in tenant.conf.d/
|
||||
+ if [ -d "${KEYLIME_CONFIG_DIR}"/tenant.conf.d ]; then
|
||||
+ for _s in "${KEYLIME_CONFIG_DIR}"/tenant.conf.d/*.conf; do
|
||||
+ [ -e "${_s}" ] || continue
|
||||
+ _store="$(grep -w ^tpm_cert_store "${_s}" \
|
||||
+ | tail -1 | cut -d'=' -f2 | tr -d "[:blank:]")"
|
||||
+ [ -n "${_store}" ] && CERT_STORE="${_store}"
|
||||
+ done
|
||||
+ fi
|
||||
+fi
|
||||
+
|
||||
+[ -n "${CERT_STORE}" ] \
|
||||
+ || die "It was not possible to determine the TPM cert store dir from tenant.conf or tenant.conf.d/ snippets"
|
||||
+[ -d "${CERT_STORE}" ] \
|
||||
+ || die "TPM cert store is not a valid directory (${CERT_STORE})"
|
||||
+
|
||||
+EK_VERIFICATION_TMPDIR=
|
||||
+ek_verification_cleanup() {
|
||||
+ [ -d "${EK_VERIFICATION_TMPDIR}" ] || return 0
|
||||
+ rm -rf "${EK_VERIFICATION_TMPDIR}"
|
||||
+}
|
||||
+trap ek_verification_cleanup EXIT
|
||||
+
|
||||
+mkdir -p "${TMPDIR:-/tmp}"
|
||||
+EK_VERIFICATION_TMPDIR="$(mktemp -d)" || \
|
||||
+ die "Creating a temp dir for EK verification failed"
|
||||
+
|
||||
+EK_CERT_FILE_DER="${EK_VERIFICATION_TMPDIR}"/ek.der
|
||||
+EK_CERT_FILE_PEM="${EK_VERIFICATION_TMPDIR}"/ek.pem
|
||||
+
|
||||
+printf '%s' "${EK_CERT}" > "${EK_CERT_FILE_DER}".b64
|
||||
+base64 -d "${EK_CERT_FILE_DER}".b64 > "${EK_CERT_FILE_DER}"
|
||||
+openssl x509 -inform der -in "${EK_CERT_FILE_DER}" > "${EK_CERT_FILE_PEM}"
|
||||
+
|
||||
+for c in "${CERT_STORE}"/*.pem; do
|
||||
+ [ -e "${c}" ] || continue
|
||||
+ log "Checking if ${c} is the issuer of EK cert..."
|
||||
+ if openssl verify -partial_chain -CAfile "${c}" "${EK_CERT_FILE_PEM}" \
|
||||
+ >>"${LOG}" 2>>"${LOG}"; then
|
||||
+ log "${EK_CERT} successfully verified by $(basename "${c}")" _
|
||||
+ exit 0
|
||||
+ fi
|
||||
+done
|
||||
+
|
||||
+die "EK signature did not match certificates from TPM cert store"
|
||||
+# vim:set ts=2 sw=2 et:
|
||||
diff --git a/test/run_tests.sh b/test/run_tests.sh
|
||||
index fc43113..81a6dff 100755
|
||||
--- a/test/run_tests.sh
|
||||
+++ b/test/run_tests.sh
|
||||
@@ -107,19 +107,19 @@ fi
|
||||
# Set correct dependencies
|
||||
# Fedora
|
||||
if [ $PACKAGE_MGR = "dnf" ]; then
|
||||
- PYTHON_PREIN="python3"
|
||||
+ PYTHON_PREIN="python3 openssl"
|
||||
PYTHON_DEPS="python3-pip python3-dbus"
|
||||
# RHEL / CentOS etc
|
||||
elif [ $PACKAGE_MGR = "yum" ]; then
|
||||
- PYTHON_PREIN="epel-release python36"
|
||||
+ PYTHON_PREIN="epel-release python36 openssl"
|
||||
PYTHON_DEPS="python36-pip python36-dbus"
|
||||
# Ubuntu / Debian
|
||||
elif [ $PACKAGE_MGR = "apt-get" ]; then
|
||||
- PYTHON_PREIN="python3"
|
||||
+ PYTHON_PREIN="python3 openssl"
|
||||
PYTHON_DEPS="python3-pip python3-dbus"
|
||||
# SUSE
|
||||
elif [ $PACKAGE_MGR = "zypper" ]; then
|
||||
- PYTHON_PREIN="python3"
|
||||
+ PYTHON_PREIN="python3 openssl"
|
||||
PYTHON_DEPS="python3-pip python3-dbus"
|
||||
else
|
||||
echo "No recognized package manager found on this system!" 1>&2
|
||||
diff --git a/test/test_cert_utils.py b/test/test_cert_utils.py
|
||||
index 4666c0f..bdf6090 100644
|
||||
--- a/test/test_cert_utils.py
|
||||
+++ b/test/test_cert_utils.py
|
||||
@@ -4,17 +4,19 @@ Copyright 2022 Red Hat, Inc.
|
||||
"""
|
||||
|
||||
import base64
|
||||
+import os
|
||||
import unittest
|
||||
|
||||
-from keylime import cert_utils
|
||||
+import cryptography
|
||||
|
||||
+from keylime import cert_utils, tpm_ek_ca
|
||||
|
||||
-class Cert_Utils_Test(unittest.TestCase):
|
||||
- def test_read_x509_der_cert_pubkey(self):
|
||||
- # The certificate listed in issue #944, from Nuvoton. It fails to
|
||||
- # be parsed by python-cryptography with the following error:
|
||||
- # ValueError: error parsing asn1 value: ParseError { kind: InvalidSetOrdering, location: ["RawCertificate::tbs_cert", "TbsCertificate::issuer", "0", "2"] }
|
||||
- nuvoton_ecdsa_sha256_der = """\
|
||||
+CERT_STORE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "tpm_cert_store"))
|
||||
+
|
||||
+# The certificate listed in issue #944, from Nuvoton. It fails to
|
||||
+# be parsed by python-cryptography with the following error:
|
||||
+# ValueError: error parsing asn1 value: ParseError { kind: InvalidSetOrdering, location: ["RawCertificate::tbs_cert", "TbsCertificate::issuer", "0", "2"] }
|
||||
+nuvoton_ecdsa_sha256_der = """\
|
||||
MIICBjCCAaygAwIBAgIIP5MvnZk8FrswCgYIKoZIzj0EAwIwVTFTMB8GA1UEAxMYTnV2b3RvbiBU
|
||||
UE0gUm9vdCBDQSAyMTEwMCUGA1UEChMeTnV2b3RvbiBUZWNobm9sb2d5IENvcnBvcmF0aW9uMAkG
|
||||
A1UEBhMCVFcwHhcNMTUxMDE5MDQzMjAwWhcNMzUxMDE1MDQzMjAwWjBVMVMwHwYDVQQDExhOdXZv
|
||||
@@ -26,10 +28,10 @@ ajW+9zAfBgNVHSMEGDAWgBSfu3mqD1JieL7RUJKacXHpajW+9zAKBggqhkjOPQQDAgNIADBFAiEA
|
||||
/jiywhOKpiMOUnTfDmXsXfDFokhKVNTXB6Xtqm7J8L4CICjT3/Y+rrSnf8zrBXqWeHDh8Wi41+w2
|
||||
ppq6Ev9orZFI
|
||||
"""
|
||||
- # This cert from STMicroelectronics presents a different issue when
|
||||
- # parsed by python-cryptography:
|
||||
- # ValueError: error parsing asn1 value: ParseError { kind: ExtraData }
|
||||
- st_sha256_with_rsa_der = """\
|
||||
+# This cert from STMicroelectronics presents a different issue when
|
||||
+# parsed by python-cryptography:
|
||||
+# ValueError: error parsing asn1 value: ParseError { kind: ExtraData }
|
||||
+st_sha256_with_rsa_der = """\
|
||||
MIIEjTCCA3WgAwIBAgIUTL0P5h7nYu2yjVCyaPw1hv89XoIwDQYJKoZIhvcNAQELBQAwVTELMAkG
|
||||
A1UEBhMCQ0gxHjAcBgNVBAoTFVNUTWljcm9lbGVjdHJvbmljcyBOVjEmMCQGA1UEAxMdU1RNIFRQ
|
||||
TSBFSyBJbnRlcm1lZGlhdGUgQ0EgMDUwHhcNMTgwNzExMDAwMDAwWhcNMjgwNzExMDAwMDAwWjAA
|
||||
@@ -60,10 +62,116 @@ rTJ1x4NA2ZtQMYyT29Yy1UlkjocAaXL5u0m3Hvz/////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/////w==
|
||||
"""
|
||||
- certs = [nuvoton_ecdsa_sha256_der, st_sha256_with_rsa_der]
|
||||
- for c in certs:
|
||||
+
|
||||
+st_ecdsa_sha256_der = """\
|
||||
+MIIDAzCCAqmgAwIBAgIUIymn2ai+UaVx1bM26/wU7I+sJd8wCgYIKoZIzj0EAwIwVjELMAkGA1UE
|
||||
+BhMCQ0gxHjAcBgNVBAoTFVNUTWljcm9lbGVjdHJvbmljcyBOVjEnMCUGA1UEAxMeU1RNIFRQTSBF
|
||||
+Q0MgSW50ZXJtZWRpYXRlIENBIDAxMB4XDTE4MDcyNjAwMDAwMFoXDTI4MDcyNjAwMDAwMFowADBZ
|
||||
+MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBsTz5y2cedVZxG/GsbXQ9bL6EQylWNjx1b/SSp2EHlN
|
||||
+aJjtn43iz2zb+qot2UOhQIwPxS5hMCXhasw4XsFXgnijggGpMIIBpTAfBgNVHSMEGDAWgBR+uDbO
|
||||
++9+KY3H/czP5utcUYWyWyzBCBgNVHSAEOzA5MDcGBFUdIAAwLzAtBggrBgEFBQcCARYhaHR0cDov
|
||||
+L3d3dy5zdC5jb20vVFBNL3JlcG9zaXRvcnkvMFkGA1UdEQEB/wRPME2kSzBJMRYwFAYFZ4EFAgEM
|
||||
+C2lkOjUzNTQ0RDIwMRcwFQYFZ4EFAgIMDFNUMzNIVFBIQUhCNDEWMBQGBWeBBQIDDAtpZDowMDQ5
|
||||
+MDAwNDBmBgNVHQkEXzBdMBYGBWeBBQIQMQ0wCwwDMi4wAgEAAgF0MEMGBWeBBQISMTowOAIBAAEB
|
||||
+/6ADCgEBoQMKAQCiAwoBAKMQMA4WAzMuMQoBBAoBAgEB/6QPMA0WBTE0MC0yCgECAQEAMAwGA1Ud
|
||||
+EwEB/wQCMAAwEAYDVR0lBAkwBwYFZ4EFCAEwDgYDVR0PAQH/BAQDAgMIMEsGCCsGAQUFBwEBBD8w
|
||||
+PTA7BggrBgEFBQcwAoYvaHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9zdG10cG1lY2NpbnQw
|
||||
+MS5jcnQwCgYIKoZIzj0EAwIDSAAwRQIgcNiZkn7poyk6J8Y1Cnwz4nV7YGPb5pBesBg6bk9n6KIC
|
||||
+IQCE/jkHb/aPP/T3GtfLNHAdHL4JnofAbsDEuLQxAseeZA==
|
||||
+"""
|
||||
+
|
||||
+
|
||||
+def has_strict_x509_parsing():
|
||||
+ """Indicates whether python-cryptography has strict x509 parsing."""
|
||||
+
|
||||
+ # Major release where python-cryptography started being strict
|
||||
+ # when parsing x509 certificates.
|
||||
+ PYCRYPTO_STRICT_X509_MAJOR = 35
|
||||
+ return int(cryptography.__version__.split(".", maxsplit=1)[0]) >= PYCRYPTO_STRICT_X509_MAJOR
|
||||
+
|
||||
+
|
||||
+def expectedFailureIf(condition):
|
||||
+ """The test is marked as an expectedFailure if the condition is satisfied."""
|
||||
+
|
||||
+ def wrapper(func):
|
||||
+ if condition:
|
||||
+ return unittest.expectedFailure(func)
|
||||
+ return func
|
||||
+
|
||||
+ return wrapper
|
||||
+
|
||||
+
|
||||
+class Cert_Utils_Test(unittest.TestCase):
|
||||
+ def test_tpm_cert_store(self):
|
||||
+ tpm_ek_ca.check_tpm_cert_store(CERT_STORE_DIR)
|
||||
+ my_trusted_certs = tpm_ek_ca.cert_loader(CERT_STORE_DIR)
|
||||
+
|
||||
+ self.assertNotEqual(len(my_trusted_certs), 0)
|
||||
+
|
||||
+ def test_cert_store_certs(self):
|
||||
+ my_trusted_certs = tpm_ek_ca.cert_loader(CERT_STORE_DIR)
|
||||
+ for fname, pem_cert in my_trusted_certs.items():
|
||||
try:
|
||||
- pubkey = cert_utils.read_x509_der_cert_pubkey(base64.b64decode(c))
|
||||
- except Exception:
|
||||
- self.fail("read_x509_der_cert_pubkey() is not expected to raise an exception here")
|
||||
- self.assertIsNotNone(pubkey)
|
||||
+ cert = cert_utils.x509_pem_cert(pem_cert)
|
||||
+ except Exception as e:
|
||||
+ self.fail(f"Failed to load certificate {fname}: {e}")
|
||||
+ self.assertIsNotNone(cert)
|
||||
+
|
||||
+ def test_verify_ek(self):
|
||||
+ tests = [
|
||||
+ {"cert": st_sha256_with_rsa_der, "expected": True}, # RSA, signed by STM_RSA_05I.pem.
|
||||
+ {"cert": st_ecdsa_sha256_der, "expected": True}, # ECC, signed by STM_ECC_01I.pem.
|
||||
+ ]
|
||||
+ for t in tests:
|
||||
+ self.assertEqual(
|
||||
+ cert_utils.verify_ek(base64.b64decode(t["cert"]), CERT_STORE_DIR),
|
||||
+ t["expected"],
|
||||
+ msg=f"Test failed for cert {t['cert']}; expected: {t['expected']}",
|
||||
+ )
|
||||
+
|
||||
+ @expectedFailureIf(has_strict_x509_parsing())
|
||||
+ def test_verify_ek_expected_failures(self):
|
||||
+ # The following certificates are not compliant, and will fail the
|
||||
+ # signature verification with python-cryptography, even though they
|
||||
+ # should validate. Marking as expected failure for now.
|
||||
+ tests = [
|
||||
+ {"cert": nuvoton_ecdsa_sha256_der, "expected": True}, # ECC, signed by NUVO_2110.pem.
|
||||
+ ]
|
||||
+ for t in tests:
|
||||
+ self.assertEqual(
|
||||
+ cert_utils.verify_ek(base64.b64decode(t["cert"]), CERT_STORE_DIR),
|
||||
+ t["expected"],
|
||||
+ msg=f"Test failed for cert {t['cert']}; expected: {t['expected']}",
|
||||
+ )
|
||||
+
|
||||
+ def test_verify_ek_script(self):
|
||||
+ # We will be using `nuvoton_ecdsa_sha256_der', which is signed by
|
||||
+ # NUVO_2110.pem but fails verification when using python-cryptography
|
||||
+ # as it is a malformed cert -- it is the same one we use in
|
||||
+ # test_verify_ek_expected_failures().
|
||||
+ # With an external script `ek_script_check' that uses openssl, the
|
||||
+ # validation works.
|
||||
+ cert = nuvoton_ecdsa_sha256_der.replace("\n", "")
|
||||
+
|
||||
+ self.assertFalse(cert_utils.verify_ek_script(None, None, None))
|
||||
+ self.assertFalse(cert_utils.verify_ek_script("/foo/bar", None, None))
|
||||
+
|
||||
+ script = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "scripts", "ek-openssl-verify"))
|
||||
+ # Testing ek-openssl-verify script, but without specifying the
|
||||
+ # EK_CERT env var.
|
||||
+ self.assertFalse(cert_utils.verify_ek_script(script, None, None))
|
||||
+
|
||||
+ # Now let's specify the EK_CERT.
|
||||
+ env = os.environ.copy()
|
||||
+ env["EK_CERT"] = cert
|
||||
+ env["TPM_CERT_STORE"] = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "tpm_cert_store"))
|
||||
+ self.assertTrue(cert_utils.verify_ek_script(script, env, None))
|
||||
+
|
||||
+ # Now, let us specify the ek_check_script with a relative path.
|
||||
+ script = "ek-openssl-verify"
|
||||
+ cwd = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "scripts"))
|
||||
+ self.assertTrue(cert_utils.verify_ek_script(script, env, cwd))
|
||||
+
|
||||
+ # And now we try a bad TPM cert store.
|
||||
+ env["TPM_CERT_STORE"] = "/some/bad/directory"
|
||||
+ self.assertFalse(cert_utils.verify_ek_script(script, env, cwd))
|
||||
--
|
||||
2.38.1
|
||||
|
@ -0,0 +1,130 @@
|
||||
From 76cbd7bbcce1793db9a3d64d962cfdb518ef4eff Mon Sep 17 00:00:00 2001
|
||||
From: Sergio Correia <scorreia@redhat.com>
|
||||
Date: Tue, 15 Nov 2022 07:09:13 -0300
|
||||
Subject: [PATCH 4/4] Do not use default values that need reading the config in
|
||||
methods
|
||||
|
||||
Following up from the recent refactoring that moved the EK validation
|
||||
to cert_utils, in a few places were added default method values that
|
||||
were reading the configuration files directly.
|
||||
|
||||
It was not such a great idea becasue it then made those config files as
|
||||
required to even import the modules.
|
||||
|
||||
Example "from keylime import cert_utils" now also requires that the
|
||||
tenant configuration be available for getting the path for the TPM
|
||||
cert store.
|
||||
|
||||
Let's stop doing that.
|
||||
|
||||
Signed-off-by: Sergio Correia <scorreia@redhat.com>
|
||||
---
|
||||
keylime/cert_utils.py | 5 +++--
|
||||
keylime/tenant.py | 2 +-
|
||||
keylime/tpm/tpm_abstract.py | 2 +-
|
||||
keylime/tpm/tpm_main.py | 4 ++--
|
||||
keylime/tpm_ek_ca.py | 6 +++---
|
||||
5 files changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/keylime/cert_utils.py b/keylime/cert_utils.py
|
||||
index d2fc54d..3576c64 100644
|
||||
--- a/keylime/cert_utils.py
|
||||
+++ b/keylime/cert_utils.py
|
||||
@@ -12,7 +12,7 @@ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import pem, rfc2459
|
||||
|
||||
-from keylime import config, keylime_logging, tpm_ek_ca
|
||||
+from keylime import keylime_logging, tpm_ek_ca
|
||||
|
||||
# Issue #944 -- python-cryptography won't parse malformed certs,
|
||||
# such as some Nuvoton ones we have encountered in the field.
|
||||
@@ -56,9 +56,10 @@ def x509_pem_cert(pem_cert_data: str):
|
||||
return x509.load_der_x509_certificate(data=encoder.encode(pyasn1_cert), backend=default_backend())
|
||||
|
||||
|
||||
-def verify_ek(ekcert, tpm_cert_store=config.get("tenant", "tpm_cert_store")):
|
||||
+def verify_ek(ekcert: bytes, tpm_cert_store: str) -> bool:
|
||||
"""Verify that the provided EK certificate is signed by a trusted root
|
||||
:param ekcert: The Endorsement Key certificate in DER format
|
||||
+ :param tpm_cert_store: The path for the TPM certificate store
|
||||
:returns: True if the certificate can be verified, False otherwise
|
||||
"""
|
||||
try:
|
||||
diff --git a/keylime/tenant.py b/keylime/tenant.py
|
||||
index dd9c09c..118f8c4 100644
|
||||
--- a/keylime/tenant.py
|
||||
+++ b/keylime/tenant.py
|
||||
@@ -430,7 +430,7 @@ class Tenant:
|
||||
elif ekcert is None:
|
||||
logger.warning("No EK cert provided, require_ek_cert option in config set to True")
|
||||
return False
|
||||
- elif not self.tpm_instance.verify_ek(base64.b64decode(ekcert)):
|
||||
+ elif not self.tpm_instance.verify_ek(base64.b64decode(ekcert), config.get("tenant", "tpm_cert_store")):
|
||||
logger.warning("Invalid EK certificate")
|
||||
return False
|
||||
|
||||
diff --git a/keylime/tpm/tpm_abstract.py b/keylime/tpm/tpm_abstract.py
|
||||
index ff41837..df6222c 100644
|
||||
--- a/keylime/tpm/tpm_abstract.py
|
||||
+++ b/keylime/tpm/tpm_abstract.py
|
||||
@@ -97,7 +97,7 @@ class AbstractTPM(metaclass=ABCMeta):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
- def verify_ek(self, ekcert):
|
||||
+ def verify_ek(self, ekcert, tpm_cert_store):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
diff --git a/keylime/tpm/tpm_main.py b/keylime/tpm/tpm_main.py
|
||||
index 35f0a2f..09af0d0 100644
|
||||
--- a/keylime/tpm/tpm_main.py
|
||||
+++ b/keylime/tpm/tpm_main.py
|
||||
@@ -776,12 +776,12 @@ class tpm(tpm_abstract.AbstractTPM):
|
||||
os.remove(sesspath)
|
||||
return key
|
||||
|
||||
- def verify_ek(self, ekcert):
|
||||
+ def verify_ek(self, ekcert, tpm_cert_store):
|
||||
"""Verify that the provided EK certificate is signed by a trusted root
|
||||
:param ekcert: The Endorsement Key certificate in DER format
|
||||
:returns: True if the certificate can be verified, false otherwise
|
||||
"""
|
||||
- return cert_utils.verify_ek(ekcert)
|
||||
+ return cert_utils.verify_ek(ekcert, tpm_cert_store)
|
||||
|
||||
def get_tpm_manufacturer(self, output=None):
|
||||
vendorStr = None
|
||||
diff --git a/keylime/tpm_ek_ca.py b/keylime/tpm_ek_ca.py
|
||||
index fb66c07..bc84571 100644
|
||||
--- a/keylime/tpm_ek_ca.py
|
||||
+++ b/keylime/tpm_ek_ca.py
|
||||
@@ -1,13 +1,13 @@
|
||||
import glob
|
||||
import os
|
||||
|
||||
-from keylime import config, keylime_logging
|
||||
+from keylime import keylime_logging
|
||||
|
||||
logger = keylime_logging.init_logging("tpm_ek_ca")
|
||||
trusted_certs = {}
|
||||
|
||||
|
||||
-def check_tpm_cert_store(tpm_cert_store=config.get("tenant", "tpm_cert_store")):
|
||||
+def check_tpm_cert_store(tpm_cert_store):
|
||||
if not os.path.isdir(tpm_cert_store):
|
||||
logger.error("The directory %s does not exist.", tpm_cert_store)
|
||||
raise Exception(f"The directory {tpm_cert_store} does not exist.")
|
||||
@@ -20,7 +20,7 @@ def check_tpm_cert_store(tpm_cert_store=config.get("tenant", "tpm_cert_store")):
|
||||
raise Exception(f"The directory {tpm_cert_store} does not contain " f"any .pem files")
|
||||
|
||||
|
||||
-def cert_loader(tpm_cert_store=config.get("tenant", "tpm_cert_store")):
|
||||
+def cert_loader(tpm_cert_store):
|
||||
file_list = glob.glob(os.path.join(tpm_cert_store, "*.pem"))
|
||||
my_trusted_certs = {}
|
||||
for file_path in file_list:
|
||||
--
|
||||
2.38.1
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
Name: keylime
|
||||
Version: 6.5.1
|
||||
Release: 1%{?dist}
|
||||
Release: 1%{?dist}.4
|
||||
Summary: Open source TPM software for Bootstrapping and Maintaining Trust
|
||||
|
||||
URL: https://github.com/keylime/keylime
|
||||
@ -18,6 +18,11 @@ Source2: %{srcname}.te
|
||||
Source3: %{srcname}.if
|
||||
Source4: %{srcname}.fc
|
||||
|
||||
Patch: 0001-ima-Fix-log-evaluation-on-quick-succession-execution.patch
|
||||
Patch: 0002-tpm_bootlog_enrich-Get-DevicePath-length-from-Length.patch
|
||||
Patch: 0003-Backport-upsteam-PR-1156.patch
|
||||
Patch: 0004-Do-not-use-default-values-that-need-reading-the-conf.patch
|
||||
|
||||
License: ASL 2.0 and MIT
|
||||
|
||||
BuildRequires: git-core
|
||||
@ -86,6 +91,7 @@ Requires: python3-lark-parser
|
||||
Requires: python3-pyasn1
|
||||
Requires: python3-pyasn1-modules
|
||||
Requires: tpm2-tools
|
||||
Requires: openssl
|
||||
|
||||
%description -n python3-%{srcname}
|
||||
The python3-keylime module implements the functionality used
|
||||
@ -183,7 +189,8 @@ rm -f %{buildroot}/%{_bindir}/%{srcname}_userdata_encrypt
|
||||
mkdir -p %{buildroot}/%{_datadir}/%{srcname}/scripts
|
||||
for s in create_allowlist.sh \
|
||||
create_mb_refstate \
|
||||
create_policy; do
|
||||
create_policy \
|
||||
ek-openssl-verify; do
|
||||
install -Dpm 755 scripts/${s} \
|
||||
%{buildroot}/%{_datadir}/%{srcname}/scripts/${s}
|
||||
done
|
||||
@ -333,11 +340,28 @@ fi
|
||||
%{_tmpfilesdir}/%{srcname}.conf
|
||||
%{_sysusersdir}/%{srcname}.conf
|
||||
%{_datadir}/%{srcname}/scripts/create_allowlist.sh
|
||||
%{_datadir}/%{srcname}/scripts/ek-openssl-verify
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
|
||||
%changelog
|
||||
* Tue Nov 15 2022 Sergio Correia <scorreia@redhat.com> - 6.5.1-1.4
|
||||
- Do not use default values that need reading the config in methods
|
||||
Resolves: rhbz#2142033 - Registrar may crash during EK validation when require_ek_cert is enabled [rhel-9.1.0.z]
|
||||
|
||||
* Mon Nov 14 2022 Sergio Correia <scorreia@redhat.com> - 6.5.1-1.3
|
||||
- Backport upstream PR#1156
|
||||
Resolves: rhbz#2142033 - Registrar may crash during EK validation when require_ek_cert is enabled [rhel-9.1.0.z]
|
||||
|
||||
* Mon Nov 14 2022 Sergio Correia <scorreia@redhat.com> - 6.5.1-1.2
|
||||
- Segmentation fault in create_mb_refstate script
|
||||
Resolves: rhbz#2142034 - Segmentation fault in /usr/share/keylime/create_mb_refstate script [rhel-9.1.0.z]
|
||||
|
||||
* Mon Nov 14 2022 Sergio Correia <scorreia@redhat.com> - 6.5.1-1.1
|
||||
- ima: Fix log evaluation on quick-succession execution of scripts
|
||||
Resolves: rhbz#2142032 - agent fails IMA attestation when one scripts is executed quickly after the other [rhel-9.1.0.z]
|
||||
|
||||
* Thu Oct 13 2022 Sergio Correia <scorreia@redhat.com> - 6.5.1-1
|
||||
- Update to 6.5.1
|
||||
Resolves: CVE-2022-3500
|
||||
|
Loading…
Reference in New Issue
Block a user