CVE-2022-1053: Improper Input Validation (CWE-20)
value: Keylime does not enforce that the agent registrar data is the same when the tenant uses it for validation of the EK and identity quote and the verifier for validating the integrity quote. This allows an attacker to use one AK, EK pair from a real TPM to pass EK validation and give the verifier an AK of a software TPM. A successful attack breaks the entire chain of trust because a not validated AK is used by the verifier. This issue is worse if the validation happens first and then the agent gets added to the verifier because the timing is easier and the verifier does not validate the regcount entry being equal to 1,
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 9.1
Published: 2022-05-06T17:15Z
Repository: https://github.com/keylime/keylime
Language: Python
Files changed: keylime/cloud_verifier_tornado.py, keylime/tenant.py
Commit date: 2022-05-04 12:25:42 -0400
Commit message: tenant, verifier: let the tenant provide the AK and mTLS certificate

This eliminates the need for the verifier to connect to the registrar.

Signed-off-by: Thore Sommer <mail@thson.de>

Diff: diff --git a/keylime/cloud_verifier_tornado.py b/keylime/cloud_verifier_tornado.py
index fa68454..4489e30 100644
--- a/keylime/cloud_verifier_tornado.py
+++ b/keylime/cloud_verifier_tornado.py
@@ -17,11 +17,10 @@ from sqlalchemy.orm.exc import NoResultFound
 import tornado.ioloop
 import tornado.web
 
 from keylime import config
 from keylime import json
-from keylime import registrar_client
 from keylime.agentstates import AgentAttestStates
 from keylime.common import states, validators, retry
 from keylime.db.verifier_db import VerfierMain
 from keylime.db.verifier_db import VerifierAllowlist
 from keylime.db.keylime_db import DBEngineManager, SessionManager
@@ -442,10 +441,12 @@ class AgentsHandler(BaseHandler):
                     agent_data['revocation_key'] = json_body['revocation_key']
                     agent_data['accept_tpm_hash_algs'] = json_body['accept_tpm_hash_algs']
                     agent_data['accept_tpm_encryption_algs'] = json_body['accept_tpm_encryption_algs']
                     agent_data['accept_tpm_signing_algs'] = json_body['accept_tpm_signing_algs']
                     agent_data['supported_version'] = json_body['supported_version']
+                    agent_data['ak_tpm'] = json_body['ak_tpm']
+                    agent_data['mtls_cert'] = json_body.get('mtls_cert', None)
                     agent_data['hash_alg'] = ""
                     agent_data['enc_alg'] = ""
                     agent_data['sign_alg'] = ""
                     agent_data['agent_id'] = agent_id
                     agent_data['boottime'] = 0
@@ -455,26 +456,12 @@ class AgentsHandler(BaseHandler):
                     agent_data['learned_ima_keyrings'] = {}
                     agent_data['verifier_id'] = config.get('cloud_verifier', 'cloudverifier_id', fallback=cloud_verifier_common.DEFAULT_VERIFIER_ID)
                     agent_data['verifier_ip'] = config.get('cloud_verifier', 'cloudverifier_ip')
                     agent_data['verifier_port'] = config.get('cloud_verifier', 'cloudverifier_port')
 
-                    # We fetch the registrar data directly here because we require it for connecting to the agent
-                    # using mTLS
-                    registrar_client.init_client_tls('cloud_verifier')
-                    registrar_data = registrar_client.getData(config.get("cloud_verifier", "registrar_ip"),
-                                                              config.get("cloud_verifier", "registrar_port"), agent_id)
-                    if registrar_data is None:
-                        web_util.echo_json_response(self, 400,
-                                                    f"Data for agent {agent_id} could not be found in registrar!")
-                        logger.warning("Data for agent %s could not be found in registrar!", agent_id)
-                        return
-
-                    agent_data['mtls_cert'] = registrar_data.get('mtls_cert', None)
-                    agent_data['ak_tpm'] = registrar_data['aik_tpm']
-
                     # TODO: Always error for v1.0 version after initial upgrade
-                    if registrar_data.get('mtls_cert', None) is None and agent_data['supported_version'] != "1.0":
+                    if agent_data['mtls_cert'] is None and agent_data['supported_version'] != "1.0":
                         web_util.echo_json_response(self, 400, "mTLS certificate for agent is required!")
                         return
 
                     is_valid, err_msg = cloud_verifier_common.validate_agent_data(agent_data)
                     if not is_valid:
@@ -508,11 +495,11 @@ class AgentsHandler(BaseHandler):
                         for key,val in exclude_db.items():
                             agent_data[key] = val
 
                         # Prepare SSLContext for mTLS connections
                         agent_mtls_cert_enabled = config.getboolean('cloud_verifier', 'agent_mtls_cert_enabled', fallback=False)
-                        mtls_cert = registrar_data.get('mtls_cert', None)
+                        mtls_cert = agent_data['mtls_cert']
                         agent_data['ssl_context'] = None
                         if agent_mtls_cert_enabled and mtls_cert:
                             agent_data['ssl_context'] = web_util.generate_agent_mtls_context(mtls_cert, self.mtls_options)
 
                         if agent_data['ssl_context'] is None:
diff --git a/keylime/tenant.py b/keylime/tenant.py
index 11b9186..95f6763 100755
--- a/keylime/tenant.py
+++ b/keylime/tenant.py
@@ -629,10 +629,12 @@ class Tenant():
             'metadata': json.dumps(self.metadata),
             'revocation_key': self.revocation_key,
             'accept_tpm_hash_algs': self.accept_tpm_hash_algs,
             'accept_tpm_encryption_algs': self.accept_tpm_encryption_algs,
             'accept_tpm_signing_algs': self.accept_tpm_signing_algs,
+            'ak_tpm': self.registrar_data['aik_tpm'],
+            'mtls_cert': self.registrar_data.get('mtls_cert', None),
             'supported_version': self.supported_version,
         }
         json_message = json.dumps(data)
         do_cv = RequestsClient(self.verifier_base_url, self.tls_cv_enabled, ignore_hostname=True)
         response = do_cv.post(

Vulnerable code: from keylime import registrar_client
                    # We fetch the registrar data directly here because we require it for connecting to the agent
                    # using mTLS
                    registrar_client.init_client_tls('cloud_verifier')
                    registrar_data = registrar_client.getData(config.get("cloud_verifier", "registrar_ip"),
                                                              config.get("cloud_verifier", "registrar_port"), agent_id)
                    if registrar_data is None:
                        web_util.echo_json_response(self, 400,
                                                    f"Data for agent {agent_id} could not be found in registrar!")
                        logger.warning("Data for agent %s could not be found in registrar!", agent_id)
                        return

                    agent_data['mtls_cert'] = registrar_data.get('mtls_cert', None)
                    agent_data['ak_tpm'] = registrar_data['aik_tpm']

                    if registrar_data.get('mtls_cert', None) is None and agent_data['supported_version'] != "1.0":
                        mtls_cert = registrar_data.get('mtls_cert', None)
Fixed code:                     agent_data['ak_tpm'] = json_body['ak_tpm']
                    agent_data['mtls_cert'] = json_body.get('mtls_cert', None)
                    if agent_data['mtls_cert'] is None and agent_data['supported_version'] != "1.0":
                        mtls_cert = agent_data['mtls_cert']
            'ak_tpm': self.registrar_data['aik_tpm'],
            'mtls_cert': self.registrar_data.get('mtls_cert', None),