From fe84002c20e84625154dc67b61c9fd04cd90d577 Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Fri, 25 Oct 2024 15:58:33 +0300 Subject: [PATCH] import keylime-7.9.0-7.el10 --- .gitignore | 2 + .keylime.metadata | 2 + SOURCES/0001-Restore-create-allowlist.patch | 389 +++++++++++ .../0002-Use-TLS-on-revocation-webhook.patch | 168 +++++ SOURCES/keylime.sysusers | 2 + SPECS/keylime.spec | 613 ++++++++++++++++++ 6 files changed, 1176 insertions(+) create mode 100644 .gitignore create mode 100644 .keylime.metadata create mode 100644 SOURCES/0001-Restore-create-allowlist.patch create mode 100644 SOURCES/0002-Use-TLS-on-revocation-webhook.patch create mode 100644 SOURCES/keylime.sysusers create mode 100644 SPECS/keylime.spec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5848b87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +SOURCES/keylime-selinux-38.1.0.tar.gz +SOURCES/v7.9.0.tar.gz diff --git a/.keylime.metadata b/.keylime.metadata new file mode 100644 index 0000000..e31fcf0 --- /dev/null +++ b/.keylime.metadata @@ -0,0 +1,2 @@ +1bdc12a3d0baf4a01d6abdca0efffd0a7c5e2ebd SOURCES/keylime-selinux-38.1.0.tar.gz +0a1cb85dc9c884869e486d09f0507b784647bc57 SOURCES/v7.9.0.tar.gz diff --git a/SOURCES/0001-Restore-create-allowlist.patch b/SOURCES/0001-Restore-create-allowlist.patch new file mode 100644 index 0000000..e5c23f4 --- /dev/null +++ b/SOURCES/0001-Restore-create-allowlist.patch @@ -0,0 +1,389 @@ +--- a/scripts/create_runtime_policy.sh 2024-01-30 18:17:19.000000000 +0100 ++++ b/scripts/create_runtime_policy.sh 2024-08-16 17:25:50.871701853 +0200 +@@ -1,282 +1,155 @@ +-#!/usr/bin/env bash ++#!/usr/bin/bash + ################################################################################ + # SPDX-License-Identifier: Apache-2.0 + # Copyright 2017 Massachusetts Institute of Technology. + ################################################################################ + +- +-if [ $0 != "-bash" ] ; then +- pushd `dirname "$0"` > /dev/null 2>&1 +-fi +-KCRP_BASE_DIR=$(pwd) +-if [ $0 != "-bash" ] ; then +- popd 2>&1 > /dev/null +-fi +-KCRP_BASE_DIR=$KCRP_BASE_DIR/.. +- +-function detect_hash { +- local hashstr=$1 +- +- case "${#hashstr}" in +- 32) hashalgo=md5sum ;; +- 40) hashalgo=sha1sum ;; +- 64) hashalgo=sha256sum ;; +- 128) hashalgo=sha512sum ;; +- *) hashalgo="na";; +- esac +- +- echo $hashalgo +-} +- +-function announce { +- # 1 - MESSAGE +- +- MESSAGE=$(echo "${1}" | tr '\n' ' ') +- MESSAGE=$(echo $MESSAGE | sed "s/\t\t*/ /g") +- +- echo "==> $(date) - ${0} - $MESSAGE" +-} +- +-function valid_algo { +- local algo=$1 +- +- [[ " ${ALGO_LIST[@]} " =~ " ${algo} " ]] +-} +- + # Configure the installer here + INITRAMFS_TOOLS_GIT=https://salsa.debian.org/kernel-team/initramfs-tools.git + INITRAMFS_TOOLS_VER="master" + +-# All defaults +-ALGO=sha1sum +-WORK_DIR=/tmp/kcrp +-OUTPUT_DIR=${WORK_DIR}/output +-ALLOWLIST_DIR=${WORK_DIR}/allowlist +-INITRAMFS_LOC="/boot/" +-INITRAMFS_STAGING_DIR=${WORK_DIR}/ima_ramfs/ +-INITRAMFS_TOOLS_DIR=${WORK_DIR}/initramfs-tools +-BOOT_AGGREGATE_LOC="/sys/kernel/security/ima/ascii_runtime_measurements" +-ROOTFS_LOC="/" +-EXCLUDE_LIST="none" +-SKIP_PATH="none" +-ALGO_LIST=("sha1sum" "sha256sum" "sha512sum") ++WORKING_DIR=$(readlink -f "$0") ++WORKING_DIR=$(dirname "$WORKING_DIR") + + # Grabs Debian's initramfs_tools from Git repo if no other options exist + if [[ ! `command -v unmkinitramfs` && ! -x "/usr/lib/dracut/skipcpio" ]] ; then + # Create temp dir for pulling in initramfs-tools +- announce "INFO: Downloading initramfs-tools: $INITRAMFS_TOOLS_DIR" ++ TMPDIR=`mktemp -d` || exit 1 ++ echo "INFO: Downloading initramfs-tools: $TMPDIR" + +- mkdir -p $INITRAMFS_TOOLS_DIR + # Clone initramfs-tools repo +- pushd $INITRAMFS_TOOLS_DIR > /dev/null 2>&1 +- git clone $INITRAMFS_TOOLS_GIT initramfs-tools > /dev/null 2>&1 +- pushd initramfs-tools > /dev/null 2>&1 +- git checkout $INITRAMFS_TOOLS_VER > /dev/null 2>&1 +- popd > /dev/null 2>&1 +- popd > /dev/null 2>&1 ++ pushd $TMPDIR ++ git clone $INITRAMFS_TOOLS_GIT initramfs-tools ++ pushd initramfs-tools ++ git checkout $INITRAMFS_TOOLS_VER ++ popd # $TMPDIR ++ popd + + shopt -s expand_aliases +- alias unmkinitramfs=$INITRAMFS_TOOLS_DIR/initramfs-tools/unmkinitramfs +- +- which unmkinitramfs > /dev/null 2>&1 || exit 1 ++ alias unmkinitramfs=$TMPDIR/initramfs-tools/unmkinitramfs + fi + ++ + if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" 1>&2 + exit 1 + fi + +-USAGE=$(cat <<-END +- Usage: $0 -o/--output_file FILENAME [-a/--algo ALGO] [-x/--ramdisk-location PATH] [-y/--boot_aggregate-location PATH] [-z/--rootfs-location PATH] [-e/--exclude_list FILENAME] [-s/--skip-path PATH] [-h/--help] ++if [ $# -lt 1 ] ++then ++ echo "No arguments provided" >&2 ++ echo "Usage: `basename $0` -o [filename] -h [hash-algo]" >&2 ++ exit $NOARGS; ++fi + +- optional arguments: +- -a/--algo (checksum algorithm to be used, default: $ALGO) +- -x/--ramdisk-location (path to initramdisk, default: $INITRAMFS_LOC, set to "none" to skip) +- -y/--boot_aggregate-location (path for IMA log, used for boot aggregate extraction, default: $BOOT_AGGREGATE_LOC, set to "none" to skip) +- -z/--rootfs-location (path to root filesystem, default: $ROOTFS_LOC, cannot be skipped) +- -e/--exclude_list (filename containing a list of paths to be excluded (i.e., verifier will not try to match checksums, default: $EXCLUDE_LIST) +- -s/--skip-path (comma-separated path list, files found there will not have checksums calculated, default: $SKIP_PATH) +- -h/--help (show this message and exit) +-END +-) ++ALGO=sha256sum + +-while [[ $# -gt 0 ]] +-do +- key="$1" ++ALGO_LIST=("sha1sum" "sha256sum" "sha512sum") ++ ++valid_algo() { ++ local algo=$1 + +- case $key in +- -a|--algo) +- ALGO="$2" +- shift +- ;; +- -a=*|--algo=*) +- ALGO=$(echo $key | cut -d '=' -f 2) +- ;; +- -x|--ramdisk-location) +- INITRAMFS_LOC="$2" +- shift +- ;; +- -x=*|--ramdisk-location=*) +- INITRAMFS_LOC=$(echo $key | cut -d '=' -f 2) +- ;; +- -y|--boot_aggregate-location) +- BOOT_AGGREGATE_LOC=$2 +- shift +- ;; +- -y=*|--boot_aggregate-location=*) +- BOOT_AGGREGATE_LOC=$(echo $key | cut -d '=' -f 2) +- ;; +- -z|--rootfs-location) +- ROOTFS_LOC=$2 +- shift +- ;; +- -z=*|--rootfs-location=*) +- ROOTFS_LOC=$(echo $key | cut -d '=' -f 2) +- ;; +- -e|--exclude_list) +- EXCLUDE_LIST=$2 +- shift +- ;; +- -e=*|--exclude_list=*) +- EXCLUDE_LIST=$(echo $key | cut -d '=' -f 2) +- ;; +- -o=*|--output_file=*) +- OUTPUT=$(echo $key | cut -d '=' -f 2) +- ;; +- -o|--output_file) +- OUTPUT=$2 +- shift +- ;; +- -s=*|--skip-path=*) +- SKIP_PATH=$(echo $key | cut -d '=' -f 2) +- ;; +- -s|--skip-path) +- SKIP_PATH=$2 +- shift +- ;; +- -h|--help) +- printf "%s\n" "$USAGE" +- exit 0 +- shift +- ;; +- *) +- # unknown option +- ;; +- esac +- shift ++ [[ " ${ALGO_LIST[@]} " =~ " ${algo} " ]] ++} ++ ++while getopts ":o:h:" opt; do ++ case $opt in ++ o) ++ OUTPUT=$(readlink -f $OPTARG) ++ rm -f $OUTPUT ++ ;; ++ h) ++ if valid_algo $OPTARG; then ++ ALGO=$OPTARG ++ else ++ echo "Invalid hash function argument: use sha1sum, sha256sum, or sha512sum" ++ exit 1 ++ fi ++ ;; ++ esac + done + +-if ! valid_algo $ALGO ++if [ ! "$OUTPUT" ] + then +- echo "Invalid hash function argument: pick from \"${ALGO_LIST[@]}\"" ++ echo "Missing argument for -o" >&2; ++ echo "Usage: $0 -o [filename] -h [hash-algo]" >&2; + exit 1 + fi + +-if [[ -z $OUTPUT ]] +-then +- printf "%s\n" "$USAGE" +- exit 1 ++ ++# Where to look for initramfs image ++INITRAMFS_LOC="/boot" ++if [ -d "/ostree" ]; then ++ # If we are on an ostree system change where we look for initramfs image ++ loc=$(grep -E "/ostree/[^/]([^/]*)" -o /proc/cmdline | head -n 1 | cut -d / -f 3) ++ INITRAMFS_LOC="/boot/ostree/${loc}/" + fi + +-rm -rf $ALLOWLIST_DIR +-rm -rf $INITRAMFS_STAGING_DIR +-rm -rf $OUTPUT_DIR + +-announce "Writing allowlist $ALLOWLIST_DIR/${OUTPUT} with $ALGO..." +-mkdir -p $ALLOWLIST_DIR ++echo "Writing allowlist to $OUTPUT with $ALGO..." + +-if [[ $BOOT_AGGREGATE_LOC != "none" ]] +-then +- announce "--- Adding boot agregate from $BOOT_AGGREGATE_LOC on allowlist $ALLOWLIST_DIR/${OUTPUT} ..." + # Add boot_aggregate from /sys/kernel/security/ima/ascii_runtime_measurements (IMA Log) file. + # The boot_aggregate measurement is always the first line in the IMA Log file. + # The format of the log lines is the following: + # + # File_Digest may start with the digest algorithm specified (e.g "sha1:", "sha256:") depending on the template used. +- head -n 1 $BOOT_AGGREGATE_LOC | awk '{ print $4 " boot_aggregate" }' | sed 's/.*://' >> $ALLOWLIST_DIR/${OUTPUT} ++head -n 1 /sys/kernel/security/ima/ascii_runtime_measurements | awk '{ print $4 " boot_aggregate" }' | sed 's/.*://' >> $OUTPUT + +- bagghash=$(detect_hash $(cat $ALLOWLIST_DIR/${OUTPUT} | cut -d ' ' -f 1)) +- if [[ $ALGO != $bagghash ]] +- then +- announce "ERROR: \"boot aggregate\" has was calculated with $bagghash, but files will be calculated with $ALGO. Use option -a $bagghash" +- exit 1 +- fi +-else +- announce "--- Skipping boot aggregate..." +-fi +- +-announce "--- Adding all appropriate files from $ROOTFS_LOC on allowlist $ALLOWLIST_DIR/${OUTPUT} ..." + # Add all appropriate files under root FS to allowlist +-pushd $ROOTFS_LOC > /dev/null 2>&1 +-BASE_EXCLUDE_DIRS="\bsys\b\|\brun\b\|\bproc\b\|\blost+found\b\|\bdev\b\|\bmedia\b\|\bsnap\b\|\bmnt\b\|\bvar\b\|\btmp\b" +-ROOTFS_FILE_LIST=$(ls | grep -v $BASE_EXCLUDE_DIRS) +-if [[ $SKIP_PATH != "none" ]] +-then +- SKIP_PATH=$(echo $SKIP_PATH | sed -e "s#^$ROOTFS_LOC##g" -e "s#,$ROOTFS_LOC##g" -e "s#,#\\\|#g") +- ROOTFS_FILE_LIST=$(echo "$ROOTFS_FILE_LIST" | grep -v "$SKIP_PATH") +-fi +-find $ROOTFS_FILE_LIST \( -fstype rootfs -o -xtype f -type l -o -type f \) -uid 0 -exec $ALGO "$ROOTFS_LOC/{}" >> $ALLOWLIST_DIR/${OUTPUT} \; +-popd > /dev/null 2>&1 ++cd / ++find `ls / | grep -v "\bsys\b\|\brun\b\|\bproc\b\|\blost+found\b\|\bdev\b\|\bmedia\b\|\bsnap\b\|mnt"` \( -fstype rootfs -o -xtype f -type l -o -type f \) -uid 0 -exec $ALGO '/{}' >> $OUTPUT \; + + # Create staging area for init ram images +-mkdir -p $INITRAMFS_STAGING_DIR +- +-if [[ $INITRAMFS_LOC != "none" ]] +-then +- # Where to look for initramfs image +- if [[ -d "/ostree" ]] +- then +- X=$INITRAMFS_LOC +- # If we are on an ostree system change where we look for initramfs image +- loc=$(grep -E "/ostree/[^/]([^/]*)" -o /proc/cmdline | head -n 1 | cut -d / -f 3) +- INITRAMFS_LOC="/boot/ostree/${loc}/" +- announce "--- The location of initramfs was overriden from \"${X}\" to \"$INITRAMFS_LOC\"" +- fi ++rm -rf /tmp/ima/ ++mkdir -p /tmp/ima + +- announce "--- Creating allowlist for init ram disks found under \"$INITRAMFS_LOC\" to $ALLOWLIST_DIR/${OUTPUT} ..." +- for i in $(ls ${INITRAMFS_LOC}/initr* 2> /dev/null) +- do +- announce " extracting $i" +- mkdir -p $INITRAMFS_STAGING_DIR/$i-extracted +- cd $INITRAMFS_STAGING_DIR/$i-extracted +- +- # platform-specific handling of init ram disk images +- if [[ `command -v unmkinitramfs` ]] ; then +- mkdir -p $INITRAMFS_STAGING_DIR/$i-extracted-unmk +- unmkinitramfs $i $INITRAMFS_STAGING_DIR/$i-extracted-unmk +- if [[ -d "$INITRAMFS_STAGING_DIR/$i-extracted-unmk/main/" ]] ; then +- cp -r $INITRAMFS_STAGING_DIR/$i-extracted-unmk/main/. /tmp/ima/$i-extracted +- else +- cp -r $INITRAMFS_STAGING_DIR/$i-extracted-unmk/. /tmp/ima/$i-extracted +- fi +- elif [[ -x "/usr/lib/dracut/skipcpio" ]] ; then +- /usr/lib/dracut/skipcpio $i | gunzip -c | cpio -i -d 2> /dev/null ++# Iterate through init ram disks and add files to allowlist ++echo "Creating allowlist for init ram disk" ++for i in `ls ${INITRAMFS_LOC}/initr*` ++do ++ echo "extracting $i" ++ mkdir -p /tmp/ima/$i-extracted ++ cd /tmp/ima/$i-extracted ++ ++ # platform-specific handling of init ram disk images ++ if [[ `command -v unmkinitramfs` ]] ; then ++ mkdir -p /tmp/ima/$i-extracted-unmk ++ unmkinitramfs $i /tmp/ima/$i-extracted-unmk ++ if [[ -d "/tmp/ima/$i-extracted-unmk/main/" ]] ; then ++ cp -r /tmp/ima/$i-extracted-unmk/main/. /tmp/ima/$i-extracted + else +- announce "ERROR: No tools for initramfs image processing found!" +- exit 1 ++ cp -r /tmp/ima/$i-extracted-unmk/. /tmp/ima/$i-extracted + fi ++ elif [[ -x "/usr/lib/dracut/skipcpio" ]] ; then ++ /usr/lib/dracut/skipcpio $i | gunzip -c 2> /dev/null | cpio -i -d 2> /dev/null ++ else ++ echo "ERROR: No tools for initramfs image processing found!" ++ break ++ fi + +- find -type f -exec $ALGO "./{}" \; | sed "s| \./\./| /|" >> $ALLOWLIST_DIR/${OUTPUT} +- done +-fi ++ find -type f -exec $ALGO "./{}" \; | sed "s| \./\./| /|" >> $OUTPUT ++done + +-# Non-critical cleanup on the resulting file (when ROOTFS_LOC = '/', the path starts on allowlist ends up with double '//' ) +-sed -i "s^ //^ /^g" $ALLOWLIST_DIR/${OUTPUT} +-# A bit of cleanup on the resulting file (among other problems, sha256sum might output a hash with the prefix '\\') +-sed -i "s/^\\\//g" $ALLOWLIST_DIR/${OUTPUT} +- +-# Convert to runtime policy +-mkdir -p $OUTPUT_DIR +-announce "Converting created allowlist ($ALLOWLIST_DIR/${OUTPUT}) to Keylime runtime policy ($OUTPUT_DIR/${OUTPUT}) ..." +-CONVERT_CMD_OPTS="--allowlist $ALLOWLIST_DIR/${OUTPUT} --output_file $OUTPUT_DIR/${OUTPUT}" +-[ -f $EXCLUDE_LIST ] && CONVERT_CMD_OPTS="$CONVERT_CMD_OPTS --excludelist $EXCLUDE_LIST" +- +-pushd $KCRP_BASE_DIR > /dev/null 2>&1 +-export PYTHONPATH=$KCRP_BASE_DIR:$PYTHONPATH +-# only 3 dependencies required: pip3 install cryptography lark packaging +-python3 ./keylime/cmd/convert_runtime_policy.py $CONVERT_CMD_OPTS; echo " " +-if [[ $? -eq 0 ]] +-then +- announce "Done, new runtime policy file present at ${OUTPUT_DIR}/$OUTPUT. It can be used on the tenant keylime host with \"keylime_tenant -c add --runtime-policy ${OUTPUT_DIR}/$OUTPUT " +-fi +-popd > /dev/null 2>&1 ++# when ROOTFS_LOC = '/', the path starts on allowlist ends up with double '//' ++# ++# Example: ++# ++# b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c //bar ++# ++# Replace the unwanted '//' with a single '/' ++sed -i 's| /\+| /|g' ${OUTPUT} ++ ++# When the file name contains newlines or backslashes, the output of sha256sum ++# adds a backslash at the beginning of the line. ++# ++# Example: ++# ++# $ echo foo > ba\\r ++# $ sha256sum ba\\r ++# \b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c ba\\r ++# ++# Remove the unwanted backslash prefix ++sed -i 's/^\\//g' ${OUTPUT} ++ ++# Clean up ++rm -rf /tmp/ima diff --git a/SOURCES/0002-Use-TLS-on-revocation-webhook.patch b/SOURCES/0002-Use-TLS-on-revocation-webhook.patch new file mode 100644 index 0000000..4b461fc --- /dev/null +++ b/SOURCES/0002-Use-TLS-on-revocation-webhook.patch @@ -0,0 +1,168 @@ +diff --git a/keylime/revocation_notifier.py b/keylime/revocation_notifier.py +index 112012b8f..5724af486 100644 +--- a/keylime/revocation_notifier.py ++++ b/keylime/revocation_notifier.py +@@ -140,7 +140,7 @@ def worker_webhook(tosend: Dict[str, Any], url: str) -> None: + for i in range(config.getint("verifier", "max_retries")): + next_retry = retry.retry_time(exponential_backoff, interval, i, logger) + try: +- response = session.post(url, json=tosend, timeout=5) ++ response = session.post(url, json=tosend, timeout=5, verify=requests.utils.DEFAULT_CA_BUNDLE_PATH) + if response.status_code in [200, 202]: + break + +diff --git a/keylime/requests_client.py b/keylime/requests_client.py +index 6da703264..16615f7d9 100644 +--- a/keylime/requests_client.py ++++ b/keylime/requests_client.py +@@ -1,3 +1,4 @@ ++import re + import ssl + from typing import Any, Dict, Optional + +@@ -15,6 +16,10 @@ def __init__( + ignore_hostname: bool = True, + **kwargs: Any, + ) -> None: ++ # Remove eventual "http?://" from the base url ++ if base_url.startswith("http"): ++ base_url = re.sub(r"https?://", "", base_url) ++ + if tls_enabled: + self.base_url = f"https://{base_url}" + else: +diff --git a/keylime/revocation_notifier.py b/keylime/revocation_notifier.py +index 5724af486..5a7cc4b16 100644 +--- a/keylime/revocation_notifier.py ++++ b/keylime/revocation_notifier.py +@@ -9,8 +9,9 @@ + + import requests + +-from keylime import config, crypto, json, keylime_logging ++from keylime import config, crypto, json, keylime_logging, web_util + from keylime.common import retry ++from keylime.requests_client import RequestsClient + + logger = keylime_logging.init_logging("revocation_notifier") + broker_proc: Optional[Process] = None +@@ -112,7 +113,10 @@ def worker(tosend: Dict[str, Any]) -> None: + exponential_backoff = config.getboolean("verifier", "exponential_backoff") + next_retry = retry.retry_time(exponential_backoff, interval, i, logger) + logger.debug( +- "Unable to publish revocation message %d times, trying again in %f seconds: %s", i, next_retry, e ++ "Unable to publish revocation message %d times, trying again in %f seconds: %s", ++ i, ++ next_retry, ++ e, + ) + time.sleep(next_retry) + mysock.close() +@@ -135,30 +139,50 @@ def notify_webhook(tosend: Dict[str, Any]) -> None: + def worker_webhook(tosend: Dict[str, Any], url: str) -> None: + interval = config.getfloat("verifier", "retry_interval") + exponential_backoff = config.getboolean("verifier", "exponential_backoff") +- with requests.Session() as session: +- logger.info("Sending revocation event via webhook...") +- for i in range(config.getint("verifier", "max_retries")): +- next_retry = retry.retry_time(exponential_backoff, interval, i, logger) ++ ++ max_retries = config.getint("verifier", "max_retries") ++ if max_retries <= 0: ++ logger.info("Invalid value found in 'max_retries' option for verifier, using default value") ++ max_retries = 5 ++ ++ # Get TLS options from the configuration ++ (cert, key, trusted_ca, key_password), verify_server_cert = web_util.get_tls_options( ++ "verifier", is_client=True, logger=logger ++ ) ++ ++ # Generate the TLS context using the obtained options ++ tls_context = web_util.generate_tls_context(cert, key, trusted_ca, key_password, is_client=True, logger=logger) ++ ++ logger.info("Sending revocation event via webhook to %s ...", url) ++ for i in range(max_retries): ++ next_retry = retry.retry_time(exponential_backoff, interval, i, logger) ++ ++ with RequestsClient( ++ url, ++ verify_server_cert, ++ tls_context, ++ ) as client: + try: +- response = session.post(url, json=tosend, timeout=5, verify=requests.utils.DEFAULT_CA_BUNDLE_PATH) +- if response.status_code in [200, 202]: +- break +- +- logger.debug( +- "Unable to publish revocation message %d times via webhook, " +- "trying again in %d seconds. " +- "Server returned status code: %s", +- i, +- next_retry, +- response.status_code, +- ) +- except requests.exceptions.RequestException as e: +- logger.debug( +- "Unable to publish revocation message %d times via webhook, trying again in %d seconds: %s", +- i, +- next_retry, +- e, +- ) ++ res = client.post("", json=tosend, timeout=5) ++ except requests.exceptions.SSLError as ssl_error: ++ if "TLSV1_ALERT_UNKNOWN_CA" in str(ssl_error): ++ logger.warning( ++ "Keylime does not recognize certificate from peer. Check if verifier 'trusted_server_ca' is configured correctly" ++ ) ++ ++ raise ssl_error from ssl_error ++ ++ if res and res.status_code in [200, 202]: ++ break ++ ++ logger.debug( ++ "Unable to publish revocation message %d times via webhook, " ++ "trying again in %d seconds. " ++ "Server returned status code: %s", ++ i + 1, ++ next_retry, ++ res.status_code, ++ ) + + time.sleep(next_retry) + +@@ -170,7 +194,11 @@ def worker_webhook(tosend: Dict[str, Any], url: str) -> None: + cert_key = None + + +-def process_revocation(revocation: Dict[str, Any], callback: Callable[[Dict[str, Any]], None], cert_path: str) -> None: ++def process_revocation( ++ revocation: Dict[str, Any], ++ callback: Callable[[Dict[str, Any]], None], ++ cert_path: str, ++) -> None: + global cert_key + + if cert_key is None: +@@ -182,10 +210,17 @@ def process_revocation(revocation: Dict[str, Any], callback: Callable[[Dict[str, + cert_key = crypto.x509_import_pubkey(certpem) + + if cert_key is None: +- logger.warning("Unable to check signature of revocation message: %s not available", cert_path) ++ logger.warning( ++ "Unable to check signature of revocation message: %s not available", ++ cert_path, ++ ) + elif "signature" not in revocation or revocation["signature"] == "none": + logger.warning("No signature on revocation message from server") +- elif not crypto.rsa_verify(cert_key, revocation["msg"].encode("utf-8"), revocation["signature"].encode("utf-8")): ++ elif not crypto.rsa_verify( ++ cert_key, ++ revocation["msg"].encode("utf-8"), ++ revocation["signature"].encode("utf-8"), ++ ): + logger.error("Invalid revocation message siganture %s", revocation) + else: + message = json.loads(revocation["msg"]) + diff --git a/SOURCES/keylime.sysusers b/SOURCES/keylime.sysusers new file mode 100644 index 0000000..4979d46 --- /dev/null +++ b/SOURCES/keylime.sysusers @@ -0,0 +1,2 @@ +u keylime - "Keylime unprivileged user" /var/lib/keylime /usr/sbin/nologin +m keylime tss diff --git a/SPECS/keylime.spec b/SPECS/keylime.spec new file mode 100644 index 0000000..a732f2d --- /dev/null +++ b/SPECS/keylime.spec @@ -0,0 +1,613 @@ +## START: Set by rpmautospec +## (rpmautospec version 0.6.5) +## RPMAUTOSPEC: autorelease, autochangelog +%define autorelease(e:s:pb:n) %{?-p:0.}%{lua: + release_number = 7; + base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); + print(release_number + base_release_number - 1); +}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} +## END: Set by rpmautospec + +%global srcname keylime +%global policy_version 38.1.0 + +# Package is actually noarch, but it has an optional dependency that is +# arch-specific. +%global debug_package %{nil} +%global with_selinux 1 +%global selinuxtype targeted + +Name: keylime +Version: 7.9.0 +Release: %autorelease +Summary: Open source TPM software for Bootstrapping and Maintaining Trust + +URL: https://github.com/keylime/keylime +Source0: https://github.com/keylime/keylime/archive/refs/tags/v%{version}.tar.gz +Source1: %{srcname}.sysusers +# The selinux policy for keylime is distributed via this repo: https://github.com/RedHat-SP-Security/keylime-selinux +Source2: https://github.com/RedHat-SP-Security/%{name}-selinux/archive/v%{policy_version}/keylime-selinux-%{policy_version}.tar.gz + +# Restore the create_allowlist.sh script +# https://issues.redhat.com/browse/RHEL-32637 +Patch1: 0001-Restore-create-allowlist.patch +# Use TLS for the revocation notification webhook +# Take into account CA certificates added by configuration file +# Include the system installed CA certificates +# https://issues.redhat.com/browse/RHEL-49601 +# https://issues.redhat.com/browse/RHEL-51279 +# https://issues.redhat.com/browse/RHEL-51321 +Patch2: 0002-Use-TLS-on-revocation-webhook.patch + +# Main program: Apache-2.0 +# Icons: MIT +License: Apache-2.0 AND MIT + +BuildRequires: git-core +BuildRequires: swig +BuildRequires: openssl-devel +BuildRequires: python3-devel +BuildRequires: python3-dbus +BuildRequires: python3-jinja2 +BuildRequires: python3-setuptools +BuildRequires: systemd-rpm-macros + +Requires: python3-%{srcname} = %{version}-%{release} +Requires: %{srcname}-base = %{version}-%{release} +Requires: %{srcname}-verifier = %{version}-%{release} +Requires: %{srcname}-registrar = %{version}-%{release} +Requires: %{srcname}-tenant = %{version}-%{release} +Requires: %{srcname}-tools = %{version}-%{release} + +# webapp was removed upstream in release 6.4.2. +Obsoletes: %{srcname}-webapp < 6.4.2 + +# python agent was removed upstream in release 7.0.0. +Obsoletes: python3-%{srcname}-agent < 7.0.0 + +# Agent. +Requires: keylime-agent +Suggests: %{srcname}-agent-rust + +# Conflicts with the monolithic versions of the package, before the split. +Conflicts: keylime < 6.3.0-3 + +%{?python_enable_dependency_generator} +%description +Keylime is a TPM based highly scalable remote boot attestation +and runtime integrity measurement solution. + +%package base +Summary: The base package contains the default configuration +License: MIT + +# Conflicts with the monolithic versions of the package, before the split. +Conflicts: keylime < 6.3.0-3 + +Requires(pre): python3-jinja2 +Requires(pre): shadow-utils +Requires: procps-ng +Requires: tpm2-tss +Requires: openssl + +%if 0%{?with_selinux} +# This ensures that the *-selinux package and all it’s dependencies are not pulled +# into containers and other systems that do not use SELinux +Recommends: (%{srcname}-selinux if selinux-policy-%{selinuxtype}) +%endif + +%ifarch %efi +Requires: efivar-libs +%endif + + +%description base +The base package contains the Keylime default configuration + +%package -n python3-%{srcname} +Summary: The Python Keylime module +License: MIT + +# Conflicts with the monolithic versions of the package, before the split. +Conflicts: keylime < 6.3.0-3 + +Requires: %{srcname}-base = %{version}-%{release} +%{?python_provide:%python_provide python3-%{srcname}} + +Requires: python3-tornado +Requires: python3-sqlalchemy +Requires: python3-alembic +Requires: python3-cryptography +Requires: python3-pyyaml +Requires: python3-packaging +Requires: python3-requests +Requires: python3-gpg +Requires: python3-lark-parser +Requires: python3-pyasn1 +Requires: python3-pyasn1-modules +Requires: python3-jsonschema +Requires: python3-typing-extensions +Requires: tpm2-tools + +%description -n python3-%{srcname} +The python3-keylime module implements the functionality used +by Keylime components. + +%package verifier +Summary: The Python Keylime Verifier component +License: MIT + +# Conflicts with the monolithic versions of the package, before the split. +Conflicts: keylime < 6.3.0-3 + +Requires: %{srcname}-base = %{version}-%{release} +Requires: python3-%{srcname} = %{version}-%{release} + +%description verifier +The Keylime Verifier continuously verifies the integrity state +of the machine that the agent is running on. + +%package registrar +Summary: The Keylime Registrar component +License: MIT + +# Conflicts with the monolithic versions of the package, before the split. +Conflicts: keylime < 6.3.0-3 + +Requires: %{srcname}-base = %{version}-%{release} +Requires: python3-%{srcname} = %{version}-%{release} + +%description registrar +The Keylime Registrar is a database of all agents registered +with Keylime and hosts the public keys of the TPM vendors. + +%if 0%{?with_selinux} +# SELinux subpackage +%package selinux +Summary: keylime SELinux policy +BuildArch: noarch +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux +Custom SELinux policy module +%endif + +%package tenant +Summary: The Python Keylime Tenant +License: MIT + +# Conflicts with the monolithic versions of the package, before the split. +Conflicts: keylime < 6.3.0-3 + +Requires: %{srcname}-base = %{version}-%{release} +Requires: python3-%{srcname} = %{version}-%{release} + + +%description tenant +The Keylime Tenant can be used to provision a Keylime Agent. + +%package tools +Summary: Keylime tools +License: MIT + +# Conflicts with the monolithic versions of the package, before the split. +Conflicts: keylime < 6.3.0-3 + +Requires: %{srcname}-base = %{version}-%{release} +Requires: python3-%{srcname} = %{version}-%{release} + +%description tools +The keylime tools package includes miscelaneous tools. + + +%prep +%autosetup -S git -n %{srcname}-%{version} -a2 + +%if 0%{?with_selinux} +# SELinux policy (originally from selinux-policy-contrib) +# this policy module will override the production module + +make -f %{_datadir}/selinux/devel/Makefile %{srcname}.pp +bzip2 -9 %{srcname}.pp +%endif + +%build +%py3_build + +%install +%py3_install +mkdir -p %{buildroot}/%{_sharedstatedir}/%{srcname} +mkdir -p --mode=0700 %{buildroot}/%{_rundir}/%{srcname} + +mkdir -p --mode=0700 %{buildroot}/%{_sysconfdir}/%{srcname}/ +for comp in "verifier" "tenant" "registrar" "ca" "logging"; do + mkdir -p --mode=0700 %{buildroot}/%{_sysconfdir}/%{srcname}/${comp}.conf.d + install -Dpm 400 config/${comp}.conf %{buildroot}/%{_sysconfdir}/%{srcname} +done + +# Ship some scripts. +mkdir -p %{buildroot}/%{_datadir}/%{srcname}/scripts +for s in create_mb_refstate \ + ek-openssl-verify; do + install -Dpm 755 scripts/${s} \ + %{buildroot}/%{_datadir}/%{srcname}/scripts/${s} +done + +# To keep the same functionality as in RHEL-9, install create_runtime_policy.sh +# as create_allowlist.sh in RHEL-10 +# The convert_runtime_policy.py script to convert allowlist and excludelist into +# runtime policy is not called anymore. +# See: https://issues.redhat.com/browse/RHEL-11866 +install -Dpm 755 scripts/create_runtime_policy.sh \ + %{buildroot}/%{_datadir}/%{srcname}/scripts/create_allowlist.sh + +# Ship configuration templates. +cp -r ./templates %{buildroot}%{_datadir}/%{srcname}/templates/ + +mkdir -p --mode=0755 %{buildroot}/%{_bindir} +install -Dpm 755 ./keylime/cmd/convert_config.py %{buildroot}/%{_bindir}/keylime_upgrade_config + +%if 0%{?with_selinux} +install -D -m 0644 %{srcname}.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{srcname}.pp.bz2 +install -D -p -m 0644 keylime-selinux-%{policy_version}/%{srcname}.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{srcname}.if +%endif + +install -Dpm 644 ./services/%{srcname}_verifier.service \ + %{buildroot}%{_unitdir}/%{srcname}_verifier.service + +install -Dpm 644 ./services/%{srcname}_registrar.service \ + %{buildroot}%{_unitdir}/%{srcname}_registrar.service + +cp -r ./tpm_cert_store %{buildroot}%{_sharedstatedir}/%{srcname}/ + +install -p -d %{buildroot}/%{_tmpfilesdir} +cat > %{buildroot}/%{_tmpfilesdir}/%{srcname}.conf << EOF +d %{_rundir}/%{srcname} 0700 %{srcname} %{srcname} - +EOF + +install -p -D -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/%{srcname}.conf + +%pre base +%sysusers_create_compat %{SOURCE1} +exit 0 + +%post base +/usr/bin/keylime_upgrade_config --component ca --component logging >/dev/null +exit 0 + +%posttrans base +if [ -d %{_sysconfdir}/%{srcname} ]; then + chmod 500 %{_sysconfdir}/%{srcname} + chown -R %{srcname}:%{srcname} %{_sysconfdir}/%{srcname} + + for comp in "verifier" "tenant" "registrar" "ca" "logging"; do + [ -d %{_sysconfdir}/%{srcname}/${comp}.conf.d ] && \ + chmod 500 %{_sysconfdir}/%{srcname}/${comp}.conf.d + done +fi + +[ -d %{_sharedstatedir}/%{srcname} ] && \ + chown -R %{srcname} %{_sharedstatedir}/%{srcname}/ + +[ -d %{_sharedstatedir}/%{srcname}/tpm_cert_store ] && \ + chmod 400 %{_sharedstatedir}/%{srcname}/tpm_cert_store/*.pem && \ + chmod 500 %{_sharedstatedir}/%{srcname}/tpm_cert_store/ + +[ -d %{_localstatedir}/log/%{srcname} ] && \ + chown -R %{srcname} %{_localstatedir}/log/%{srcname}/ +exit 0 + +%post verifier +/usr/bin/keylime_upgrade_config --component verifier >/dev/null +%systemd_post %{srcname}_verifier.service + +%post registrar +/usr/bin/keylime_upgrade_config --component registrar >/dev/null +%systemd_post %{srcname}_registrar.service + +%post tenant +/usr/bin/keylime_upgrade_config --component tenant >/dev/null +exit 0 + +%if 0%{?with_selinux} +# SELinux contexts are saved so that only affected files can be +# relabeled after the policy module installation +%pre selinux +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{srcname}.pp.bz2 +%selinux_relabel_post -s %{selinuxtype} + +if [ "$1" -le "1" ]; then # First install + # The services need to be restarted for the custom label to be + # applied in case they where already present in the system, + # restart fails silently in case they where not. + for svc in registrar verifier; do + [ -f "%{_unitdir}/%{srcname}_${svc}".service ] && \ + %systemd_postun_with_restart "%{srcname}_${svc}".service + done +fi +exit 0 + +%postun selinux +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{srcname} + %selinux_relabel_post -s %{selinuxtype} +fi +%endif + +%preun verifier +%systemd_preun %{srcname}_verifier.service + +%preun registrar +%systemd_preun %{srcname}_registrar.service + +%preun tenant +%systemd_preun %{srcname}_registrar.service + +%postun verifier +%systemd_postun_with_restart %{srcname}_verifier.service + +%postun registrar +%systemd_postun_with_restart %{srcname}_registrar.service + +%files verifier +%license LICENSE +%attr(500,%{srcname},%{srcname}) %dir %{_sysconfdir}/%{srcname}/verifier.conf.d +%config(noreplace) %verify(not md5 size mode mtime) %attr(400,%{srcname},%{srcname}) %{_sysconfdir}/%{srcname}/verifier.conf +%{_bindir}/%{srcname}_verifier +%{_bindir}/%{srcname}_ca +%{_unitdir}/keylime_verifier.service + +%files registrar +%license LICENSE +%attr(500,%{srcname},%{srcname}) %dir %{_sysconfdir}/%{srcname}/registrar.conf.d +%config(noreplace) %verify(not md5 size mode mtime) %attr(400,%{srcname},%{srcname}) %{_sysconfdir}/%{srcname}/registrar.conf +%{_bindir}/%{srcname}_registrar +%{_unitdir}/keylime_registrar.service + +%if 0%{?with_selinux} +%files selinux +%{_datadir}/selinux/packages/%{selinuxtype}/%{srcname}.pp.* +%{_datadir}/selinux/devel/include/distributed/%{srcname}.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{srcname} +%endif + +%files tenant +%license LICENSE +%attr(500,%{srcname},%{srcname}) %dir %{_sysconfdir}/%{srcname}/tenant.conf.d +%config(noreplace) %verify(not md5 size mode mtime) %attr(400,%{srcname},%{srcname}) %{_sysconfdir}/%{srcname}/tenant.conf +%{_bindir}/%{srcname}_tenant + +%files -n python3-%{srcname} +%license LICENSE +%{python3_sitelib}/%{srcname}-*.egg-info/ +%{python3_sitelib}/%{srcname} +%{_datadir}/%{srcname}/scripts/create_mb_refstate +%{_bindir}/keylime_attest +%{_bindir}/keylime_convert_runtime_policy +%{_bindir}/keylime_create_policy +%{_bindir}/keylime_sign_runtime_policy + + +%files tools +%license LICENSE +%{_bindir}/%{srcname}_userdata_encrypt + +%files base +%license LICENSE +%doc README.md +%attr(500,%{srcname},%{srcname}) %dir %{_sysconfdir}/%{srcname}/{ca,logging}.conf.d +%config(noreplace) %verify(not md5 size mode mtime) %attr(400,%{srcname},%{srcname}) %{_sysconfdir}/%{srcname}/ca.conf +%config(noreplace) %verify(not md5 size mode mtime) %attr(400,%{srcname},%{srcname}) %{_sysconfdir}/%{srcname}/logging.conf +%attr(700,%{srcname},%{srcname}) %dir %{_rundir}/%{srcname} +%attr(700,%{srcname},%{srcname}) %dir %{_sharedstatedir}/%{srcname} +%attr(500,%{srcname},%{srcname}) %dir %{_sharedstatedir}/%{srcname}/tpm_cert_store +%attr(400,%{srcname},%{srcname}) %{_sharedstatedir}/%{srcname}/tpm_cert_store/*.pem +%{_tmpfilesdir}/%{srcname}.conf +%{_sysusersdir}/%{srcname}.conf +%{_datadir}/%{srcname}/scripts/create_allowlist.sh +%{_datadir}/%{srcname}/scripts/ek-openssl-verify +%{_datadir}/%{srcname}/templates +%{_bindir}/keylime_upgrade_config + +%files +%license LICENSE + +%changelog +## START: Generated by rpmautospec +* Mon Aug 19 2024 Anderson Toshiyuki Sasaki - 7.9.0-7 +- Use TLS on revocation notification webhook +- Include system installed CA certificates when verifying webhook server + certificate +- Include the CA certificates added via configuration file option + 'trusted_server_ca' + +* Fri Aug 16 2024 Anderson Toshiyuki Sasaki - 7.9.0-6 +- Restore create_allowlist.sh to be the same as in RHEL-9 + +* Mon Jun 24 2024 Karel Srot - 7.9.0-5 +- Add rhel-10 gating.yaml + +* Mon Jun 24 2024 Troy Dawson - 7.9.0-4 +- Bump release for June 2024 mass rebuild + +* Thu May 09 2024 Karel Srot - 7.9.0-3 +- tests: Update CI test plan for C10S + +* Mon Feb 12 2024 Sergio Correia - 7.9.0-2 +- Fixes for rawhide + +* Tue Jan 30 2024 Sergio Correia - 7.9.0-1 +- Updating for Keylime release v7.9.0 +- Migrated license to SPDX + +* Wed Jan 24 2024 Fedora Release Engineering - 7.8.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sun Jan 21 2024 Fedora Release Engineering - 7.8.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Tue Dec 05 2023 Sergio Correia - 7.8.0-1 +- Updating for Keylime release v7.8.0 + +* Thu Nov 02 2023 Sergio Correia - 7.7.0-1 +- Updating for Keylime release v7.7.0 + +* Thu Aug 24 2023 Sergio Correia - 7.5.0-1 +- Updating for Keylime release v7.5.0 + +* Mon Jul 31 2023 Sergio Correia - 7.3.0-1 +- Updating for Keylime release v7.3.0 + +* Thu Jul 20 2023 Fedora Release Engineering - 7.2.5-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Thu Jun 15 2023 Python Maint - 7.2.5-3 +- Rebuilt for Python 3.12 + +* Tue Jun 06 2023 Sergio Correia - 7.2.5-2 +- Update test plan + +* Mon Jun 05 2023 Sergio Correia - 7.2.5-1 +- Updating for Keylime release v7.2.5 + +* Fri Feb 03 2023 Sergio Correia - 6.6.0-1 +- Updating for Keylime release v6.6.0 + +* Wed Jan 25 2023 Sergio Correia - 6.5.3-2 +- e2e tests: do not change the tpm hash alg to sha256 + +* Wed Jan 25 2023 Sergio Correia - 6.5.3-1 +- Updating for Keylime release v6.5.3 + +* Thu Jan 19 2023 Fedora Release Engineering - 6.4.3-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Mon Dec 12 2022 Karel Srot - 6.4.3-7 +- Ignore non-keylime AVCs on Fedora Rawhide + +* Fri Dec 09 2022 Sergio Correia - 6.4.3-6 +- Proper exception handling in tornado_requests + +* Fri Dec 09 2022 Sergio Correia - 6.4.3-5 +- Do not remove tag-repository.repo + +* Thu Dec 01 2022 Karel Srot - 6.4.3-4 +- Add dynamic_ref reference to e2e_tests.fmf + +* Tue Oct 25 2022 Patrik Koncity - 6.4.3-3 +- Add keylime selinux policy as subpackage and update CI + +* Wed Sep 14 2022 Sergio Correia - 6.4.3-2 +- Update tests branch to fedora-main + +* Thu Aug 25 2022 Sergio Correia - 6.4.3-1 +- Updating for Keylime release v6.4.3 + +* Thu Jul 21 2022 Fedora Release Engineering - 6.4.2-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + +* Mon Jul 11 2022 Sergio Correia - 6.4.2-3 +- Wrap efivar-libs dependency in a "ifarch %%efi" + +* Fri Jul 08 2022 Sergio Correia - 6.4.2-2 +- Fix efivar-libs dependency +- Some arches do not have efivar-libs, so let's require it conditionally. + +* Fri Jul 08 2022 Sergio Correia - 6.4.2-1 +- Updating for Keylime release v6.4.2 +- Remove keylime-webapp and mark package as obsolete +- Configure tmpfiles.d +- Move common python dependencies to python3-keylime +- Change dependency from python3-gnupg to python3-gpg +- Use sysusers.d for handling user creation + +* Fri Jul 08 2022 Sergio Correia - 6.4.1-4 +- Adjust Fedora CI test plan as per upstream + +* Thu Jul 07 2022 Sergio Correia - 6.4.1-3 +- Opt in to rpmautospec + +* Mon Jun 13 2022 Python Maint - 6.4.1-2 +- Rebuilt for Python 3.11 + +* Mon Jun 06 2022 Sergio Correia - 6.4.1-1 +- Updating for Keylime release v6.4.1 + +* Wed May 04 2022 Sergio Correia - 6.4.0-1 +- Updating for Keylime release v6.4.0 + +* Wed Apr 06 2022 Sergio Correia - 6.3.2-1 +- Updating for Keylime release v6.3.2 + +* Mon Feb 14 2022 Sergio Correia - 6.3.1-1 +- Updating for Keylime release v6.3.1 + +* Tue Feb 08 2022 Sergio Correia - 6.0.3-4 +- Add Conflicts clauses for the subpackages + +* Mon Feb 07 2022 Sergio Correia - 6.3.0-3 +- Split keylime into subpackages + Related: rhbz#2045874 - Keylime subpackaging and agent alternatives + +* Thu Jan 27 2022 Sergio Correia - 6.3.0-2 +- Fix permissions of config file + +* Thu Jan 27 2022 Sergio Correia - 6.3.0-1 +- Updating for Keylime release v6.3.0 + +* Thu Jan 20 2022 Fedora Release Engineering - 6.1.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Thu Jul 22 2021 Fedora Release Engineering - 6.1.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Fri Jun 04 2021 Python Maint - 6.1.0-3 +- Rebuilt for Python 3.10 + +* Thu Mar 25 2021 Luke Hinds 6.0.1-1 +- Updating for Keylime release v6.1.0 + +* Wed Mar 03 2021 Luke Hinds 6.0.1-1 +- Updating for Keylime release v6.0.1 + +* Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek - 6.0.0-2 +- Rebuilt for updated systemd-rpm-macros + See https://pagure.io/fesco/issue/2583. + +* Wed Feb 24 2021 Luke Hinds 6.0.0-1 +- Updating for Keylime release v6.0.0 + +* Tue Feb 02 2021 Luke Hinds 5.8.1-1 +- Updating for Keylime release v5.8.1 + +* Tue Jan 26 2021 Fedora Release Engineering - 5.8.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Sat Jan 23 2021 Luke Hinds 5.8.0-1 +- Updating for Keylime release v5.8.0 + +* Fri Jul 17 2020 Luke Hinds 5.7.2-1 +- Updating for Keylime release v5.7.2 + +* Tue May 26 2020 Miro Hrončok - 5.6.2-2 +- Rebuilt for Python 3.9 + +* Fri May 01 2020 Luke Hinds 5.6.2-1 +- Updating for Keylime release v5.6.2 + +* Thu Feb 06 2020 Luke Hinds 5.5.0-1 +- Updating for Keylime release v5.5.0 + +* Wed Jan 29 2020 Fedora Release Engineering - 5.4.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Thu Dec 12 2019 Luke Hinds 5.4.1-1 +– Initial Packaging + +## END: Generated by rpmautospec