Example #1
0
 def test_sign_ec(self):
     try:
         signing.verify_signature_from_file(
             f"{TEST_FILES}/allowlist-ec-key.pem",
             f"{TEST_FILES}/allowlist.json",
             f"{TEST_FILES}/allowlist-ec-sig.bin", "Testing Allowlist")
     except Exception as e:
         self.fail(f"Signing raised exception: {e}!")
Example #2
0
 def test_sign_bad_sig(self):
     try:
         signing.verify_signature_from_file(
             f"{TEST_FILES}/allowlist-pgp-key.pgp",
             f"{TEST_FILES}/allowlist.json",
             f"{TEST_FILES}/allowlist-invalid-sig.sig", "Testing Allowlist")
         self.fail("Signing passed with invalid signature!")
     except Exception:
         pass
Example #3
0
 def test_sign_gpg(self):
     try:
         signing.verify_signature_from_file(
             f"{TEST_FILES}/allowlist-pgp-key.pgp",
             f"{TEST_FILES}/allowlist.json",
             f"{TEST_FILES}/allowlist-pgp-sig.sig",
             "Testing Allowlist",
         )
     except Exception as e:
         self.fail(f"Signing raised exception: {e}!")
Example #4
0
def read_allowlist(al_path=None, checksum="", gpg_sig_file=None, gpg_key_file=None):
    if al_path is None:
        al_path = config.get("tenant", "ima_allowlist")

    # If user only wants signatures then an allowlist is not required
    if al_path is None or al_path == "":
        return copy.deepcopy(empty_allowlist)

    # Purposefully die if path doesn't exist
    with open(al_path, "rb") as f:
        pass

    # verify GPG signature if needed
    if gpg_sig_file and gpg_key_file:
        signing.verify_signature_from_file(gpg_key_file, al_path, gpg_sig_file, "allowlist")

    # Purposefully die if path doesn't exist
    with open(al_path, "rb") as f:
        logger.debug("Loading allowlist from %s", al_path)
        alist_bytes = f.read()
        sha256 = hashlib.sha256()
        sha256.update(alist_bytes)
        calculated_checksum = sha256.hexdigest()
        alist_raw = alist_bytes.decode("utf-8")
        logger.debug("Loaded allowlist from %s with checksum %s", al_path, calculated_checksum)

    if checksum:
        if checksum == calculated_checksum:
            logger.debug("Allowlist passed checksum validation")
        else:
            raise Exception(
                f"Checksum of allowlist does not match! Expected {checksum}, Calculated {calculated_checksum}"
            )

    # if the first non-whitespace character in the file is '{' treat it as the new JSON format
    p = re.compile(r"^\s*{")
    if p.match(alist_raw):
        logger.debug("Reading allow list as JSON format")
        alist = json.loads(alist_raw)

        # verify it's the current version
        if "meta" in alist and "version" in alist["meta"]:
            version = alist["meta"]["version"]
            if int(version) <= ALLOWLIST_CURRENT_VERSION:
                logger.debug("Allowlist has compatible version %s", version)
            else:
                # in the future we will support multiple versions and convert between them,
                # but for now there is only one
                raise Exception("Allowlist has unsupported version {version}")
        else:
            logger.debug("Allowlist does not specify a version. Assuming current version %s", ALLOWLIST_CURRENT_VERSION)

    else:
        # convert legacy format into new structured format
        logger.debug("Converting legacy allowlist format to JSON")

        alist = copy.deepcopy(empty_allowlist)
        alist["meta"]["timestamp"] = str(datetime.datetime.now())
        alist["meta"]["generator"] = "keylime-legacy-format-upgrade"
        if checksum:
            alist["meta"]["checksum"] = checksum

        for line in alist_raw.splitlines():
            line = line.strip()
            if len(line) == 0:
                continue

            pieces = line.split(None, 1)
            if not len(pieces) == 2:
                logger.warning("Line in AllowList does not consist of hash and file path: %s", line)
                continue

            (checksum_hash, path) = pieces

            if path.startswith("%keyring:"):
                entrytype = "keyrings"
                path = path[len("%keyring:") :]  # remove leading '%keyring:' from path to get keyring name
            else:
                entrytype = "hashes"

            if path in alist[entrytype]:
                alist[entrytype][path].append(checksum_hash)
            else:
                alist[entrytype][path] = [checksum_hash]

    alist = update_allowlist(alist)

    return alist