Skip to content
Permalink
Browse files Browse the repository at this point in the history
validators: create validators module
Move from the config module some validators, and create the validators
module.  Add tests for them.

Signed-off-by: Alberto Planas <aplanas@suse.com>
  • Loading branch information
aplanas authored and mpeters committed Jan 27, 2022
1 parent ea5d037 commit 65c2b73
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 44 deletions.
4 changes: 2 additions & 2 deletions keylime/cloud_verifier_common.py
Expand Up @@ -16,7 +16,7 @@
from keylime.failure import Failure, Component
from keylime.tpm.tpm_main import tpm
from keylime.tpm.tpm_abstract import TPM_Utilities
from keylime.common import algorithms
from keylime.common import algorithms, validators
from keylime import ima_file_signatures

# setup logging
Expand Down Expand Up @@ -300,7 +300,7 @@ def validate_agent_data(agent_data):
lists = json.loads(agent_data['allowlist'])

# Validate exlude list contains valid regular expressions
is_valid, _, err_msg = config.valid_exclude_list(lists.get('exclude'))
is_valid, _, err_msg = validators.valid_exclude_list(lists.get('exclude'))
if not is_valid:
err_msg += " Exclude list regex is misformatted. Please correct the issue and try again."

Expand Down
34 changes: 34 additions & 0 deletions keylime/common/validators.py
@@ -0,0 +1,34 @@
"""Validators module."""
import re


def valid_regex(regex):
"""Check if string is a valid regular expression."""
if regex is None:
return True, None, None

try:
compiled_regex = re.compile(regex)
except re.error as regex_err:
err = "Invalid regex: " + regex_err.msg + "."
return False, None, err

return True, compiled_regex, None


def valid_exclude_list(exclude_list):
"""Check if the list is composed of valid regex."""
if not exclude_list:
return True, None, None

combined_regex = "(" + ")|(".join(exclude_list) + ")"
return valid_regex(combined_regex)


def valid_hex(value):
"""Check if the string is a valid hex number representation."""
try:
int(value, 16)
except Exception:
return False
return True
32 changes: 0 additions & 32 deletions keylime/config.py
Expand Up @@ -5,7 +5,6 @@
import os
import os.path
import configparser
import re
from typing import Optional

import yaml
Expand Down Expand Up @@ -179,37 +178,6 @@ def yaml_to_dict(arry, add_newlines=True, logger=None) -> Optional[dict]:
return None


def valid_exclude_list(exclude_list):
if not exclude_list:
return True, None, None

combined_regex = "(" + ")|(".join(exclude_list) + ")"
return valid_regex(combined_regex)


def valid_regex(regex):
if regex is None:
return True, None, None

try:
compiled_regex = re.compile(regex)
except re.error as regex_err:
err = "Invalid regex: " + regex_err.msg + "."
return False, None, err

return True, compiled_regex, None


def valid_hex(value: str):
if not value.isalnum():
return False
try:
int(value, 16)
return True
except ValueError:
return False


if STUB_IMA:
IMA_ML = '../scripts/ima/ascii_runtime_measurements'
else:
Expand Down
15 changes: 7 additions & 8 deletions keylime/ima.py
Expand Up @@ -15,11 +15,11 @@

from keylime import config
from keylime import gpg
from keylime import keylime_logging
from keylime import ima_ast
from keylime.agentstates import AgentAttestState
from keylime import ima_file_signatures
from keylime.common.algorithms import Hash
from keylime import keylime_logging
from keylime.agentstates import AgentAttestState
from keylime.common import algorithms, validators
from keylime.failure import Failure, Component


Expand Down Expand Up @@ -223,15 +223,14 @@ def _process_measurement_list(agentAttestState, lines, hash_alg, lists=None, m2w
allow_list = None
exclude_list = None

ima_log_hash_alg = Hash.SHA1
ima_log_hash_alg = algorithms.Hash.SHA1
if allow_list is not None:
try:
ima_log_hash_alg = Hash(allow_list["ima"]["log_hash_alg"])
ima_log_hash_alg = algorithms.Hash(allow_list["ima"]["log_hash_alg"])
except ValueError:
logger.warning("Specified IMA log hash algorithm %s is not a valid algorithm! Defaulting to SHA1.",
allow_list["ima"]["log_hash_alg"])


if boot_aggregates and allow_list:
if 'boot_aggregate' not in allow_list['hashes'] :
allow_list['hashes']['boot_aggregate'] = []
Expand All @@ -240,7 +239,7 @@ def _process_measurement_list(agentAttestState, lines, hash_alg, lists=None, m2w
if val not in allow_list['hashes']['boot_aggregate'] :
allow_list['hashes']['boot_aggregate'].append(val)

is_valid, compiled_regex, err_msg = config.valid_exclude_list(exclude_list)
is_valid, compiled_regex, err_msg = validators.valid_exclude_list(exclude_list)
if not is_valid:
# This should not happen as the exclude list has already been validated
# by the verifier before acceping it. This is a safety net just in case.
Expand Down Expand Up @@ -312,7 +311,7 @@ def _process_measurement_list(agentAttestState, lines, hash_alg, lists=None, m2w


def process_measurement_list(agentAttestState, lines, lists=None, m2w=None, pcrval=None, ima_keyrings=None,
boot_aggregates=None, hash_alg=Hash.SHA1):
boot_aggregates=None, hash_alg=algorithms.Hash.SHA1):
failure = Failure(Component.IMA)
try:
running_hash, failure = _process_measurement_list(agentAttestState, lines, hash_alg, lists=lists, m2w=m2w,
Expand Down
4 changes: 2 additions & 2 deletions keylime/keylime_agent.py
Expand Up @@ -43,7 +43,7 @@
from keylime import secure_mount
from keylime import web_util
from keylime import api_version as keylime_api_version
from keylime.common import algorithms
from keylime.common import algorithms, validators
from keylime.tpm.tpm_main import tpm
from keylime.tpm.tpm_abstract import TPM_Utilities
from keylime.tpm.tpm2_objects import pubkey_from_tpm2b_public
Expand Down Expand Up @@ -131,7 +131,7 @@ def do_GET(self):

# Sanitization assurance (for tpm.run() tasks below)
if not (nonce.isalnum() and
(pcrmask is None or config.valid_hex(pcrmask)) and
(pcrmask is None or validators.valid_hex(pcrmask)) and
ima_ml_entry.isalnum()):
logger.warning('GET quote returning 400 response. parameters should be strictly alphanumeric')
web_util.echo_json_response(
Expand Down
82 changes: 82 additions & 0 deletions test/test_validators.py
@@ -0,0 +1,82 @@
import unittest

from keylime.common import validators


class TestValidRegex(unittest.TestCase):
"""Tests for valid_regex."""

def test_none(self):
"""Check that None is a valid regex."""
self.assertEqual(validators.valid_regex(None), (True, None, None))

def test_valid(self):
"""Check a well formed regex."""
value = validators.valid_regex(r"a.*")
self.assertTrue(value[0])
self.assertEqual(value[1].pattern, r"a.*")
self.assertEqual(value[2], None)

def test_invalid(self):
"""Check a not valid regex."""
value = validators.valid_regex(r"a[")
self.assertEqual(
value, (False, None, "Invalid regex: unterminated character set.")
)


class TestValidExcludeList(unittest.TestCase):
"""Tests for valid_exclude_list."""

def test_none(self):
"""Check that the empty list is valid."""
self.assertEqual(validators.valid_exclude_list(None), (True, None, None))

def test_single(self):
"""Check a single exclude list element."""
value = validators.valid_exclude_list([r"a.*"])
self.assertTrue(value[0])
self.assertEqual(value[1].pattern, r"(a.*)")
self.assertEqual(value[2], None)

def test_multi(self):
"""Check a multiple elements exclude list."""
value = validators.valid_exclude_list([r"a.*", r"b.*"])
self.assertTrue(value[0])
self.assertEqual(value[1].pattern, r"(a.*)|(b.*)")
self.assertEqual(value[2], None)

def test_invalid(self):
"""Check an invalid exclude list."""
value = validators.valid_exclude_list([r"a["])
self.assertEqual(
value, (False, None, "Invalid regex: unterminated character set.")
)


class TestValidHex(unittest.TestCase):
"""Tests for valid_hex."""

def test_none(self):
"""Check that None is not valid."""
self.assertFalse(validators.valid_hex(None))

def test_empty(self):
"""Check that the empty string is not valid."""
self.assertFalse(validators.valid_hex(""))

def test_valid_lower(self):
"""Check a valid lower case hexadecimal number."""
self.assertTrue(validators.valid_hex("123abc"))

def test_valid_upper(self):
"""Check a valid upper case hexadecimal number."""
self.assertTrue(validators.valid_hex("123ABC"))

def test_invalid(self):
"""Check and invalid hexadecimal number."""
self.assertFalse(validators.valid_hex("123xyz"))


if __name__ == "__main__":
unittest.main()

0 comments on commit 65c2b73

Please sign in to comment.