Skip to content

Commit

Permalink
validators: create validators module
Browse files Browse the repository at this point in the history
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.