Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config, tpm_main: explicitly handle YAML load errors #807

Merged
merged 1 commit into from
Dec 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 9 additions & 3 deletions keylime/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
SPDX-License-Identifier: Apache-2.0
Copyright 2017 Massachusetts Institute of Technology.
'''

import os
import os.path
import configparser
Expand All @@ -11,13 +10,15 @@
import re
from http.server import BaseHTTPRequestHandler
import http.client
from typing import Optional

import tornado.web
import yaml
try:
from yaml import CSafeLoader as SafeLoader
except ImportError:
from yaml import SafeLoader
from yaml.reader import ReaderError

from keylime import api_version as keylime_api_version
from keylime import json
Expand Down Expand Up @@ -245,10 +246,15 @@ def list_to_dict(alist):
return params


def yaml_to_dict(arry, add_newlines=True):
def yaml_to_dict(arry, add_newlines=True, logger=None) -> Optional[dict]:
arry = convert(arry)
sep = "\n" if add_newlines else ""
return yaml.load(sep.join(arry), Loader=SafeLoader)
try:
return yaml.load(sep.join(arry), Loader=SafeLoader)
except ReaderError as err:
if logger is not None:
logger.warning("Could not load yaml as dict: %s", str(err))
return None


def get_restful_params(urlstring):
Expand Down
44 changes: 32 additions & 12 deletions keylime/tpm/tpm_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,10 @@ def __get_tpm_algorithms(self):
output = output.replace("clear", "0")
output = [output]

retyaml = config.yaml_to_dict(output)
retyaml = config.yaml_to_dict(output, logger=logger)
if retyaml is None:
logger.warning("Could not read YAML output of tpm2_getcap.")
return
for algorithm, details in retyaml.items():
if details["asymmetric"] == 1 and details["object"] == 1 and algorithms.Encrypt.is_recognized(algorithm):
self.supported['encrypt'].add(algorithm)
Expand Down Expand Up @@ -419,7 +422,7 @@ def __create_ek(self, asym_alg=None):
if code != tpm_abstract.AbstractTPM.EXIT_SUCESS:
raise Exception("tpm2_getcap failed with code " + str(code) + ": " + str(reterr))

outjson = config.yaml_to_dict(output)
outjson = config.yaml_to_dict(output, logger=logger)
if outjson is not None and hex(current_handle) in outjson:
if self.tools_version == "3.2":
cmd = ["tpm2_evictcontrol", "-A", "o", "-H",
Expand Down Expand Up @@ -469,7 +472,9 @@ def __create_ek(self, asym_alg=None):
handle = int(0x81010007)
elif self.tools_version in ["4.0", "4.2"]:
handle = None
retyaml = config.yaml_to_dict(output)
retyaml = config.yaml_to_dict(output, logger=logger)
if retyaml is None:
raise Exception("Could not read YAML output of tpm2_createek.")
if "persistent-handle" in retyaml:
handle = retyaml["persistent-handle"]

Expand Down Expand Up @@ -603,7 +608,7 @@ def __create_aik(self, asym_alg=None, hash_alg=None, sign_alg=None):
output = output.replace("0x", " - 0x")
output = [output]

outjson = config.yaml_to_dict(output)
outjson = config.yaml_to_dict(output, logger=logger)
if self.tools_version == "3.2":
evict_it = outjson is not None and aik_handle in outjson
elif self.tools_version in ["4.0", "4.2"]:
Expand Down Expand Up @@ -664,7 +669,9 @@ def __create_aik(self, asym_alg=None, hash_alg=None, sign_alg=None):
if code != tpm_abstract.AbstractTPM.EXIT_SUCESS:
raise Exception("tpm2_createak failed with code " + str(code) + ": " + str(reterr))

jsonout = config.yaml_to_dict(retout)
jsonout = config.yaml_to_dict(retout, logger=logger)
if jsonout is None:
raise Exception("unable to parse YAML output of tpm2_createak. Is your tpm2-tools installation up to date?")
aik_tpm = retDict['fileouts'][akpubfile.name]
if aik_tpm == "":
raise Exception("unable to read public aik from create identity. Is your tpm2-tools installation up to date?")
Expand Down Expand Up @@ -711,7 +718,10 @@ def flush_keys(self):
retout = [retout]

owner_pw = self.get_tpm_metadata("owner_pw")
jsonout = config.yaml_to_dict(retout)
jsonout = config.yaml_to_dict(retout, logger=logger)
if jsonout is None:
logger.warning("Could not read YAML output of tpm2_getcap.")
jsonout = {}
for key in jsonout:
if str(hex(key)) != self.defaults['ek_handle']:
logger.debug("Flushing key handle %s" % hex(key))
Expand Down Expand Up @@ -907,7 +917,9 @@ def get_tpm_manufacturer(self):
for i, s in enumerate(output):
output[i] = re.sub(r"[\x01-\x1F\x7F]", "", s.decode('utf-8')).encode('utf-8')

retyaml = config.yaml_to_dict(output)
retyaml = config.yaml_to_dict(output, logger=logger)
if retyaml is None:
raise Exception("Could not read YAML output of tpm2_getcap.")
if "TPM2_PT_VENDOR_STRING_1" in retyaml:
vendorStr = retyaml["TPM2_PT_VENDOR_STRING_1"]["value"]
elif "TPM_PT_VENDOR_STRING_1" in retyaml:
Expand Down Expand Up @@ -1107,7 +1119,11 @@ def check_quote(self, agentAttestState, nonce, data, quote, aikTpmFromRegistrar,
return failure

pcrs = []
jsonout = config.yaml_to_dict(retout)
jsonout = config.yaml_to_dict(retout, logger=logger)
if jsonout is None:
failure.add_event("quote_validation", {"message": "YAML parsing failed for quote validation using tpm2-tools.",
"data": retout}, False)
return failure
if "pcrs" in jsonout:
if hash_alg in jsonout["pcrs"]:
alg_size = algorithms.get_hash_size(hash_alg) // 4
Expand Down Expand Up @@ -1151,7 +1167,9 @@ def readPCR(self, pcrval, hash_alg=None):
elif self.tools_version in ["4.0", "4.2"]:
output = config.convert(self.__run("tpm2_pcrread")['retout'])

jsonout = config.yaml_to_dict(output)
jsonout = config.yaml_to_dict(output, logger=logger)
if jsonout is None:
raise Exception("Could not read YAML output of tpm2_pcrread.")

if hash_alg not in jsonout:
raise Exception("Invalid hashing algorithm '%s' for reading PCR number %d." % (hash_alg, pcrval))
Expand Down Expand Up @@ -1213,7 +1231,7 @@ def read_ekcert_nvram(self):
if self.tools_version in ["4.0", "4.2"]:
raise Exception("tpm2_nvreadpublic for ekcert failed with code " + str(code) + ": " + str(reterr))

outjson = config.yaml_to_dict(output)
outjson = config.yaml_to_dict(output, logger=logger)

if outjson is None or 0x1c00002 not in outjson or "size" not in outjson[0x1c00002]:
logger.warning("No EK certificate found in TPM NVRAM")
Expand Down Expand Up @@ -1320,7 +1338,7 @@ def __add_boot_aggregate(self, log: dict) -> None :
except Exception:
pass

def parse_binary_bootlog(self, log_bin:bytes) -> dict:
def parse_binary_bootlog(self, log_bin:bytes) -> typing.Optional[dict]:
'''Parse and enrich a BIOS boot log

The input is the binary log.
Expand All @@ -1330,7 +1348,9 @@ def parse_binary_bootlog(self, log_bin:bytes) -> dict:
log_bin_filename = log_bin_file.name
retDict_tpm2 = self.__run(['tpm2_eventlog', '--eventlog-version=2', log_bin_filename])
log_parsed_strs = retDict_tpm2['retout']
log_parsed_data = config.yaml_to_dict(log_parsed_strs, add_newlines=False)
log_parsed_data = config.yaml_to_dict(log_parsed_strs, add_newlines=False, logger=logger)
if log_parsed_data is None:
return None
#pylint: disable=import-outside-toplevel
try:
from keylime import tpm_bootlog_enrich
Expand Down