Update to upstream commit 0186093
Related: rhbz#2084552 Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
This commit is contained in:
parent
e8f918028a
commit
02a44a5bc5
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
/rust-keylime-0.1.0~20220603gitaed51c7-vendor.tar.xz
|
||||
/rust-keylime-0.1.0~20220603gitaed51c7.tar.gz
|
||||
/rust-keylime-0.1.0~20220805git0186093.tar.gz
|
||||
/rust-keylime-0.1.0~20220805git0186093-vendor.tar.xz
|
||||
|
||||
@ -6,16 +6,16 @@
|
||||
%global crate keylime_agent
|
||||
%global crate_version 0.1.0
|
||||
|
||||
%global commit aed51c7c8c526953e945357594352c3df2ca4ace
|
||||
%global commit 01860934f7308bc5ea1e68c8d858aea056620ce8
|
||||
%global shortcommit %(c=%{commit}; echo ${c:0:7})
|
||||
%global commitdate 20220603
|
||||
%global commitdate 20220805
|
||||
|
||||
# RHEL: Use bundled deps as it doesn't ship Rust libraries
|
||||
%global bundled_rust_deps 1
|
||||
|
||||
Name: keylime-agent-rust
|
||||
Version: %{crate_version}~%{commitdate}git%{shortcommit}
|
||||
Release: 4%{?dist}
|
||||
Release: 1%{?dist}
|
||||
Summary: Rust agent for Keylime
|
||||
|
||||
# Upstream license specification: Apache-2.0
|
||||
@ -40,28 +40,20 @@ URL: https://github.com/keylime/rust-keylime/
|
||||
# The source tarball is downloaded using the following commands:
|
||||
# spectool -g keylime-agent-rust.spec
|
||||
Source0: %{url}/archive/%{commit}/rust-keylime-%{version}.tar.gz
|
||||
# The vendor tarball is created using cargo vendor:
|
||||
# The vendor tarball is created using cargo-vendor-filterer to remove Windows
|
||||
# related files (https://github.com/cgwalters/cargo-vendor-filterer)
|
||||
# tar xf rust-keylime-%%{version}.tar.gz
|
||||
# cd rust-keylime-%%{version}
|
||||
# cargo vendor
|
||||
# cargo vendor-filterer --platform x86_64-unknown-linux-gnu \
|
||||
# --platform powerpc64le-unknown-linux-gnu \
|
||||
# --platform aarch64-unknown-linux-gnu \
|
||||
# --platform i686-unknown-linux-gnu \
|
||||
# --platform s390x-unknown-linux-gnu \
|
||||
# --exclude-crate-path "libloading#tests"
|
||||
# tar jcf rust-keylime-%%{version}-vendor.tar.xz vendor
|
||||
Source1: rust-keylime-%{version}-vendor.tar.xz
|
||||
# Drop dependencies and adjust the features
|
||||
Patch0: rust-keylime-drop-dependencies.patch
|
||||
# Add serialization functions to fix issue on big-endian arches
|
||||
Patch1: rust-keylime-add-quote-serialization.patch
|
||||
# Show path on missing mTLS certificate
|
||||
Patch2: rust-keylime-show-path-missing-cert.patch
|
||||
# Use more descriptive error messages for missing files errors
|
||||
Patch3: rust-keylime-descriptive-error-messages.patch
|
||||
# Set supplementary groups when dropping privileges
|
||||
Patch4: rust-keylime-set-supplementary-groups.patch
|
||||
# Adjust the supported and required features
|
||||
Patch5: rust-keylime-adjust-features.patch
|
||||
# Load configuration file only once during startup
|
||||
Patch6: rust-keylime-load-config-once.patch
|
||||
# Add support for PCR hash algorithms other than SHA-1 to the IMA emulator
|
||||
Patch7: rust-keylime-ima-emulator-hash-algorithms.patch
|
||||
Patch0: rust-keylime-adjust-features.patch
|
||||
|
||||
ExclusiveArch: %{rust_arches}
|
||||
|
||||
@ -87,8 +79,8 @@ Provides: bundled(crate(actix-codec)) = 0.5.0
|
||||
Provides: bundled(crate(actix-http)) = 3.0.4
|
||||
Provides: bundled(crate(actix-macros)) = 0.2.3
|
||||
Provides: bundled(crate(actix-router)) = 0.5.0
|
||||
Provides: bundled(crate(actix-rt)) = 2.6.0
|
||||
Provides: bundled(crate(actix-server)) = 2.0.0
|
||||
Provides: bundled(crate(actix-rt)) = 2.7.0
|
||||
Provides: bundled(crate(actix-server)) = 2.1.1
|
||||
Provides: bundled(crate(actix-service)) = 2.0.2
|
||||
Provides: bundled(crate(actix-tls)) = 3.0.3
|
||||
Provides: bundled(crate(actix-utils)) = 3.0.0
|
||||
@ -108,36 +100,36 @@ Provides: bundled(crate(bindgen)) = 0.59.2
|
||||
Provides: bundled(crate(bitfield)) = 0.13.2
|
||||
Provides: bundled(crate(bitflags)) = 1.3.2
|
||||
Provides: bundled(crate(block-buffer)) = 0.10.2
|
||||
Provides: bundled(crate(brotli)) = 3.3.3
|
||||
Provides: bundled(crate(brotli)) = 3.3.4
|
||||
Provides: bundled(crate(brotli-decompressor)) = 2.3.2
|
||||
Provides: bundled(crate(bytes)) = 1.1.0
|
||||
Provides: bundled(crate(bytestring)) = 1.0.0
|
||||
Provides: bundled(crate(cc)) = 1.0.72
|
||||
Provides: bundled(crate(cc)) = 1.0.73
|
||||
Provides: bundled(crate(cexpr)) = 0.6.0
|
||||
Provides: bundled(crate(cfg-if)) = 1.0.0
|
||||
Provides: bundled(crate(clang-sys)) = 1.3.3
|
||||
Provides: bundled(crate(clap)) = 2.34.0
|
||||
Provides: bundled(crate(clap)) = 3.1.18
|
||||
Provides: bundled(crate(clap_derive)) = 3.1.18
|
||||
Provides: bundled(crate(clap_lex)) = 0.2.4
|
||||
Provides: bundled(crate(clap_lex)) = 0.2.0
|
||||
Provides: bundled(crate(compress-tools)) = 0.12.2
|
||||
Provides: bundled(crate(convert_case)) = 0.4.0
|
||||
Provides: bundled(crate(cookie)) = 0.16.0
|
||||
Provides: bundled(crate(cpufeatures)) = 0.2.1
|
||||
Provides: bundled(crate(cpufeatures)) = 0.2.2
|
||||
Provides: bundled(crate(crc32fast)) = 1.3.2
|
||||
Provides: bundled(crate(crypto-common)) = 0.1.3
|
||||
Provides: bundled(crate(derive_more)) = 0.99.17
|
||||
Provides: bundled(crate(digest)) = 0.10.3
|
||||
Provides: bundled(crate(dlv-list)) = 0.2.3
|
||||
Provides: bundled(crate(either)) = 1.7.0
|
||||
Provides: bundled(crate(encoding_rs)) = 0.8.30
|
||||
Provides: bundled(crate(enumflags2)) = 0.7.3
|
||||
Provides: bundled(crate(enumflags2_derive)) = 0.7.3
|
||||
Provides: bundled(crate(encoding_rs)) = 0.8.31
|
||||
Provides: bundled(crate(enumflags2)) = 0.7.5
|
||||
Provides: bundled(crate(enumflags2_derive)) = 0.7.4
|
||||
Provides: bundled(crate(env_logger)) = 0.7.1
|
||||
Provides: bundled(crate(env_logger)) = 0.9.0
|
||||
Provides: bundled(crate(fastrand)) = 1.7.0
|
||||
Provides: bundled(crate(firestorm)) = 0.5.0
|
||||
Provides: bundled(crate(flate2)) = 1.0.22
|
||||
Provides: bundled(crate(firestorm)) = 0.5.1
|
||||
Provides: bundled(crate(flate2)) = 1.0.24
|
||||
Provides: bundled(crate(fnv)) = 1.0.7
|
||||
Provides: bundled(crate(foreign-types)) = 0.3.2
|
||||
Provides: bundled(crate(foreign-types-shared)) = 0.1.1
|
||||
@ -152,28 +144,26 @@ Provides: bundled(crate(futures-sink)) = 0.3.21
|
||||
Provides: bundled(crate(futures-task)) = 0.3.21
|
||||
Provides: bundled(crate(futures-util)) = 0.3.21
|
||||
Provides: bundled(crate(generic-array)) = 0.14.5
|
||||
Provides: bundled(crate(getrandom)) = 0.2.4
|
||||
Provides: bundled(crate(getrandom)) = 0.2.6
|
||||
Provides: bundled(crate(glob)) = 0.3.0
|
||||
Provides: bundled(crate(h2)) = 0.3.11
|
||||
Provides: bundled(crate(hamming)) = 0.1.3
|
||||
Provides: bundled(crate(h2)) = 0.3.13
|
||||
Provides: bundled(crate(hashbrown)) = 0.9.1
|
||||
Provides: bundled(crate(hashbrown)) = 0.11.2
|
||||
Provides: bundled(crate(heck)) = 0.4.0
|
||||
Provides: bundled(crate(hex)) = 0.4.3
|
||||
Provides: bundled(crate(hostname-validator)) = 1.1.0
|
||||
Provides: bundled(crate(http)) = 0.2.6
|
||||
Provides: bundled(crate(http-body)) = 0.4.4
|
||||
Provides: bundled(crate(httparse)) = 1.6.0
|
||||
Provides: bundled(crate(hostname-validator)) = 1.1.1
|
||||
Provides: bundled(crate(http)) = 0.2.8
|
||||
Provides: bundled(crate(http-body)) = 0.4.5
|
||||
Provides: bundled(crate(httparse)) = 1.7.1
|
||||
Provides: bundled(crate(httpdate)) = 1.0.2
|
||||
Provides: bundled(crate(humantime)) = 1.3.0
|
||||
Provides: bundled(crate(humantime)) = 2.1.0
|
||||
Provides: bundled(crate(hyper)) = 0.14.17
|
||||
Provides: bundled(crate(hyper)) = 0.14.19
|
||||
Provides: bundled(crate(hyper-tls)) = 0.5.0
|
||||
Provides: bundled(crate(idna)) = 0.2.3
|
||||
Provides: bundled(crate(indexmap)) = 1.8.0
|
||||
Provides: bundled(crate(instant)) = 0.1.12
|
||||
Provides: bundled(crate(ipnet)) = 2.3.1
|
||||
Provides: bundled(crate(itoa)) = 1.0.1
|
||||
Provides: bundled(crate(indexmap)) = 1.8.2
|
||||
Provides: bundled(crate(ipnet)) = 2.5.0
|
||||
Provides: bundled(crate(itoa)) = 1.0.2
|
||||
Provides: bundled(crate(jobserver)) = 0.1.24
|
||||
Provides: bundled(crate(keylime_agent)) = 0.1.0
|
||||
Provides: bundled(crate(language-tags)) = 0.3.2
|
||||
@ -181,124 +171,124 @@ Provides: bundled(crate(lazy_static)) = 1.4.0
|
||||
Provides: bundled(crate(lazycell)) = 1.3.0
|
||||
Provides: bundled(crate(libc)) = 0.2.126
|
||||
Provides: bundled(crate(libloading)) = 0.7.3
|
||||
Provides: bundled(crate(local-channel)) = 0.1.2
|
||||
Provides: bundled(crate(local-waker)) = 0.1.2
|
||||
Provides: bundled(crate(lock_api)) = 0.4.6
|
||||
Provides: bundled(crate(log)) = 0.4.14
|
||||
Provides: bundled(crate(local-channel)) = 0.1.3
|
||||
Provides: bundled(crate(local-waker)) = 0.1.3
|
||||
Provides: bundled(crate(lock_api)) = 0.4.7
|
||||
Provides: bundled(crate(log)) = 0.4.17
|
||||
Provides: bundled(crate(matches)) = 0.1.9
|
||||
Provides: bundled(crate(mbox)) = 0.6.0
|
||||
Provides: bundled(crate(memchr)) = 2.4.1
|
||||
Provides: bundled(crate(memchr)) = 2.5.0
|
||||
Provides: bundled(crate(mime)) = 0.3.16
|
||||
Provides: bundled(crate(minimal-lexical)) = 0.2.1
|
||||
Provides: bundled(crate(miniz_oxide)) = 0.4.4
|
||||
Provides: bundled(crate(mio)) = 0.7.14
|
||||
Provides: bundled(crate(mio)) = 0.8.2
|
||||
Provides: bundled(crate(native-tls)) = 0.2.8
|
||||
Provides: bundled(crate(miniz_oxide)) = 0.5.3
|
||||
Provides: bundled(crate(mio)) = 0.8.3
|
||||
Provides: bundled(crate(native-tls)) = 0.2.10
|
||||
Provides: bundled(crate(nom)) = 7.1.1
|
||||
Provides: bundled(crate(num-derive)) = 0.3.3
|
||||
Provides: bundled(crate(num-integer)) = 0.1.44
|
||||
Provides: bundled(crate(num-traits)) = 0.2.14
|
||||
Provides: bundled(crate(num-traits)) = 0.2.15
|
||||
Provides: bundled(crate(num_cpus)) = 1.13.1
|
||||
Provides: bundled(crate(num_threads)) = 0.1.5
|
||||
Provides: bundled(crate(once_cell)) = 1.9.0
|
||||
Provides: bundled(crate(openssl)) = 0.10.38
|
||||
Provides: bundled(crate(num_threads)) = 0.1.6
|
||||
Provides: bundled(crate(oid)) = 0.2.1
|
||||
Provides: bundled(crate(once_cell)) = 1.12.0
|
||||
Provides: bundled(crate(openssl)) = 0.10.40
|
||||
Provides: bundled(crate(openssl-macros)) = 0.1.0
|
||||
Provides: bundled(crate(openssl-probe)) = 0.1.5
|
||||
Provides: bundled(crate(openssl-sys)) = 0.9.72
|
||||
Provides: bundled(crate(openssl-sys)) = 0.9.74
|
||||
Provides: bundled(crate(ordered-multimap)) = 0.3.1
|
||||
Provides: bundled(crate(os_str_bytes)) = 6.0.0
|
||||
Provides: bundled(crate(parking_lot)) = 0.11.2
|
||||
Provides: bundled(crate(parking_lot_core)) = 0.8.5
|
||||
Provides: bundled(crate(os_str_bytes)) = 6.1.0
|
||||
Provides: bundled(crate(parking_lot)) = 0.12.1
|
||||
Provides: bundled(crate(parking_lot_core)) = 0.9.3
|
||||
Provides: bundled(crate(paste)) = 1.0.7
|
||||
Provides: bundled(crate(peeking_take_while)) = 0.1.2
|
||||
Provides: bundled(crate(percent-encoding)) = 2.1.0
|
||||
Provides: bundled(crate(pest)) = 2.1.3
|
||||
Provides: bundled(crate(pin-project-lite)) = 0.2.8
|
||||
Provides: bundled(crate(picky-asn1)) = 0.3.3
|
||||
Provides: bundled(crate(picky-asn1)) = 0.5.0
|
||||
Provides: bundled(crate(picky-asn1-der)) = 0.2.5
|
||||
Provides: bundled(crate(picky-asn1-der)) = 0.3.1
|
||||
Provides: bundled(crate(picky-asn1-x509)) = 0.6.1
|
||||
Provides: bundled(crate(pin-project-lite)) = 0.2.9
|
||||
Provides: bundled(crate(pin-utils)) = 0.1.0
|
||||
Provides: bundled(crate(pkg-config)) = 0.3.24
|
||||
Provides: bundled(crate(pkg-config)) = 0.3.25
|
||||
Provides: bundled(crate(ppv-lite86)) = 0.2.16
|
||||
Provides: bundled(crate(pretty_env_logger)) = 0.4.0
|
||||
Provides: bundled(crate(primal)) = 0.3.0
|
||||
Provides: bundled(crate(primal-bit)) = 0.3.0
|
||||
Provides: bundled(crate(primal-check)) = 0.3.1
|
||||
Provides: bundled(crate(primal-estimate)) = 0.3.1
|
||||
Provides: bundled(crate(primal-sieve)) = 0.3.1
|
||||
Provides: bundled(crate(proc-macro-error)) = 1.0.4
|
||||
Provides: bundled(crate(proc-macro-error-attr)) = 1.0.4
|
||||
Provides: bundled(crate(proc-macro2)) = 1.0.36
|
||||
Provides: bundled(crate(proc-macro2)) = 1.0.39
|
||||
Provides: bundled(crate(quick-error)) = 1.2.3
|
||||
Provides: bundled(crate(quote)) = 1.0.15
|
||||
Provides: bundled(crate(quote)) = 1.0.18
|
||||
Provides: bundled(crate(rand)) = 0.8.5
|
||||
Provides: bundled(crate(rand_chacha)) = 0.3.1
|
||||
Provides: bundled(crate(rand_core)) = 0.6.3
|
||||
Provides: bundled(crate(regex)) = 1.5.4
|
||||
Provides: bundled(crate(regex-syntax)) = 0.6.25
|
||||
Provides: bundled(crate(regex)) = 1.5.6
|
||||
Provides: bundled(crate(regex-syntax)) = 0.6.26
|
||||
Provides: bundled(crate(remove_dir_all)) = 0.5.3
|
||||
Provides: bundled(crate(reqwest)) = 0.11.10
|
||||
Provides: bundled(crate(rust-ini)) = 0.17.0
|
||||
Provides: bundled(crate(rustc-hash)) = 1.1.0
|
||||
Provides: bundled(crate(rustc_version)) = 0.3.3
|
||||
Provides: bundled(crate(rustc_version)) = 0.4.0
|
||||
Provides: bundled(crate(ryu)) = 1.0.9
|
||||
Provides: bundled(crate(ryu)) = 1.0.10
|
||||
Provides: bundled(crate(scopeguard)) = 1.1.0
|
||||
Provides: bundled(crate(semver)) = 0.11.0
|
||||
Provides: bundled(crate(semver)) = 1.0.5
|
||||
Provides: bundled(crate(semver)) = 1.0.9
|
||||
Provides: bundled(crate(semver-parser)) = 0.10.2
|
||||
Provides: bundled(crate(serde)) = 1.0.136
|
||||
Provides: bundled(crate(serde_derive)) = 1.0.136
|
||||
Provides: bundled(crate(serde_json)) = 1.0.79
|
||||
Provides: bundled(crate(serde)) = 1.0.137
|
||||
Provides: bundled(crate(serde_bytes)) = 0.11.6
|
||||
Provides: bundled(crate(serde_derive)) = 1.0.137
|
||||
Provides: bundled(crate(serde_json)) = 1.0.81
|
||||
Provides: bundled(crate(serde_urlencoded)) = 0.7.1
|
||||
Provides: bundled(crate(sha-1)) = 0.10.0
|
||||
Provides: bundled(crate(shlex)) = 1.1.0
|
||||
Provides: bundled(crate(signal-hook-registry)) = 1.4.0
|
||||
Provides: bundled(crate(slab)) = 0.4.5
|
||||
Provides: bundled(crate(slab)) = 0.4.6
|
||||
Provides: bundled(crate(smallvec)) = 1.8.0
|
||||
Provides: bundled(crate(socket2)) = 0.4.4
|
||||
Provides: bundled(crate(stable_deref_trait)) = 1.2.0
|
||||
Provides: bundled(crate(static_assertions)) = 1.1.0
|
||||
Provides: bundled(crate(strsim)) = 0.8.0
|
||||
Provides: bundled(crate(strsim)) = 0.10.0
|
||||
Provides: bundled(crate(syn)) = 1.0.86
|
||||
Provides: bundled(crate(syn)) = 1.0.96
|
||||
Provides: bundled(crate(synstructure)) = 0.12.6
|
||||
Provides: bundled(crate(target-lexicon)) = 0.12.3
|
||||
Provides: bundled(crate(target-lexicon)) = 0.12.4
|
||||
Provides: bundled(crate(tempfile)) = 3.3.0
|
||||
Provides: bundled(crate(termcolor)) = 1.1.2
|
||||
Provides: bundled(crate(termcolor)) = 1.1.3
|
||||
Provides: bundled(crate(textwrap)) = 0.11.0
|
||||
Provides: bundled(crate(textwrap)) = 0.15.0
|
||||
Provides: bundled(crate(thiserror)) = 1.0.30
|
||||
Provides: bundled(crate(thiserror-impl)) = 1.0.30
|
||||
Provides: bundled(crate(thiserror)) = 1.0.31
|
||||
Provides: bundled(crate(thiserror-impl)) = 1.0.31
|
||||
Provides: bundled(crate(time)) = 0.3.9
|
||||
Provides: bundled(crate(time-macros)) = 0.2.4
|
||||
Provides: bundled(crate(tinyvec)) = 1.5.1
|
||||
Provides: bundled(crate(tinyvec)) = 1.6.0
|
||||
Provides: bundled(crate(tinyvec_macros)) = 0.1.0
|
||||
Provides: bundled(crate(tokio)) = 1.16.1
|
||||
Provides: bundled(crate(tokio-macros)) = 1.7.0
|
||||
Provides: bundled(crate(tokio)) = 1.19.2
|
||||
Provides: bundled(crate(tokio-macros)) = 1.8.0
|
||||
Provides: bundled(crate(tokio-native-tls)) = 0.3.0
|
||||
Provides: bundled(crate(tokio-openssl)) = 0.6.3
|
||||
Provides: bundled(crate(tokio-util)) = 0.6.9
|
||||
Provides: bundled(crate(tokio-util)) = 0.7.1
|
||||
Provides: bundled(crate(tokio-util)) = 0.7.3
|
||||
Provides: bundled(crate(tower-service)) = 0.3.1
|
||||
Provides: bundled(crate(tracing)) = 0.1.30
|
||||
Provides: bundled(crate(tracing-attributes)) = 0.1.20
|
||||
Provides: bundled(crate(tracing-core)) = 0.1.22
|
||||
Provides: bundled(crate(tracing)) = 0.1.35
|
||||
Provides: bundled(crate(tracing-core)) = 0.1.27
|
||||
Provides: bundled(crate(try-lock)) = 0.2.3
|
||||
Provides: bundled(crate(tss-esapi)) = 7.0.0
|
||||
Provides: bundled(crate(tss-esapi)) = 7.1.0
|
||||
Provides: bundled(crate(tss-esapi-sys)) = 0.3.0
|
||||
Provides: bundled(crate(typenum)) = 1.15.0
|
||||
Provides: bundled(crate(ucd-trie)) = 0.1.3
|
||||
Provides: bundled(crate(unicode-bidi)) = 0.3.7
|
||||
Provides: bundled(crate(unicode-bidi)) = 0.3.8
|
||||
Provides: bundled(crate(unicode-ident)) = 1.0.0
|
||||
Provides: bundled(crate(unicode-normalization)) = 0.1.19
|
||||
Provides: bundled(crate(unicode-width)) = 0.1.9
|
||||
Provides: bundled(crate(unicode-xid)) = 0.2.2
|
||||
Provides: bundled(crate(unicode-xid)) = 0.2.3
|
||||
Provides: bundled(crate(url)) = 2.2.2
|
||||
Provides: bundled(crate(uuid)) = 0.8.2
|
||||
Provides: bundled(crate(vec_map)) = 0.8.2
|
||||
Provides: bundled(crate(version_check)) = 0.9.4
|
||||
Provides: bundled(crate(want)) = 0.3.0
|
||||
Provides: bundled(crate(which)) = 4.2.5
|
||||
Provides: bundled(crate(zeroize)) = 1.5.2
|
||||
Provides: bundled(crate(zeroize_derive)) = 1.3.1
|
||||
Provides: bundled(crate(zstd)) = 0.10.0
|
||||
Provides: bundled(crate(zstd-safe)) = 4.1.4
|
||||
Provides: bundled(crate(zeroize)) = 1.5.5
|
||||
Provides: bundled(crate(zeroize_derive)) = 1.3.2
|
||||
Provides: bundled(crate(zstd)) = 0.10.2
|
||||
Provides: bundled(crate(zstd-safe)) = 4.1.6
|
||||
Provides: bundled(crate(zstd-sys)) = 1.6.3
|
||||
|
||||
%description
|
||||
@ -329,6 +319,15 @@ install -Dpm 644 ./dist/systemd/system/keylime_agent.service \
|
||||
install -Dpm 644 ./dist/systemd/system/var-lib-keylime-secure.mount \
|
||||
%{buildroot}%{_unitdir}/var-lib-keylime-secure.mount
|
||||
|
||||
# Setting up the agent to use keylime:keylime user/group after dropping privileges.
|
||||
sed -e 's/^run_as[[:space:]]*=.*/run_as = keylime:keylime/g' -i keylime-agent.conf
|
||||
|
||||
# Using sha256 for tpm_hash_alg.
|
||||
sed -e 's/^tpm_hash_alg[[:space:]]*=.*/tpm_hash_alg = sha256/g' -i keylime-agent.conf
|
||||
|
||||
install -Dpm 600 keylime-agent.conf \
|
||||
%{buildroot}%{_sysconfdir}/keylime-agent.conf
|
||||
|
||||
%preun
|
||||
%systemd_preun keylime_agent.service
|
||||
%systemd_preun var-lib-keylime-secure.mount
|
||||
@ -340,6 +339,7 @@ install -Dpm 644 ./dist/systemd/system/var-lib-keylime-secure.mount \
|
||||
%files
|
||||
%license LICENSE
|
||||
%doc README.md
|
||||
%config(noreplace) %attr(600,keylime,keylime) %{_sysconfdir}/keylime-agent.conf
|
||||
%{_unitdir}/keylime_agent.service
|
||||
%{_unitdir}/var-lib-keylime-secure.mount
|
||||
%attr(700,keylime,keylime) %dir %{_rundir}/keylime
|
||||
@ -355,6 +355,9 @@ install -Dpm 644 ./dist/systemd/system/var-lib-keylime-secure.mount \
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Thu Aug 25 2022 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 0.1.0~20220805git0185093-1
|
||||
- Update to upstream commit 0186093
|
||||
|
||||
* Mon Jul 18 2022 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 0.1.0~20220603gitaed51c7-4
|
||||
- Remove vendored source files for non-Linux or unsupported platforms
|
||||
|
||||
|
||||
@ -1,217 +0,0 @@
|
||||
From 423f7337d991ec5085914a361e68260bdd513ac6 Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Mon, 20 Jun 2022 11:51:46 +0200
|
||||
Subject: [PATCH] tpm: Add serialization functions for structures in quotes
|
||||
|
||||
Add serialization and deserialization functions for the data in quotes
|
||||
to avoid endianness issues when the arch is big-endian.
|
||||
|
||||
The added serialization and deserialization functions will convert the
|
||||
data endianness as necessary.
|
||||
|
||||
Note: the official marshalling and unmarshalling functions cannot be
|
||||
used directly because the tpm2-tools uses a custom format.
|
||||
|
||||
Fixes: #407
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
src/tpm.rs | 139 +++++++++++++++++++++++++++++++++++++++++------------
|
||||
1 file changed, 107 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/src/tpm.rs b/src/tpm.rs
|
||||
index 9002c29..5521892 100644
|
||||
--- a/src/tpm.rs
|
||||
+++ b/src/tpm.rs
|
||||
@@ -52,15 +52,20 @@ use tss_esapi::{
|
||||
tss2_esys::{
|
||||
Tss2_MU_TPM2B_PUBLIC_Marshal, Tss2_MU_TPMS_ATTEST_Marshal,
|
||||
Tss2_MU_TPMS_ATTEST_Unmarshal, Tss2_MU_TPMT_SIGNATURE_Marshal,
|
||||
- TPM2B_ATTEST, TPM2B_PUBLIC, TPML_DIGEST, TPML_PCR_SELECTION,
|
||||
- TPMS_ATTEST, TPMS_SCHEME_HASH, TPMT_SIGNATURE, TPMT_SIG_SCHEME,
|
||||
- TPMU_SIG_SCHEME,
|
||||
+ TPM2B_ATTEST, TPM2B_DIGEST, TPM2B_PUBLIC, TPML_DIGEST,
|
||||
+ TPML_PCR_SELECTION, TPMS_ATTEST, TPMS_PCR_SELECTION,
|
||||
+ TPMS_SCHEME_HASH, TPMT_SIGNATURE, TPMT_SIG_SCHEME, TPMU_SIG_SCHEME,
|
||||
},
|
||||
utils::TpmsContext,
|
||||
Context,
|
||||
};
|
||||
|
||||
pub const MAX_NONCE_SIZE: usize = 64;
|
||||
+pub const TPML_DIGEST_SIZE: usize = std::mem::size_of::<TPML_DIGEST>();
|
||||
+pub const TPML_PCR_SELECTION_SIZE: usize =
|
||||
+ std::mem::size_of::<TPML_PCR_SELECTION>();
|
||||
+pub const TPMS_PCR_SELECTION_SIZE: usize =
|
||||
+ std::mem::size_of::<TPMS_PCR_SELECTION>();
|
||||
|
||||
/*
|
||||
* Input: None
|
||||
@@ -123,6 +128,95 @@ pub(crate) fn create_ek(
|
||||
assert_eq_size!(TPML_PCR_SELECTION, [u8; 132]);
|
||||
assert_eq_size!(TPML_DIGEST, [u8; 532]);
|
||||
|
||||
+// Serialize a TPML_PCR_SELECTION into a Vec<u8>
|
||||
+// The serialization will adjust the data endianness as necessary and add paddings to keep the
|
||||
+// memory aligment.
|
||||
+pub(crate) fn serialize_pcrsel(
|
||||
+ pcr_selection: &TPML_PCR_SELECTION,
|
||||
+) -> Vec<u8> {
|
||||
+ let mut output = Vec::with_capacity(TPML_PCR_SELECTION_SIZE);
|
||||
+ output.extend(u32::to_le_bytes(pcr_selection.count));
|
||||
+ for selection in pcr_selection.pcrSelections.iter() {
|
||||
+ output.extend(selection.hash.to_le_bytes());
|
||||
+ output.extend(selection.sizeofSelect.to_le_bytes());
|
||||
+ output.extend(selection.pcrSelect);
|
||||
+ output.extend([0u8; 1]); // padding to keep the memory alignment
|
||||
+ }
|
||||
+ output
|
||||
+}
|
||||
+
|
||||
+// Deserialize a TPML_PCR_SELECTION from a &[u8] slice.
|
||||
+// The deserialization will adjust the data endianness as necessary.
|
||||
+pub(crate) fn deserialize_pcrsel(
|
||||
+ pcrsel_vec: &[u8],
|
||||
+) -> Result<TPML_PCR_SELECTION> {
|
||||
+ if pcrsel_vec.len() != TPML_PCR_SELECTION_SIZE {
|
||||
+ return Err(KeylimeError::InvalidRequest);
|
||||
+ }
|
||||
+
|
||||
+ let mut reader = std::io::Cursor::new(pcrsel_vec);
|
||||
+ let mut count_vec = [0u8; 4];
|
||||
+ reader.read_exact(&mut count_vec)?;
|
||||
+ let count = u32::from_le_bytes(count_vec);
|
||||
+
|
||||
+ let mut pcr_selections: [TPMS_PCR_SELECTION; 16] =
|
||||
+ [TPMS_PCR_SELECTION::default(); 16];
|
||||
+
|
||||
+ for selection in &mut pcr_selections {
|
||||
+ let mut hash_vec = [0u8; 2];
|
||||
+ reader.read_exact(&mut hash_vec)?;
|
||||
+ selection.hash = u16::from_le_bytes(hash_vec);
|
||||
+
|
||||
+ let mut size_vec = [0u8; 1];
|
||||
+ reader.read_exact(&mut size_vec)?;
|
||||
+ selection.sizeofSelect = u8::from_le_bytes(size_vec);
|
||||
+
|
||||
+ reader.read_exact(&mut selection.pcrSelect)?;
|
||||
+ }
|
||||
+
|
||||
+ Ok(TPML_PCR_SELECTION {
|
||||
+ count,
|
||||
+ pcrSelections: pcr_selections,
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+// Serialize a TPML_DIGEST into a Vec<u8>
|
||||
+// The serialization will adjust the data endianness as necessary.
|
||||
+pub(crate) fn serialize_digest(digest_list: &TPML_DIGEST) -> Vec<u8> {
|
||||
+ let mut output = Vec::with_capacity(TPML_DIGEST_SIZE);
|
||||
+ output.extend(u32::to_le_bytes(digest_list.count));
|
||||
+ for digest in digest_list.digests.iter() {
|
||||
+ output.extend(digest.size.to_le_bytes());
|
||||
+ output.extend(digest.buffer);
|
||||
+ }
|
||||
+ output
|
||||
+}
|
||||
+
|
||||
+// Deserialize a TPML_DIGEST from a &[u8] slice.
|
||||
+// The deserialization will adjust the data endianness as necessary.
|
||||
+pub(crate) fn deserialize_digest(digest_vec: &[u8]) -> Result<TPML_DIGEST> {
|
||||
+ if digest_vec.len() != TPML_DIGEST_SIZE {
|
||||
+ return Err(KeylimeError::InvalidRequest);
|
||||
+ }
|
||||
+
|
||||
+ let mut reader = std::io::Cursor::new(digest_vec);
|
||||
+ let mut count_vec = [0u8; 4];
|
||||
+
|
||||
+ reader.read_exact(&mut count_vec)?;
|
||||
+ let count = u32::from_le_bytes(count_vec);
|
||||
+
|
||||
+ let mut digests: [TPM2B_DIGEST; 8] = [TPM2B_DIGEST::default(); 8];
|
||||
+
|
||||
+ for digest in &mut digests {
|
||||
+ let mut size_vec = [0u8; 2];
|
||||
+ reader.read_exact(&mut size_vec)?;
|
||||
+ digest.size = u16::from_le_bytes(size_vec);
|
||||
+ reader.read_exact(&mut digest.buffer)?;
|
||||
+ }
|
||||
+
|
||||
+ Ok(TPML_DIGEST { count, digests })
|
||||
+}
|
||||
+
|
||||
// Recreate how tpm2-tools creates the PCR out file. Roughly, this is a
|
||||
// TPML_PCR_SELECTION + number of TPML_DIGESTS + TPML_DIGESTs.
|
||||
// Reference:
|
||||
@@ -140,16 +234,14 @@ pub(crate) fn pcrdata_to_vec(
|
||||
const DIGEST_SIZE: usize = std::mem::size_of::<TPML_DIGEST>();
|
||||
|
||||
let mut pcrsel: TPML_PCR_SELECTION = selection_list.into();
|
||||
- pcrsel.count = pcrsel.count.to_le();
|
||||
- let pcrsel_vec: [u8; PCRSEL_SIZE] =
|
||||
- unsafe { std::mem::transmute(pcrsel) };
|
||||
+ let pcrsel_vec = serialize_pcrsel(&pcrsel);
|
||||
|
||||
let digest: Vec<TPML_DIGEST> = pcrdata.into();
|
||||
let num_tpml_digests = digest.len() as u32;
|
||||
let mut digest_vec = Vec::with_capacity(digest.len() * DIGEST_SIZE);
|
||||
|
||||
for d in digest {
|
||||
- let vec: [u8; DIGEST_SIZE] = unsafe { std::mem::transmute(d) };
|
||||
+ let vec = serialize_digest(&d);
|
||||
digest_vec.extend(vec);
|
||||
}
|
||||
|
||||
@@ -665,41 +757,24 @@ pub mod testing {
|
||||
);
|
||||
|
||||
fn vec_to_pcrdata(val: &[u8]) -> Result<(PcrSelectionList, PcrData)> {
|
||||
- const PCRSEL_SIZE: usize = std::mem::size_of::<TPML_PCR_SELECTION>();
|
||||
- const DIGEST_SIZE: usize = std::mem::size_of::<TPML_DIGEST>();
|
||||
-
|
||||
let mut reader = std::io::Cursor::new(val);
|
||||
- let mut pcrsel_vec = [0u8; PCRSEL_SIZE];
|
||||
- let len = reader.read(&mut pcrsel_vec)?;
|
||||
- if len != pcrsel_vec.len() {
|
||||
- return Err(KeylimeError::InvalidRequest);
|
||||
- }
|
||||
- let mut pcrsel = unsafe {
|
||||
- std::mem::transmute::<[u8; PCRSEL_SIZE], TPML_PCR_SELECTION>(
|
||||
- pcrsel_vec,
|
||||
- )
|
||||
- };
|
||||
+ let mut pcrsel_vec = [0u8; TPML_PCR_SELECTION_SIZE];
|
||||
+ reader.read_exact(&mut pcrsel_vec)?;
|
||||
+
|
||||
+ let pcrsel = deserialize_pcrsel(&pcrsel_vec)?;
|
||||
let pcrlist: PcrSelectionList = pcrsel.try_into()?;
|
||||
|
||||
let mut count_vec = [0u8; 4];
|
||||
- let len = reader.read(&mut count_vec)?;
|
||||
- if len < count_vec.len() {
|
||||
- return Err(KeylimeError::InvalidRequest);
|
||||
- }
|
||||
+ reader.read_exact(&mut count_vec)?;
|
||||
let count = u32::from_le_bytes(count_vec);
|
||||
// Always 1 PCR digest should follow
|
||||
if count != 1 {
|
||||
return Err(KeylimeError::InvalidRequest);
|
||||
}
|
||||
|
||||
- let mut digest_vec = [0u8; DIGEST_SIZE];
|
||||
- let len = reader.read(&mut digest_vec)?;
|
||||
- if len != digest_vec.len() {
|
||||
- return Err(KeylimeError::InvalidRequest);
|
||||
- }
|
||||
- let mut digest = unsafe {
|
||||
- std::mem::transmute::<[u8; DIGEST_SIZE], TPML_DIGEST>(digest_vec)
|
||||
- };
|
||||
+ let mut digest_vec = [0u8; TPML_DIGEST_SIZE];
|
||||
+ reader.read_exact(&mut digest_vec)?;
|
||||
+ let digest = deserialize_digest(&digest_vec)?;
|
||||
let mut digest_list = DigestList::new();
|
||||
for i in 0..digest.count {
|
||||
digest_list.add(digest.digests[i as usize].try_into()?);
|
||||
--
|
||||
2.35.3
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
--- a/Cargo.toml 2022-07-04 14:30:04.244003909 +0200
|
||||
+++ b/Cargo.toml 2022-07-04 14:31:46.421291210 +0200
|
||||
@@ -37,28 +37,14 @@
|
||||
--- a/Cargo.toml 2022-08-25 12:16:51.789234342 +0200
|
||||
+++ b/Cargo.toml 2022-08-25 12:21:45.451435220 +0200
|
||||
@@ -39,28 +39,13 @@
|
||||
static_assertions = "1"
|
||||
tempfile = "3.0.4"
|
||||
tokio = {version = "1", features = ["full"]}
|
||||
-tss-esapi = "7.0.0"
|
||||
+tss-esapi = {version = "7.0.0", features = ["generate-bindings"]}
|
||||
tokio = {version = "1.13.1", features = ["full"]}
|
||||
-tss-esapi = "7.1.0"
|
||||
+tss-esapi = {version="7.1.0", features = ["generate-bindings"]}
|
||||
thiserror = "1.0"
|
||||
uuid = {version = "0.8", features = ["v4"]}
|
||||
-zmq = {version = "0.9.2", optional = true}
|
||||
@ -18,7 +18,7 @@
|
||||
actix-rt = "2"
|
||||
|
||||
[features]
|
||||
# The features enabled by default
|
||||
-# The features enabled by default
|
||||
-default = ["with-zmq", "legacy-python-actions"]
|
||||
-# this should change to dev-dependencies when we have integration testing
|
||||
-testing = ["wiremock"]
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
From e20b936fc9d92ae05406cb86471d3e6fba823b7f Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Tue, 28 Jun 2022 13:47:38 +0200
|
||||
Subject: [PATCH] main: Use more descriptive message for missing files error
|
||||
|
||||
Use more descriptive message when required paths are missing instead of
|
||||
the generic message.
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
src/main.rs | 19 ++++++++++++++++---
|
||||
1 file changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/main.rs b/src/main.rs
|
||||
index 9404284..ef29eb2 100644
|
||||
--- a/src/main.rs
|
||||
+++ b/src/main.rs
|
||||
@@ -608,9 +608,22 @@ async fn main() -> Result<()> {
|
||||
let payload = Arc::clone(&encr_payload_arc);
|
||||
|
||||
let revocation_cert = revocation::get_revocation_cert_path(&config)?;
|
||||
- let actions_dir =
|
||||
- Path::new(&config.revocation_actions_dir).canonicalize()?;
|
||||
- let work_dir = Path::new(&config.work_dir).canonicalize()?;
|
||||
+ let actions_dir = Path::new(&config.revocation_actions_dir)
|
||||
+ .canonicalize()
|
||||
+ .map_err(|e| {
|
||||
+ Error::Configuration(format!(
|
||||
+ "Path {} set in revocation_actions_dir not found: {}",
|
||||
+ &config.revocation_actions_dir, e
|
||||
+ ))
|
||||
+ })?;
|
||||
+
|
||||
+ let work_dir =
|
||||
+ Path::new(&config.work_dir).canonicalize().map_err(|e| {
|
||||
+ Error::Configuration(format!(
|
||||
+ "Path {} set in keylime_dir not found: {}",
|
||||
+ &config.work_dir, e
|
||||
+ ))
|
||||
+ })?;
|
||||
|
||||
let quotedata = web::Data::new(QuoteData {
|
||||
tpmcontext: Mutex::new(ctx),
|
||||
@ -1,193 +0,0 @@
|
||||
From 9229cb4673aad2cae7605e66bdf2160716e1f694 Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Thu, 9 Jun 2022 18:34:34 +0200
|
||||
Subject: [PATCH 1/4] Update clap dependency to 3.1.18
|
||||
|
||||
This change replaces clap::App with clap::Command in main.rs file.
|
||||
|
||||
On commit f3fa925 the clap dependency in Cargo.lock file was updated
|
||||
from version 3.0.14 to version 3.1.18.
|
||||
|
||||
In clap version 3.1.0, clap::App was deprecated in favor of
|
||||
clap::Command. This causes warnings during the Keylime agent build due
|
||||
to the usage of the deprecated structure.
|
||||
|
||||
To avoid similar issues in the future, use the tilde dependency version
|
||||
requirement to allow versions >= 3.1.18 but < 3.2.0.
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
Cargo.lock | 76 ++++++++++++++++++++++-------------------------------
|
||||
Cargo.toml | 2 +-
|
||||
src/main.rs | 2 +-
|
||||
3 files changed, 33 insertions(+), 47 deletions(-)
|
||||
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 92f3974..f0c7d39 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -21,7 +21,7 @@ doc = false
|
||||
actix-web = { version = "4", features = ["openssl"] }
|
||||
base64 = "0.13"
|
||||
cfg-if = "1"
|
||||
-clap = { version = "3.0.14", features = ["derive"] }
|
||||
+clap = { version = "~3.1.18", features = ["derive"] }
|
||||
compress-tools = "0.12"
|
||||
flate2 = "1.0.4"
|
||||
futures = "0.3.6"
|
||||
diff --git a/src/main.rs b/src/main.rs
|
||||
index 1896104..8540597 100644
|
||||
--- a/src/main.rs
|
||||
+++ b/src/main.rs
|
||||
@@ -51,7 +51,7 @@ mod tpm;
|
||||
mod version_handler;
|
||||
|
||||
use actix_web::{dev::Service, http, middleware, rt, web, App, HttpServer};
|
||||
-use clap::{App as ClapApp, Arg};
|
||||
+use clap::{Arg, Command as ClapApp};
|
||||
use common::*;
|
||||
use compress_tools::*;
|
||||
use error::{Error, Result};
|
||||
--
|
||||
2.35.3
|
||||
|
||||
|
||||
From c61e3f389e4bde4d0a318a571c9b3dcf8a62749f Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Tue, 17 May 2022 18:31:01 +0200
|
||||
Subject: [PATCH 2/4] Drop unused dependency rustc-serialize
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
Cargo.lock | 7 -------
|
||||
Cargo.toml | 1 -
|
||||
2 files changed, 8 deletions(-)
|
||||
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index f0c7d39..0f4e4ab 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -34,7 +34,6 @@ picky-asn1-x509 = "0.6.1"
|
||||
pretty_env_logger = "0.4"
|
||||
reqwest = {version = "0.11", features = ["json"]}
|
||||
rust-ini = "0.17"
|
||||
-rustc-serialize = "0.3.24"
|
||||
serde = "1.0.80"
|
||||
serde_derive = "1.0.80"
|
||||
serde_json = { version = "1.0", features = ["raw_value"] }
|
||||
--
|
||||
2.35.3
|
||||
|
||||
|
||||
From f7b59a6a7739d275ffe15a915eb48a36ceafccdd Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Tue, 17 May 2022 18:56:50 +0200
|
||||
Subject: [PATCH 3/4] Drop unused dependency flate2
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
Cargo.lock | 1 -
|
||||
Cargo.toml | 1 -
|
||||
src/tpm.rs | 3 ---
|
||||
3 files changed, 5 deletions(-)
|
||||
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 0f4e4ab..69d2eec 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -23,7 +23,6 @@ base64 = "0.13"
|
||||
cfg-if = "1"
|
||||
clap = { version = "~3.1.18", features = ["derive"] }
|
||||
compress-tools = "0.12"
|
||||
-flate2 = "1.0.4"
|
||||
futures = "0.3.6"
|
||||
hex = "0.4"
|
||||
libc = "0.2.43"
|
||||
diff --git a/src/tpm.rs b/src/tpm.rs
|
||||
index 355dd0d..43129f1 100644
|
||||
--- a/src/tpm.rs
|
||||
+++ b/src/tpm.rs
|
||||
@@ -20,8 +20,6 @@ use openssl::{
|
||||
pkey::{Id, PKeyRef, Public},
|
||||
};
|
||||
|
||||
-use flate2::{write::ZlibEncoder, Compression};
|
||||
-
|
||||
use tss_esapi::{
|
||||
abstraction::{
|
||||
ak,
|
||||
@@ -635,7 +633,6 @@ pub(crate) fn quote(
|
||||
#[cfg(test)]
|
||||
pub mod testing {
|
||||
use super::*;
|
||||
- use flate2::read::ZlibDecoder;
|
||||
use tss_esapi::constants::structure_tags::StructureTag;
|
||||
use tss_esapi::structures::{Attest, AttestBuffer, DigestList, Ticket};
|
||||
use tss_esapi::tss2_esys::Tss2_MU_TPMT_SIGNATURE_Unmarshal;
|
||||
--
|
||||
2.35.3
|
||||
|
||||
|
||||
From c3f0b4f603089d38715535f8e16b7a40f413e4de Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Thu, 9 Jun 2022 16:21:06 +0200
|
||||
Subject: [PATCH 4/4] Make wiremock an optional dependency
|
||||
|
||||
Make a wiremock optional, enabled when the 'testing' feature is enabled.
|
||||
The goal is to reduce the number of dependencies, with the downside that
|
||||
the test code coverage will drop.
|
||||
|
||||
Wiremock is currently used only on 'registrar_agent' tests to mock
|
||||
responses from the registrar service.
|
||||
|
||||
Note: wiremock was moved to be an optional regular dependency because
|
||||
optional dev-dependencies are not supported.
|
||||
see: https://github.com/rust-lang/cargo/issues/1596
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
Cargo.toml | 7 +++++--
|
||||
src/registrar_agent.rs | 1 +
|
||||
2 files changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 69d2eec..5052512 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -43,16 +43,19 @@ tss-esapi = "7.1.0"
|
||||
thiserror = "1.0"
|
||||
uuid = {version = "0.8", features = ["v4"]}
|
||||
zmq = {version = "0.9.2", optional = true}
|
||||
+# wiremock was moved to be a regular dependency because optional
|
||||
+# dev-dependencies are not supported
|
||||
+# see: https://github.com/rust-lang/cargo/issues/1596
|
||||
+wiremock = {version = "0.5", optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2"
|
||||
-wiremock = "0.5"
|
||||
|
||||
[features]
|
||||
# The features enabled by default
|
||||
default = ["with-zmq", "legacy-python-actions"]
|
||||
# this should change to dev-dependencies when we have integration testing
|
||||
-testing = []
|
||||
+testing = ["wiremock"]
|
||||
# Whether the agent should be compiled with support to listen for notification
|
||||
# messages on ZeroMQ
|
||||
with-zmq = ["zmq"]
|
||||
diff --git a/src/registrar_agent.rs b/src/registrar_agent.rs
|
||||
index 85b5931..b02ba48 100644
|
||||
--- a/src/registrar_agent.rs
|
||||
+++ b/src/registrar_agent.rs
|
||||
@@ -149,6 +149,7 @@ pub(crate) async fn do_register_agent(
|
||||
}
|
||||
}
|
||||
|
||||
+#[cfg(feature = "testing")]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
--
|
||||
2.35.3
|
||||
|
||||
@ -1,899 +0,0 @@
|
||||
From d30000a1c3ae6cb8f6dc60c295e037614605b36e Mon Sep 17 00:00:00 2001
|
||||
From: Daiki Ueno <dueno@redhat.com>
|
||||
Date: Tue, 5 Jul 2022 16:24:32 +0900
|
||||
Subject: [PATCH 1/4] algorithms: Add conversion between our hash algorithms
|
||||
and OpenSSL's
|
||||
|
||||
Signed-off-by: Daiki Ueno <dueno@redhat.com>
|
||||
---
|
||||
src/algorithms.rs | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/src/algorithms.rs b/src/algorithms.rs
|
||||
index 414ef100..019f9360 100644
|
||||
--- a/src/algorithms.rs
|
||||
+++ b/src/algorithms.rs
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2021 Keylime Authors
|
||||
+use openssl::hash::MessageDigest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
@@ -74,6 +75,18 @@ impl From<HashAlgorithm> for HashingAlgorithm {
|
||||
}
|
||||
}
|
||||
|
||||
+impl From<HashAlgorithm> for MessageDigest {
|
||||
+ fn from(hash_algorithm: HashAlgorithm) -> Self {
|
||||
+ match hash_algorithm {
|
||||
+ HashAlgorithm::Sha1 => MessageDigest::sha1(),
|
||||
+ HashAlgorithm::Sha256 => MessageDigest::sha256(),
|
||||
+ HashAlgorithm::Sha384 => MessageDigest::sha384(),
|
||||
+ HashAlgorithm::Sha512 => MessageDigest::sha512(),
|
||||
+ HashAlgorithm::Sm3_256 => MessageDigest::sm3(),
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum EncryptionAlgorithm {
|
||||
Rsa,
|
||||
|
||||
From a90aa5b0852d587114aca7a8e79306987c562624 Mon Sep 17 00:00:00 2001
|
||||
From: Daiki Ueno <dueno@redhat.com>
|
||||
Date: Tue, 5 Jul 2022 15:43:42 +0900
|
||||
Subject: [PATCH 2/4] ima_entry: add IMA entry parser ported from Python
|
||||
Keylime
|
||||
|
||||
Signed-off-by: Daiki Ueno <dueno@redhat.com>
|
||||
---
|
||||
src/ima_entry.rs | 516 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 516 insertions(+)
|
||||
create mode 100644 src/ima_entry.rs
|
||||
|
||||
diff --git a/src/ima_entry.rs b/src/ima_entry.rs
|
||||
new file mode 100644
|
||||
index 00000000..7bb4a970
|
||||
--- /dev/null
|
||||
+++ b/src/ima_entry.rs
|
||||
@@ -0,0 +1,516 @@
|
||||
+// SPDX-License-Identifier: Apache-2.0
|
||||
+// Copyright 2022 Keylime Authors
|
||||
+
|
||||
+// Parser for IMA ASCII entries.
|
||||
+//
|
||||
+// Implements the templates (modes) and types as defined in:
|
||||
+// https://elixir.bootlin.com/linux/latest/source/security/integrity/ima/ima_template.c
|
||||
+// https://www.kernel.org/doc/html/v5.12/security/IMA-templates.html
|
||||
+
|
||||
+use crate::algorithms::HashAlgorithm;
|
||||
+use openssl::hash::MessageDigest;
|
||||
+use std::convert::{TryFrom, TryInto};
|
||||
+use std::io::{Error, ErrorKind, Result, Write};
|
||||
+
|
||||
+pub trait Encode {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()>;
|
||||
+}
|
||||
+
|
||||
+pub trait EncodeLegacy {
|
||||
+ fn encode_legacy(&self, writer: &mut dyn Write) -> Result<()>;
|
||||
+}
|
||||
+
|
||||
+#[derive(PartialEq)]
|
||||
+pub struct Digest {
|
||||
+ pub algorithm: HashAlgorithm,
|
||||
+ value: Vec<u8>,
|
||||
+}
|
||||
+
|
||||
+impl Digest {
|
||||
+ pub fn new(algorithm: HashAlgorithm, value: &[u8]) -> Result<Self> {
|
||||
+ let digest: MessageDigest = algorithm.into();
|
||||
+ if value.len() != digest.size() {
|
||||
+ return Err(Error::new(
|
||||
+ ErrorKind::InvalidInput,
|
||||
+ "invalid digest value",
|
||||
+ ));
|
||||
+ }
|
||||
+ let mut v = Vec::with_capacity(digest.size());
|
||||
+ v.extend_from_slice(value);
|
||||
+ Ok(Self {
|
||||
+ algorithm,
|
||||
+ value: v,
|
||||
+ })
|
||||
+ }
|
||||
+
|
||||
+ pub fn value(&self) -> &[u8] {
|
||||
+ &self.value
|
||||
+ }
|
||||
+
|
||||
+ pub fn start(algorithm: HashAlgorithm) -> Self {
|
||||
+ let digest: MessageDigest = algorithm.into();
|
||||
+ Self {
|
||||
+ algorithm,
|
||||
+ value: vec![0x00u8; digest.size()],
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pub fn ff(algorithm: HashAlgorithm) -> Self {
|
||||
+ let digest: MessageDigest = algorithm.into();
|
||||
+ Self {
|
||||
+ algorithm,
|
||||
+ value: vec![0xffu8; digest.size()],
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for Digest {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ let tokens: Vec<&str> = value.splitn(2, ':').collect();
|
||||
+ if tokens.len() == 1 {
|
||||
+ Ok(Digest {
|
||||
+ algorithm: HashAlgorithm::Sha1,
|
||||
+ value: hex::decode(&tokens[0]).map_err(|_| {
|
||||
+ Error::new(
|
||||
+ ErrorKind::InvalidInput,
|
||||
+ "invalid hex encoding",
|
||||
+ )
|
||||
+ })?,
|
||||
+ })
|
||||
+ } else {
|
||||
+ Ok(Digest {
|
||||
+ algorithm: tokens[0].try_into().map_err(|_| {
|
||||
+ Error::new(ErrorKind::InvalidInput, "invalid algorithm")
|
||||
+ })?,
|
||||
+ value: hex::decode(&tokens[1]).map_err(|_| {
|
||||
+ Error::new(
|
||||
+ ErrorKind::InvalidInput,
|
||||
+ "invalid hex encoding",
|
||||
+ )
|
||||
+ })?,
|
||||
+ })
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl Encode for Digest {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ if self.algorithm == HashAlgorithm::Sha1 {
|
||||
+ writer.write_all(&(self.value.len() as u32).to_le_bytes())?;
|
||||
+ writer.write_all(&self.value)?;
|
||||
+ } else {
|
||||
+ let algorithm = format!("{}", self.algorithm);
|
||||
+ let total_len = algorithm.len() + 2 + self.value.len();
|
||||
+ writer.write_all(&(total_len as u32).to_le_bytes())?;
|
||||
+ writer.write_all(algorithm.as_bytes())?;
|
||||
+ writer.write_all(&[58u8, 0u8])?;
|
||||
+ writer.write_all(&self.value)?;
|
||||
+ }
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl EncodeLegacy for Digest {
|
||||
+ fn encode_legacy(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ writer.write_all(&self.value)?;
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct Name {
|
||||
+ name: String,
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for Name {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ Ok(Self {
|
||||
+ name: value.to_string(),
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+const TCG_EVENT_NAME_LEN_MAX: usize = 255;
|
||||
+
|
||||
+impl Encode for Name {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ let bytes = self.name.as_bytes();
|
||||
+ writer.write_all(&((bytes.len() + 1) as u32).to_le_bytes())?;
|
||||
+ writer.write_all(bytes)?;
|
||||
+ writer.write_all(&[0u8])?; // NUL
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl EncodeLegacy for Name {
|
||||
+ fn encode_legacy(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ let bytes = self.name.as_bytes();
|
||||
+ writer.write_all(bytes)?;
|
||||
+ writer.write_all(&vec![0u8; TCG_EVENT_NAME_LEN_MAX - bytes.len()])?;
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct Signature {
|
||||
+ value: Vec<u8>,
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for Signature {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ let value = hex::decode(value).map_err(|_| {
|
||||
+ Error::new(ErrorKind::InvalidInput, "invalid hex encoding")
|
||||
+ })?;
|
||||
+ // basic checks on signature
|
||||
+ if value.len() < 9 {
|
||||
+ return Err(Error::new(
|
||||
+ ErrorKind::InvalidInput,
|
||||
+ "invalid signature",
|
||||
+ ));
|
||||
+ }
|
||||
+ let sig_size = u16::from_be_bytes(value[7..9].try_into().unwrap()); //#[allow_ci]
|
||||
+ if (sig_size as usize) + 9 != value.len() {
|
||||
+ return Err(Error::new(
|
||||
+ ErrorKind::InvalidInput,
|
||||
+ "invalid signature",
|
||||
+ ));
|
||||
+ }
|
||||
+ Ok(Self { value })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl Encode for Signature {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ writer.write_all(&(self.value.len() as u32).to_le_bytes())?;
|
||||
+ writer.write_all(&self.value)?;
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct Buffer {
|
||||
+ value: Vec<u8>,
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for Buffer {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ Ok(Self {
|
||||
+ value: hex::decode(value).map_err(|_| {
|
||||
+ Error::new(ErrorKind::InvalidInput, "invalid hex encoding")
|
||||
+ })?,
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl Encode for Buffer {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ writer.write_all(&(self.value.len() as u32).to_le_bytes())?;
|
||||
+ writer.write_all(&self.value)?;
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+pub trait EventData: Encode {
|
||||
+ fn path(&self) -> &str;
|
||||
+}
|
||||
+
|
||||
+struct Ima {
|
||||
+ digest: Digest,
|
||||
+ path: Name,
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for Ima {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ let tokens: Vec<&str> = value.splitn(2, ' ').collect();
|
||||
+ if tokens.len() != 2 {
|
||||
+ return Err(Error::new(ErrorKind::InvalidInput, value));
|
||||
+ }
|
||||
+ Ok(Self {
|
||||
+ digest: Digest::try_from(tokens[0])?,
|
||||
+ path: Name::try_from(tokens[1])?,
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl EventData for Ima {
|
||||
+ fn path(&self) -> &str {
|
||||
+ &self.path.name
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl Encode for Ima {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ self.digest.encode_legacy(writer)?;
|
||||
+ self.path.encode_legacy(writer)?;
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct ImaNg {
|
||||
+ digest: Digest,
|
||||
+ path: Name,
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for ImaNg {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ let tokens: Vec<&str> = value.splitn(2, ' ').collect();
|
||||
+ if tokens.len() != 2 {
|
||||
+ return Err(Error::new(ErrorKind::InvalidInput, value));
|
||||
+ }
|
||||
+
|
||||
+ Ok(Self {
|
||||
+ digest: Digest::try_from(tokens[0])?,
|
||||
+ path: Name::try_from(tokens[1])?,
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl EventData for ImaNg {
|
||||
+ fn path(&self) -> &str {
|
||||
+ &self.path.name
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl Encode for ImaNg {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ self.digest.encode(writer)?;
|
||||
+ self.path.encode(writer)?;
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct ImaSig {
|
||||
+ digest: Digest,
|
||||
+ path: Name,
|
||||
+ signature: Option<Signature>,
|
||||
+}
|
||||
+
|
||||
+impl EventData for ImaSig {
|
||||
+ fn path(&self) -> &str {
|
||||
+ &self.path.name
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for ImaSig {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ // extract signature first
|
||||
+ let (value, signature) = value
|
||||
+ .rsplit_once(' ')
|
||||
+ .ok_or_else(|| Error::new(ErrorKind::InvalidInput, value))?;
|
||||
+
|
||||
+ // parse d-ng|n-ng as in ima-ng
|
||||
+ let tokens: Vec<&str> = value.splitn(2, ' ').collect();
|
||||
+ if tokens.len() != 2 {
|
||||
+ return Err(Error::new(ErrorKind::InvalidInput, value));
|
||||
+ }
|
||||
+
|
||||
+ let digest = Digest::try_from(tokens[0])?;
|
||||
+ let path = Name::try_from(tokens[1])?;
|
||||
+ let signature = if !signature.is_empty() {
|
||||
+ Some(Signature::try_from(signature)?)
|
||||
+ } else {
|
||||
+ None
|
||||
+ };
|
||||
+
|
||||
+ Ok(Self {
|
||||
+ digest,
|
||||
+ path,
|
||||
+ signature,
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl Encode for ImaSig {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ self.digest.encode(writer)?;
|
||||
+ self.path.encode(writer)?;
|
||||
+ if let Some(signature) = &self.signature {
|
||||
+ signature.encode(writer)?;
|
||||
+ } else {
|
||||
+ writer.write_all(&0u32.to_le_bytes())?;
|
||||
+ }
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct ImaBuf {
|
||||
+ digest: Digest,
|
||||
+ name: Name,
|
||||
+ data: Buffer,
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for ImaBuf {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ let tokens: Vec<&str> = value.splitn(3, ' ').collect();
|
||||
+ if tokens.len() != 3 {
|
||||
+ return Err(Error::new(ErrorKind::InvalidInput, value));
|
||||
+ }
|
||||
+ Ok(Self {
|
||||
+ digest: Digest::try_from(tokens[0])?,
|
||||
+ name: Name::try_from(tokens[1])?,
|
||||
+ data: Buffer::try_from(tokens[2])?,
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl EventData for ImaBuf {
|
||||
+ fn path(&self) -> &str {
|
||||
+ &self.name.name
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+impl Encode for ImaBuf {
|
||||
+ fn encode(&self, writer: &mut dyn Write) -> Result<()> {
|
||||
+ self.digest.encode(writer)?;
|
||||
+ self.name.encode(writer)?;
|
||||
+ self.data.encode(writer)?;
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+pub struct Entry {
|
||||
+ pub template_hash: Digest,
|
||||
+ pub event_data: Box<dyn EventData>,
|
||||
+}
|
||||
+
|
||||
+impl TryFrom<&str> for Entry {
|
||||
+ type Error = std::io::Error;
|
||||
+
|
||||
+ fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
|
||||
+ let tokens: Vec<&str> = value.splitn(4, ' ').collect();
|
||||
+ if tokens.len() != 4 {
|
||||
+ return Err(Error::new(ErrorKind::InvalidInput, value));
|
||||
+ }
|
||||
+
|
||||
+ let template_hash = Digest {
|
||||
+ algorithm: HashAlgorithm::Sha1,
|
||||
+ value: hex::decode(&tokens[1]).map_err(|_| {
|
||||
+ Error::new(ErrorKind::InvalidInput, "invalid hex encoding")
|
||||
+ })?,
|
||||
+ };
|
||||
+ let mode = tokens[2];
|
||||
+ let event = tokens[3];
|
||||
+
|
||||
+ match mode {
|
||||
+ "ima" => Ok(Self {
|
||||
+ template_hash,
|
||||
+ event_data: Box::new(Ima::try_from(event)?),
|
||||
+ }),
|
||||
+ "ima-ng" => Ok(Self {
|
||||
+ template_hash,
|
||||
+ event_data: Box::new(ImaNg::try_from(event)?),
|
||||
+ }),
|
||||
+ "ima-sig" => Ok(Self {
|
||||
+ template_hash,
|
||||
+ event_data: Box::new(ImaSig::try_from(event)?),
|
||||
+ }),
|
||||
+ "ima-buf" => Ok(Self {
|
||||
+ template_hash,
|
||||
+ event_data: Box::new(ImaBuf::try_from(event)?),
|
||||
+ }),
|
||||
+ template => Err(Error::new(
|
||||
+ ErrorKind::Other,
|
||||
+ format!("unrecognized template \"{}\"", template,),
|
||||
+ )),
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// Unit Testing
|
||||
+#[cfg(test)]
|
||||
+mod tests {
|
||||
+ use super::*;
|
||||
+
|
||||
+ #[test]
|
||||
+ fn test_parse_ima() {
|
||||
+ let entry: Entry = "10 d7026dc672344d3ee372217bdbc7395947788671 ima 6f66d1d8e2fffcc12dfcb78c04b81fe5b8bbae4e /usr/bin/kmod"
|
||||
+ .try_into().expect("unable to parse ima template");
|
||||
+ assert_eq!(entry.event_data.path(), "/usr/bin/kmod");
|
||||
+ let mut buf = vec![];
|
||||
+ entry
|
||||
+ .event_data
|
||||
+ .encode(&mut buf)
|
||||
+ .expect("unable to encode event data");
|
||||
+ assert_eq!(
|
||||
+ &buf,
|
||||
+ &hex::decode("6f66d1d8e2fffcc12dfcb78c04b81fe5b8bbae4e2f7573722f62696e2f6b6d6f640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(), //#[allow_ci]
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn test_parse_ima_ng() {
|
||||
+ let entry: Entry = "10 7936eb315fb4e74b99e7d461bc5c96049e1ee092 ima-ng sha1:bc026ae66d81713e4e852465e980784dc96651f8 /usr/lib/systemd/systemd"
|
||||
+ .try_into().expect("unable to parse ima-ng template");
|
||||
+ assert_eq!(entry.event_data.path(), "/usr/lib/systemd/systemd");
|
||||
+ let mut buf = vec![];
|
||||
+ entry
|
||||
+ .event_data
|
||||
+ .encode(&mut buf)
|
||||
+ .expect("unable to encode event data");
|
||||
+ assert_eq!(
|
||||
+ &buf,
|
||||
+ &hex::decode("14000000bc026ae66d81713e4e852465e980784dc96651f8190000002f7573722f6c69622f73797374656d642f73797374656d6400").unwrap(), //#[allow_ci]
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn test_parse_ima_sig() {
|
||||
+ let entry: Entry = "10 06e804489a77ddab51b9ef27e17053c0e5d503bd ima-sig sha1:1cb84b12db45d7da8de58ba6744187db84082f0e /usr/bin/zmore 030202531f402500483046022100bff9c02dc7b270c83cc94bfec10eecd42831de2cdcb04f024369a14623bc3a91022100cc4d015ae932fb98d6846645ed7d1bb1afd4621ec9089bc087126f191886dd31"
|
||||
+ .try_into().expect("unable to parse ima-sig template");
|
||||
+ assert_eq!(entry.event_data.path(), "/usr/bin/zmore");
|
||||
+ let mut buf = vec![];
|
||||
+ entry
|
||||
+ .event_data
|
||||
+ .encode(&mut buf)
|
||||
+ .expect("unable to encode event data");
|
||||
+ assert_eq!(
|
||||
+ &buf,
|
||||
+ &hex::decode("140000001cb84b12db45d7da8de58ba6744187db84082f0e0f0000002f7573722f62696e2f7a6d6f72650051000000030202531f402500483046022100bff9c02dc7b270c83cc94bfec10eecd42831de2cdcb04f024369a14623bc3a91022100cc4d015ae932fb98d6846645ed7d1bb1afd4621ec9089bc087126f191886dd31").unwrap(), //#[allow_ci]
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn test_parse_ima_sig_missing() {
|
||||
+ let entry: Entry = "10 5426cf3031a43f5bfca183d79950698a95a728f6 ima-sig sha256:f1125b940480d20ad841d26d5ea253edc0704b5ec1548c891edf212cb1a9365e /lib/modules/5.4.48-openpower1/kernel/drivers/usb/common/usb-common.ko "
|
||||
+ .try_into().expect("unable to parse ima-sig template without signature");
|
||||
+ assert_eq!(entry.event_data.path(), "/lib/modules/5.4.48-openpower1/kernel/drivers/usb/common/usb-common.ko");
|
||||
+ let mut buf = vec![];
|
||||
+ entry
|
||||
+ .event_data
|
||||
+ .encode(&mut buf)
|
||||
+ .expect("unable to encode event data");
|
||||
+ assert_eq!(
|
||||
+ &buf,
|
||||
+ &hex::decode("280000007368613235363a00f1125b940480d20ad841d26d5ea253edc0704b5ec1548c891edf212cb1a9365e470000002f6c69622f6d6f64756c65732f352e342e34382d6f70656e706f776572312f6b65726e656c2f647269766572732f7573622f636f6d6d6f6e2f7573622d636f6d6d6f6e2e6b6f0000000000").unwrap(), //#[allow_ci]
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn test_parse_ima_buf() {
|
||||
+ let entry: Entry = "10 b7862dbbf1383ac6c7cca7f02d981a081aacb1f1 ima-buf sha1:6e0e6fc8a188ef4f059638949adca4d221946906 device_resume 6e616d653d544553543b757569643d43525950542d5645524954592d39656633326535623635623034343234613561386562343436636630653731332d544553543b63617061636974793d303b6d616a6f723d3235333b6d696e6f723d303b6d696e6f725f636f756e743d313b6e756d5f746172676574733d313b6163746976655f7461626c655f686173683d346565383065333365353635643336333430356634303238393436653837623365396563306335383661666639656630656436663561653762656237326431333b"
|
||||
+ .try_into().expect("unable to parse ima-buf template");
|
||||
+ assert_eq!(entry.event_data.path(), "device_resume");
|
||||
+ let mut buf = vec![];
|
||||
+ entry
|
||||
+ .event_data
|
||||
+ .encode(&mut buf)
|
||||
+ .expect("unable to encode event data");
|
||||
+ assert_eq!(
|
||||
+ &buf,
|
||||
+ &hex::decode("140000006e0e6fc8a188ef4f059638949adca4d2219469060e0000006465766963655f726573756d6500ce0000006e616d653d544553543b757569643d43525950542d5645524954592d39656633326535623635623034343234613561386562343436636630653731332d544553543b63617061636974793d303b6d616a6f723d3235333b6d696e6f723d303b6d696e6f725f636f756e743d313b6e756d5f746172676574733d313b6163746976655f7461626c655f686173683d346565383065333365353635643336333430356634303238393436653837623365396563306335383661666639656630656436663561653762656237326431333b").unwrap(), //#[allow_ci]
|
||||
+ );
|
||||
+ }
|
||||
+}
|
||||
|
||||
From 7decf3b0985235e28f36c1b445def535d615c8df Mon Sep 17 00:00:00 2001
|
||||
From: Daiki Ueno <dueno@redhat.com>
|
||||
Date: Sun, 15 May 2022 17:46:36 +0200
|
||||
Subject: [PATCH 3/4] ima_emulator: Support PCR hash algorithms other than
|
||||
SHA-1
|
||||
|
||||
This ports the recent changes to keylime_ima_emulator in the Python
|
||||
stack, which allows PCR hash algorithms other than SHA-1 through the
|
||||
command-line options.
|
||||
|
||||
Signed-off-by: Daiki Ueno <dueno@redhat.com>
|
||||
---
|
||||
src/algorithms.rs | 1 -
|
||||
src/ima_emulator.rs | 176 ++++++++++++++++++++++++++++++--------------
|
||||
2 files changed, 122 insertions(+), 55 deletions(-)
|
||||
|
||||
diff --git a/src/algorithms.rs b/src/algorithms.rs
|
||||
index 019f9360..3386abd7 100644
|
||||
--- a/src/algorithms.rs
|
||||
+++ b/src/algorithms.rs
|
||||
@@ -10,7 +10,6 @@ use tss_esapi::{
|
||||
AsymmetricAlgorithm, HashingAlgorithm, SignatureSchemeAlgorithm,
|
||||
},
|
||||
structures::{HashScheme, SignatureScheme},
|
||||
- tss2_esys::TPMT_SIG_SCHEME,
|
||||
};
|
||||
|
||||
// This error needs to be public because we implement TryFrom for public types
|
||||
diff --git a/src/ima_emulator.rs b/src/ima_emulator.rs
|
||||
index ba590bbc..c09e41b6 100644
|
||||
--- a/src/ima_emulator.rs
|
||||
+++ b/src/ima_emulator.rs
|
||||
@@ -1,28 +1,32 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2021 Keylime Authors
|
||||
|
||||
+mod algorithms;
|
||||
+use crate::algorithms::HashAlgorithm;
|
||||
+mod ima_entry;
|
||||
+use openssl::hash::{hash, MessageDigest};
|
||||
+
|
||||
use log::*;
|
||||
|
||||
-use std::convert::TryFrom;
|
||||
+use clap::Parser;
|
||||
+use std::collections::HashMap;
|
||||
+use std::convert::{TryFrom, TryInto};
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
+use std::path::{Path, PathBuf};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use tss_esapi::{
|
||||
abstraction::pcr,
|
||||
handles::PcrHandle,
|
||||
- interface_types::algorithm::HashingAlgorithm,
|
||||
structures::{Digest, DigestValues, PcrSelectionListBuilder, PcrSlot},
|
||||
Context, Tcti,
|
||||
};
|
||||
|
||||
const IMA_ML: &str = "/sys/kernel/security/ima/ascii_runtime_measurements";
|
||||
|
||||
-const START_HASH: &[u8; 20] = &[0u8; 20];
|
||||
-const FF_HASH: &[u8; 20] = &[0xffu8; 20];
|
||||
-
|
||||
#[derive(Error, Debug)]
|
||||
enum ImaEmulatorError {
|
||||
#[error("Invalid envvar")]
|
||||
@@ -31,8 +35,14 @@ enum ImaEmulatorError {
|
||||
TssEsapiError(#[from] tss_esapi::Error),
|
||||
#[error("Decoding error")]
|
||||
FromHexError(#[from] hex::FromHexError),
|
||||
+ #[error("Algorithm error")]
|
||||
+ AlgorithmError(#[from] algorithms::AlgorithmError),
|
||||
+ #[error("OpenSSL error")]
|
||||
+ OpenSSLError(#[from] openssl::error::ErrorStack),
|
||||
#[error("I/O error")]
|
||||
IoError(#[from] std::io::Error),
|
||||
+ #[error("Integer parsing error")]
|
||||
+ ParseInt(#[from] std::num::ParseIntError),
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
}
|
||||
@@ -41,57 +51,75 @@ type Result<T> = std::result::Result<T, ImaEmulatorError>;
|
||||
|
||||
fn ml_extend(
|
||||
context: &mut Context,
|
||||
- ml: &str,
|
||||
+ ml: &Path,
|
||||
mut position: usize,
|
||||
+ ima_hash_alg: HashAlgorithm,
|
||||
+ pcr_hash_alg: HashAlgorithm,
|
||||
search_hash: Option<&Digest>,
|
||||
) -> Result<usize> {
|
||||
let f = File::open(ml)?;
|
||||
let mut reader = BufReader::new(f);
|
||||
- let mut running_hash: Vec<u8> = Vec::from(&START_HASH[..]);
|
||||
+ let ima_digest: MessageDigest = ima_hash_alg.into();
|
||||
+ let ima_start_hash = ima_entry::Digest::start(ima_hash_alg);
|
||||
+ let pcr_digest: MessageDigest = pcr_hash_alg.into();
|
||||
+ let mut running_hash = ima_entry::Digest::start(pcr_hash_alg);
|
||||
+ let ff_hash = ima_entry::Digest::ff(pcr_hash_alg);
|
||||
for line in reader.by_ref().lines().skip(position) {
|
||||
let line = line?;
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
- let tokens: Vec<&str> = line.splitn(5, ' ').collect();
|
||||
- if tokens.len() < 5 {
|
||||
- error!("invalid measurement list file line: -{}-", line);
|
||||
- }
|
||||
+
|
||||
+ let entry: ima_entry::Entry = line.as_str().try_into()?;
|
||||
+
|
||||
position += 1;
|
||||
|
||||
- let path = tokens[4];
|
||||
- let template_hash = hex::decode(tokens[1])?;
|
||||
- let template_hash = if template_hash == START_HASH {
|
||||
- Digest::try_from(&FF_HASH[..])
|
||||
+ // Set correct hash for time of measure, time of use (ToMToU) errors
|
||||
+ // and if a file is already opened for write.
|
||||
+ // https://elixir.bootlin.com/linux/v5.12.12/source/security/integrity/ima/ima_main.c#L101
|
||||
+ let pcr_template_hash = if entry.template_hash == ima_start_hash {
|
||||
+ Digest::try_from(ff_hash.value())
|
||||
} else {
|
||||
- Digest::try_from(template_hash)
|
||||
+ let mut event_data = vec![];
|
||||
+ entry.event_data.encode(&mut event_data)?;
|
||||
+ let pcr_event_hash = hash(pcr_digest, &event_data)?;
|
||||
+ let ima_event_hash = hash(ima_digest, &event_data)?;
|
||||
+ if ima_event_hash.as_ref() != entry.template_hash.value() {
|
||||
+ return Err(ImaEmulatorError::Other(
|
||||
+ "IMA template hash doesn't match".to_string(),
|
||||
+ ));
|
||||
+ }
|
||||
+ Digest::try_from(pcr_event_hash.as_ref())
|
||||
}?;
|
||||
|
||||
match search_hash {
|
||||
None => {
|
||||
println!(
|
||||
"extending hash {} for {}",
|
||||
- hex::encode(template_hash.value()),
|
||||
- &path
|
||||
+ hex::encode(pcr_template_hash.value()),
|
||||
+ entry.event_data.path(),
|
||||
);
|
||||
let mut vals = DigestValues::new();
|
||||
- vals.set(HashingAlgorithm::Sha1, template_hash);
|
||||
- // TODO: Add support for other hash algorithms
|
||||
+ vals.set(pcr_hash_alg.into(), pcr_template_hash);
|
||||
context.execute_with_nullauth_session(|ctx| {
|
||||
ctx.pcr_extend(PcrHandle::Pcr10, vals)
|
||||
})?;
|
||||
}
|
||||
Some(search_hash) => {
|
||||
- let mut hasher = openssl::sha::Sha1::new();
|
||||
- hasher.update(&running_hash);
|
||||
- hasher.update(&template_hash);
|
||||
- running_hash = hasher.finish().into();
|
||||
- let digest = Digest::try_from(running_hash.as_slice())?;
|
||||
+ let mut hasher = openssl::hash::Hasher::new(pcr_digest)?;
|
||||
+ hasher.update(running_hash.value())?;
|
||||
+ hasher.update(&pcr_template_hash)?;
|
||||
+ running_hash =
|
||||
+ ima_entry::Digest::new(pcr_hash_alg, &hasher.finish()?)?;
|
||||
+ let digest = Digest::try_from(running_hash.value())?;
|
||||
let mut vals = DigestValues::new();
|
||||
- vals.set(HashingAlgorithm::Sha1, digest.clone());
|
||||
+ vals.set(pcr_hash_alg.into(), digest.clone());
|
||||
|
||||
if digest == *search_hash {
|
||||
- println!("Located last IMA file updated: {}", path);
|
||||
+ println!(
|
||||
+ "Located last IMA file updated: {}",
|
||||
+ entry.event_data.path()
|
||||
+ );
|
||||
return Ok(position);
|
||||
}
|
||||
}
|
||||
@@ -106,7 +134,20 @@ fn ml_extend(
|
||||
Ok(position)
|
||||
}
|
||||
|
||||
+#[derive(Parser)]
|
||||
+#[clap(about)]
|
||||
+struct Args {
|
||||
+ #[clap(long = "hash_algs", short = 'a', default_value = "sha1")]
|
||||
+ hash_algs: Vec<String>,
|
||||
+ #[clap(long, short = 'i', default_value = "sha1")]
|
||||
+ ima_hash_alg: String,
|
||||
+ #[clap(long, short = 'f', default_value = IMA_ML)]
|
||||
+ ima_log: PathBuf,
|
||||
+}
|
||||
+
|
||||
fn main() -> std::result::Result<(), ImaEmulatorError> {
|
||||
+ let args = Args::parse();
|
||||
+
|
||||
let tcti =
|
||||
match Tcti::from_environment_variable() {
|
||||
Ok(tcti) => tcti,
|
||||
@@ -124,37 +165,64 @@ fn main() -> std::result::Result<(), ImaEmulatorError> {
|
||||
));
|
||||
}
|
||||
|
||||
- // check if pcr is clean
|
||||
- let pcr_list = PcrSelectionListBuilder::new()
|
||||
- .with_selection(HashingAlgorithm::Sha1, &[PcrSlot::Slot10])
|
||||
- .build()?;
|
||||
- let pcr_data = context
|
||||
- .execute_without_session(|ctx| pcr::read_all(ctx, pcr_list))?;
|
||||
- let digest = pcr_data
|
||||
- .pcr_bank(HashingAlgorithm::Sha1)
|
||||
- .ok_or_else(|| {
|
||||
- ImaEmulatorError::Other(
|
||||
- "IMA slot does not have SHA-1 bank".to_string(),
|
||||
- )
|
||||
- })?
|
||||
- .get_digest(PcrSlot::Slot10)
|
||||
- .ok_or_else(|| {
|
||||
- ImaEmulatorError::Other(
|
||||
- "could not read value from IMA PCR".to_string(),
|
||||
- )
|
||||
- })?;
|
||||
-
|
||||
- let mut pos = 0;
|
||||
-
|
||||
- if digest.value() != START_HASH {
|
||||
- log::warn!("IMA PCR is not empty, trying to find the last updated file in the measurement list...");
|
||||
- pos = ml_extend(&mut context, IMA_ML, 0, Some(digest))?;
|
||||
+ let ima_hash_alg: HashAlgorithm =
|
||||
+ args.ima_hash_alg.as_str().try_into()?;
|
||||
+ let mut positions = HashMap::new();
|
||||
+ for pcr_hash_alg in args.hash_algs {
|
||||
+ let pcr_hash_alg: HashAlgorithm = pcr_hash_alg.as_str().try_into()?;
|
||||
+ positions.insert(pcr_hash_alg, 0usize);
|
||||
+ }
|
||||
+
|
||||
+ for (pcr_hash_alg, position) in positions.iter_mut() {
|
||||
+ // check if pcr is clean
|
||||
+ let pcr_list = PcrSelectionListBuilder::new()
|
||||
+ .with_selection((*pcr_hash_alg).into(), &[PcrSlot::Slot10])
|
||||
+ .build()?;
|
||||
+ let pcr_data = context
|
||||
+ .execute_without_session(|ctx| pcr::read_all(ctx, pcr_list))?;
|
||||
+ let digest = pcr_data
|
||||
+ .pcr_bank((*pcr_hash_alg).into())
|
||||
+ .ok_or_else(|| {
|
||||
+ ImaEmulatorError::Other(format!(
|
||||
+ "IMA slot does not have {} bank",
|
||||
+ *pcr_hash_alg,
|
||||
+ ))
|
||||
+ })?
|
||||
+ .get_digest(PcrSlot::Slot10)
|
||||
+ .ok_or_else(|| {
|
||||
+ ImaEmulatorError::Other(
|
||||
+ "could not read value from IMA PCR".to_string(),
|
||||
+ )
|
||||
+ })?;
|
||||
+
|
||||
+ let pcr_digest: MessageDigest = (*pcr_hash_alg).into();
|
||||
+ let pcr_start_hash = vec![0x00u8; pcr_digest.size()];
|
||||
+ if digest.value() != pcr_start_hash {
|
||||
+ log::warn!("IMA PCR is not empty, trying to find the last updated file in the measurement list...");
|
||||
+ *position = ml_extend(
|
||||
+ &mut context,
|
||||
+ &args.ima_log,
|
||||
+ *position,
|
||||
+ ima_hash_alg,
|
||||
+ *pcr_hash_alg,
|
||||
+ Some(digest),
|
||||
+ )?;
|
||||
+ }
|
||||
}
|
||||
|
||||
- println!("Monitoring {}", IMA_ML);
|
||||
+ println!("Monitoring {}", args.ima_log.display());
|
||||
|
||||
loop {
|
||||
- pos = ml_extend(&mut context, IMA_ML, pos, None)?;
|
||||
+ for (pcr_hash_alg, position) in positions.iter_mut() {
|
||||
+ *position = ml_extend(
|
||||
+ &mut context,
|
||||
+ &args.ima_log,
|
||||
+ *position,
|
||||
+ ima_hash_alg,
|
||||
+ *pcr_hash_alg,
|
||||
+ None,
|
||||
+ )?;
|
||||
+ }
|
||||
|
||||
// FIXME: We could poll IMA_ML as in the python implementation, though
|
||||
// the file is not pollable:
|
||||
|
||||
From d0e2dd7dc9f24df1eb5ff3f8cde95e5e561992d6 Mon Sep 17 00:00:00 2001
|
||||
From: Karel Srot <ksrot@redhat.com>
|
||||
Date: Wed, 6 Jul 2022 22:02:53 +0200
|
||||
Subject: [PATCH 4/4] Enable usage of Rust IMA emulator in E2E tests.
|
||||
|
||||
Instalation of Rust IMA emulator has been implemented in
|
||||
https://github.com/RedHat-SP-Security/keylime-tests/pull/141
|
||||
|
||||
Signed-off-by: Karel Srot <ksrot@redhat.com>
|
||||
---
|
||||
packit-ci.fmf | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/packit-ci.fmf b/packit-ci.fmf
|
||||
index 9a9f9581..064bc0ae 100644
|
||||
--- a/packit-ci.fmf
|
||||
+++ b/packit-ci.fmf
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
environment:
|
||||
TPM_BINARY_MEASUREMENTS: /var/tmp/binary_bios_measurements
|
||||
+ RUST_IMA_EMULATOR: 1
|
||||
|
||||
prepare:
|
||||
how: shell
|
||||
@ -1,339 +0,0 @@
|
||||
--- a/src/common.rs 2022-06-03 17:28:38.000000000 +0200
|
||||
+++ b/src/common.rs 2022-07-04 13:48:28.257066939 +0200
|
||||
@@ -231,59 +231,122 @@
|
||||
|
||||
impl KeylimeConfig {
|
||||
pub fn build() -> Result<Self> {
|
||||
- let agent_ip =
|
||||
- config_get_env("cloud_agent", "cloudagent_ip", "CLOUDAGENT_IP")?;
|
||||
+ let conf_name = config_file_get();
|
||||
+ let conf = Ini::load_from_file(&conf_name)?;
|
||||
+
|
||||
+ let agent_ip = config_get_env(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "cloudagent_ip",
|
||||
+ "CLOUDAGENT_IP",
|
||||
+ )?;
|
||||
let agent_port = config_get_env(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
"cloud_agent",
|
||||
"cloudagent_port",
|
||||
"CLOUDAGENT_PORT",
|
||||
)?;
|
||||
- let registrar_ip =
|
||||
- config_get_env("cloud_agent", "registrar_ip", "REGISTRAR_IP")?;
|
||||
+ let registrar_ip = config_get_env(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "registrar_ip",
|
||||
+ "REGISTRAR_IP",
|
||||
+ )?;
|
||||
let registrar_port = config_get_env(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
"cloud_agent",
|
||||
"registrar_port",
|
||||
"REGISTRAR_PORT",
|
||||
)?;
|
||||
- let agent_uuid_config = config_get("cloud_agent", "agent_uuid")?;
|
||||
+ let agent_uuid_config =
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "agent_uuid")?;
|
||||
let agent_uuid = get_uuid(&agent_uuid_config);
|
||||
- let agent_contact_ip = cloudagent_contact_ip_get();
|
||||
- let agent_contact_port = cloudagent_contact_port_get()?;
|
||||
+ let agent_contact_ip = cloudagent_contact_ip_get(&conf_name, &conf);
|
||||
+ let agent_contact_port =
|
||||
+ cloudagent_contact_port_get(&conf_name, &conf)?;
|
||||
let hash_alg = HashAlgorithm::try_from(
|
||||
- config_get("cloud_agent", "tpm_hash_alg")?.as_str(),
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "tpm_hash_alg")?
|
||||
+ .as_str(),
|
||||
)?;
|
||||
let enc_alg = EncryptionAlgorithm::try_from(
|
||||
- config_get("cloud_agent", "tpm_encryption_alg")?.as_str(),
|
||||
+ config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "tpm_encryption_alg",
|
||||
+ )?
|
||||
+ .as_str(),
|
||||
)?;
|
||||
let sign_alg = SignAlgorithm::try_from(
|
||||
- config_get("cloud_agent", "tpm_signing_alg")?.as_str(),
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "tpm_signing_alg")?
|
||||
+ .as_str(),
|
||||
)?;
|
||||
// There was a typo in Python Keylime and this accounts for having a version
|
||||
// of Keylime installed that still has this typo. TODO: Remove later
|
||||
let run_revocation = bool::from_str(
|
||||
- &config_get("cloud_agent", "listen_notifications")
|
||||
- .or_else(|_| {
|
||||
- config_get("cloud_agent", "listen_notfications")
|
||||
- })?
|
||||
- .to_lowercase(),
|
||||
- )?;
|
||||
- let revocation_cert = config_get("cloud_agent", "revocation_cert")?;
|
||||
- let revocation_ip = config_get("general", "receive_revocation_ip")?;
|
||||
- let revocation_port =
|
||||
- config_get("general", "receive_revocation_port")?;
|
||||
+ &config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "listen_notifications",
|
||||
+ )
|
||||
+ .or_else(|_| {
|
||||
+ config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "listen_notfications",
|
||||
+ )
|
||||
+ })?
|
||||
+ .to_lowercase(),
|
||||
+ )?;
|
||||
+ let revocation_cert =
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "revocation_cert")?;
|
||||
+ let revocation_ip = config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "general",
|
||||
+ "receive_revocation_ip",
|
||||
+ )?;
|
||||
+ let revocation_port = config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "general",
|
||||
+ "receive_revocation_port",
|
||||
+ )?;
|
||||
|
||||
- let secure_size = config_get("cloud_agent", "secure_size")?;
|
||||
- let payload_script = config_get("cloud_agent", "payload_script")?;
|
||||
+ let secure_size =
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "secure_size")?;
|
||||
+ let payload_script =
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "payload_script")?;
|
||||
let dec_payload_filename =
|
||||
- config_get("cloud_agent", "dec_payload_file")?;
|
||||
- let key_filename = config_get("cloud_agent", "enc_keyname")?;
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "dec_payload_file")?;
|
||||
+
|
||||
+ let key_filename =
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "enc_keyname")?;
|
||||
let extract_payload_zip = bool::from_str(
|
||||
- &config_get("cloud_agent", "extract_payload_zip")?.to_lowercase(),
|
||||
+ &config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "extract_payload_zip",
|
||||
+ )?
|
||||
+ .to_lowercase(),
|
||||
)?;
|
||||
|
||||
- let work_dir =
|
||||
- config_get_env("cloud_agent", "keylime_dir", "KEYLIME_DIR")
|
||||
- .or_else::<Error, _>(|_| Ok(String::from(WORK_DIR)))?;
|
||||
+
|
||||
+ let work_dir = config_get_env(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "keylime_dir",
|
||||
+ "KEYLIME_DIR",
|
||||
+ )
|
||||
+ .or_else::<Error, _>(|_| Ok(String::from(WORK_DIR)))?;
|
||||
|
||||
let tpm_data_path = PathBuf::from(&work_dir).join(TPM_DATA);
|
||||
let tpm_data = if tpm_data_path.exists() {
|
||||
@@ -302,20 +365,31 @@
|
||||
None
|
||||
};
|
||||
|
||||
- let mut keylime_ca_path = config_get("cloud_agent", "keylime_ca")?;
|
||||
+ let mut keylime_ca_path =
|
||||
+ config_get(&conf_name, &conf, "cloud_agent", "keylime_ca")?;
|
||||
if keylime_ca_path == "default" {
|
||||
keylime_ca_path = Path::new(&work_dir)
|
||||
.join(DEFAULT_CA_PATH)
|
||||
.display()
|
||||
.to_string();
|
||||
}
|
||||
- let revocation_actions =
|
||||
- config_get("cloud_agent", "revocation_actions")
|
||||
- .or_else::<Error, _>(|_| Ok(String::from(REV_ACTIONS)))?;
|
||||
- let revocation_actions_dir =
|
||||
- config_get("cloud_agent", "revocation_actions_dir")
|
||||
- .or_else::<Error, _>(|_| Ok(String::from(REV_ACTIONS_DIR)))?;
|
||||
+ let revocation_actions = config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "revocation_actions",
|
||||
+ )
|
||||
+ .or_else::<Error, _>(|_| Ok(String::from(REV_ACTIONS)))?;
|
||||
+ let revocation_actions_dir = config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "revocation_actions_dir",
|
||||
+ )
|
||||
+ .or_else::<Error, _>(|_| Ok(String::from(REV_ACTIONS_DIR)))?;
|
||||
let allow_payload_revocation_actions = match config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
"cloud_agent",
|
||||
"allow_payload_revocation_actions",
|
||||
) {
|
||||
@@ -323,7 +397,7 @@
|
||||
Err(_) => ALLOW_PAYLOAD_REV_ACTIONS,
|
||||
};
|
||||
let run_as = if permissions::get_euid() == 0 {
|
||||
- match config_get("cloud_agent", "run_as") {
|
||||
+ match config_get(&conf_name, &conf, "cloud_agent", "run_as") {
|
||||
Ok(user_group) => Some(user_group),
|
||||
Err(_) => {
|
||||
warn!("Cannot drop privileges since 'run_as' is empty or missing in 'cloud_agent' section of keylime.conf.");
|
||||
@@ -334,19 +408,27 @@
|
||||
None
|
||||
};
|
||||
|
||||
- let mtls_enabled =
|
||||
- match config_get("cloud_agent", "mtls_cert_enabled") {
|
||||
- Ok(enabled) => bool::from_str(&enabled.to_lowercase())
|
||||
- .or::<Error>(Ok(MTLS_ENABLED))?,
|
||||
- Err(_) => true,
|
||||
- };
|
||||
-
|
||||
- let enable_insecure_payload =
|
||||
- match config_get("cloud_agent", "enable_insecure_payload") {
|
||||
- Ok(allowed) => bool::from_str(&allowed.to_lowercase())
|
||||
- .or::<Error>(Ok(ALLOW_INSECURE_PAYLOAD))?,
|
||||
- Err(_) => false,
|
||||
- };
|
||||
+ let mtls_enabled = match config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "mtls_cert_enabled",
|
||||
+ ) {
|
||||
+ Ok(enabled) => bool::from_str(&enabled.to_lowercase())
|
||||
+ .or::<Error>(Ok(MTLS_ENABLED))?,
|
||||
+ Err(_) => true,
|
||||
+ };
|
||||
+
|
||||
+ let enable_insecure_payload = match config_get(
|
||||
+ &conf_name,
|
||||
+ &conf,
|
||||
+ "cloud_agent",
|
||||
+ "enable_insecure_payload",
|
||||
+ ) {
|
||||
+ Ok(allowed) => bool::from_str(&allowed.to_lowercase())
|
||||
+ .or::<Error>(Ok(ALLOW_INSECURE_PAYLOAD))?,
|
||||
+ Err(_) => false,
|
||||
+ };
|
||||
|
||||
Ok(KeylimeConfig {
|
||||
agent_ip,
|
||||
@@ -477,19 +559,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
-/// Returns revocation ip from keylime.conf if env var not present
|
||||
-fn revocation_ip_get() -> Result<String> {
|
||||
- config_get_env("general", "receive_revocation_ip", "REVOCATION_IP")
|
||||
-}
|
||||
-
|
||||
-/// Returns revocation port from keylime.conf if env var not present
|
||||
-fn revocation_port_get() -> Result<String> {
|
||||
- config_get_env("general", "receive_revocation_port", "REVOCATION_PORT")
|
||||
-}
|
||||
-
|
||||
/// Returns the contact ip for the agent if set
|
||||
-fn cloudagent_contact_ip_get() -> Option<String> {
|
||||
+fn cloudagent_contact_ip_get(conf_name: &str, conf: &Ini) -> Option<String> {
|
||||
match config_get_env(
|
||||
+ conf_name,
|
||||
+ conf,
|
||||
"cloud_agent",
|
||||
"agent_contact_ip",
|
||||
"KEYLIME_AGENT_CONTACT_IP",
|
||||
@@ -500,8 +574,13 @@
|
||||
}
|
||||
|
||||
/// Returns the contact ip for the agent if set
|
||||
-fn cloudagent_contact_port_get() -> Result<Option<u32>> {
|
||||
+fn cloudagent_contact_port_get(
|
||||
+ conf_name: &str,
|
||||
+ conf: &Ini,
|
||||
+) -> Result<Option<u32>> {
|
||||
match config_get_env(
|
||||
+ conf_name,
|
||||
+ conf,
|
||||
"cloud_agent",
|
||||
"agent_contact_port",
|
||||
"KEYLIME_AGENT_CONTACT_PORT",
|
||||
@@ -518,15 +597,18 @@
|
||||
}
|
||||
|
||||
/*
|
||||
- * Input: [section] and key
|
||||
+ * Input: conf_name, conf, [section] and key
|
||||
* Return: Returns the matched key
|
||||
*
|
||||
* Example call:
|
||||
- * let port = common::config_get("general","cloudagent_port");
|
||||
+ * let port = common::config_get(conf_file_name, file_Ini,"general","cloudagent_port");
|
||||
*/
|
||||
-fn config_get(section: &str, key: &str) -> Result<String> {
|
||||
- let conf_name = config_file_get();
|
||||
- let conf = Ini::load_from_file(&conf_name)?;
|
||||
+fn config_get(
|
||||
+ conf_name: &str,
|
||||
+ conf: &Ini,
|
||||
+ section: &str,
|
||||
+ key: &str,
|
||||
+) -> Result<String> {
|
||||
let section = match conf.section(Some(section.to_owned())) {
|
||||
Some(section) => section,
|
||||
None =>
|
||||
@@ -554,23 +636,29 @@
|
||||
}
|
||||
|
||||
/*
|
||||
- * Input: [section] and key and environment variable
|
||||
+ * Input: conf_name, conf,[section] and key and environment variable
|
||||
* Return: Returns the matched key
|
||||
*
|
||||
* Example call:
|
||||
- * let port = common::config_get_env("general","cloudagent_port", "CLOUDAGENT_PORT");
|
||||
+ * let port = common::config_get_env(conf_file_name, file_Ini, "general","cloudagent_port", "CLOUDAGENT_PORT");
|
||||
*/
|
||||
-fn config_get_env(section: &str, key: &str, env: &str) -> Result<String> {
|
||||
+fn config_get_env(
|
||||
+ conf_name: &str,
|
||||
+ conf: &Ini,
|
||||
+ section: &str,
|
||||
+ key: &str,
|
||||
+ env: &str,
|
||||
+) -> Result<String> {
|
||||
match env::var(env) {
|
||||
Ok(ip) => {
|
||||
// The variable length must be larger than 0 to accept
|
||||
if !ip.is_empty() {
|
||||
Ok(ip)
|
||||
} else {
|
||||
- config_get(section, key)
|
||||
+ config_get(conf_name, conf, section, key)
|
||||
}
|
||||
}
|
||||
- _ => config_get(section, key),
|
||||
+ _ => config_get(conf_name, conf, section, key),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,162 +0,0 @@
|
||||
From 4ec807b1bbcfaa67f85d0c2659b1f439c2f540b4 Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
Date: Fri, 24 Jun 2022 16:25:54 +0200
|
||||
Subject: [PATCH] permissions: Set supplementary groups when dropping
|
||||
privileges
|
||||
|
||||
This allows the agent to run with the user primary group and have the
|
||||
access given by the supplementary groups.
|
||||
|
||||
Fixes: #414
|
||||
|
||||
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
---
|
||||
src/permissions.rs | 70 ++++++++++++++++++++++++++++++++++------------
|
||||
1 file changed, 52 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/src/permissions.rs b/src/permissions.rs
|
||||
index 279a6dd..86e3fae 100644
|
||||
--- a/src/permissions.rs
|
||||
+++ b/src/permissions.rs
|
||||
@@ -2,7 +2,7 @@
|
||||
// Copyright 2021 Keylime Authors
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
-use libc::{gid_t, uid_t};
|
||||
+use libc::{c_char, c_int, gid_t, uid_t};
|
||||
use log::*;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::{
|
||||
@@ -13,10 +13,9 @@ use std::{
|
||||
ptr,
|
||||
};
|
||||
|
||||
-#[derive(Debug)]
|
||||
pub(crate) struct UserIds {
|
||||
- uid: uid_t,
|
||||
- gid: gid_t,
|
||||
+ passwd: libc::passwd,
|
||||
+ group: libc::group,
|
||||
}
|
||||
|
||||
pub(crate) fn get_gid() -> gid_t {
|
||||
@@ -47,14 +46,14 @@ impl TryFrom<&str> for UserIds {
|
||||
let group = parts[1];
|
||||
|
||||
// Get gid from group name
|
||||
- let gid = if let Ok(g_cstr) = CString::new(group.as_bytes()) {
|
||||
+ let grnam = if let Ok(g_cstr) = CString::new(group.as_bytes()) {
|
||||
let p = unsafe { libc::getgrnam(g_cstr.as_ptr()) };
|
||||
if p.is_null() {
|
||||
let e = io::Error::last_os_error();
|
||||
error!("Could not get group {}: {}", group, e);
|
||||
return Err(Error::Conversion(e.to_string()));
|
||||
}
|
||||
- unsafe { (*p).gr_gid }
|
||||
+ unsafe { (*p) }
|
||||
} else {
|
||||
return Err(Error::Conversion(format!(
|
||||
"Failed to convert {} to CString",
|
||||
@@ -63,14 +62,14 @@ impl TryFrom<&str> for UserIds {
|
||||
};
|
||||
|
||||
// Get uid from user name
|
||||
- let uid = if let Ok(u_cstr) = CString::new(user.as_bytes()) {
|
||||
+ let passwd = if let Ok(u_cstr) = CString::new(user.as_bytes()) {
|
||||
let p = unsafe { libc::getpwnam(u_cstr.as_ptr()) };
|
||||
if p.is_null() {
|
||||
let e = io::Error::last_os_error();
|
||||
error!("Could not get user {}: {}", user, e);
|
||||
return Err(Error::Conversion(e.to_string()));
|
||||
}
|
||||
- unsafe { (*p).pw_uid }
|
||||
+ unsafe { (*p) }
|
||||
} else {
|
||||
return Err(Error::Conversion(format!(
|
||||
"Failed to convert {} to CString",
|
||||
@@ -78,7 +77,10 @@ impl TryFrom<&str> for UserIds {
|
||||
)));
|
||||
};
|
||||
|
||||
- Ok(UserIds { uid, gid })
|
||||
+ Ok(UserIds {
|
||||
+ passwd,
|
||||
+ group: grnam,
|
||||
+ })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,22 +90,51 @@ impl TryFrom<&str> for UserIds {
|
||||
pub(crate) fn run_as(user_group: &str) -> Result<()> {
|
||||
let ids: UserIds = user_group.try_into()?;
|
||||
|
||||
- // Drop supplementary groups
|
||||
- if unsafe { libc::setgroups(0, ptr::null()) } != 0 {
|
||||
+ // Set gid
|
||||
+ if unsafe { libc::setgid(ids.group.gr_gid) } != 0 {
|
||||
let e = io::Error::last_os_error();
|
||||
- error!("Could not drop supplementary groups: {}", e);
|
||||
+ error!("Could not set group id: {}", e);
|
||||
return Err(Error::Permission);
|
||||
}
|
||||
|
||||
- // Set gid
|
||||
- if unsafe { libc::setgid(ids.gid) } != 0 {
|
||||
+ // Get list of supplementary groups
|
||||
+ let mut sup_groups: [gid_t; 32] = [0u32; 32];
|
||||
+ let mut ngroups: c_int = 32;
|
||||
+ if unsafe {
|
||||
+ libc::getgrouplist(
|
||||
+ ids.passwd.pw_name,
|
||||
+ ids.group.gr_gid,
|
||||
+ sup_groups.as_mut_ptr(),
|
||||
+ &mut ngroups,
|
||||
+ )
|
||||
+ } < 0
|
||||
+ {
|
||||
+ // Allocate a Vec and try again
|
||||
+ let mut sup_groups: Vec<gid_t> = Vec::with_capacity(ngroups as usize);
|
||||
+ if unsafe {
|
||||
+ libc::getgrouplist(
|
||||
+ ids.passwd.pw_name,
|
||||
+ ids.group.gr_gid,
|
||||
+ sup_groups.as_mut_ptr(),
|
||||
+ &mut ngroups,
|
||||
+ )
|
||||
+ } < 0
|
||||
+ {
|
||||
+ error!("Could not get list of supplementary groups");
|
||||
+ return Err(Error::Permission);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Set supplementary groups
|
||||
+ if unsafe { libc::setgroups(ngroups as usize, sup_groups.as_ptr()) } != 0
|
||||
+ {
|
||||
let e = io::Error::last_os_error();
|
||||
- error!("Could not set group id: {}", e);
|
||||
+ error!("Could not set supplementary groups: {}", e);
|
||||
return Err(Error::Permission);
|
||||
}
|
||||
|
||||
// Set uid
|
||||
- if unsafe { libc::setuid(ids.uid) } != 0 {
|
||||
+ if unsafe { libc::setuid(ids.passwd.pw_uid) } != 0 {
|
||||
let e = io::Error::last_os_error();
|
||||
error!("Could not set user id: {}", e);
|
||||
return Err(Error::Permission);
|
||||
@@ -126,9 +157,12 @@ pub(crate) fn chown(user_group: &str, path: &Path) -> Result<()> {
|
||||
return Err(Error::Permission);
|
||||
}
|
||||
|
||||
- // change directory owner to root
|
||||
+ // change directory owner
|
||||
let c_path = CString::new(path.as_os_str().as_bytes())?;
|
||||
- if unsafe { libc::chown(c_path.as_ptr(), ids.uid, ids.gid) } != 0 {
|
||||
+ if unsafe {
|
||||
+ libc::chown(c_path.as_ptr(), ids.passwd.pw_uid, ids.group.gr_gid)
|
||||
+ } != 0
|
||||
+ {
|
||||
error!("Failed to change file {} owner.", path.display());
|
||||
return Err(Error::Permission);
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
--- a/src/main.rs 2022-06-28 16:54:37.559307146 +0200
|
||||
+++ b/src/main.rs 2022-06-28 17:37:39.512350575 +0200
|
||||
@@ -512,7 +512,16 @@
|
||||
let ssl_context;
|
||||
if config.mtls_enabled {
|
||||
let keylime_ca_cert =
|
||||
- crypto::load_x509(Path::new(&config.keylime_ca_path))?;
|
||||
+ match crypto::load_x509(Path::new(&config.keylime_ca_path)) {
|
||||
+ Ok(t) => Ok(t),
|
||||
+ Err(e) => {
|
||||
+ error!(
|
||||
+ "Certificate not installed: {}",
|
||||
+ config.keylime_ca_path
|
||||
+ );
|
||||
+ Err(e)
|
||||
+ }
|
||||
+ }?;
|
||||
|
||||
cert = crypto::generate_x509(&nk_priv, &config.agent_uuid)?;
|
||||
mtls_cert = Some(&cert);
|
||||
4
sources
4
sources
@ -1,2 +1,2 @@
|
||||
SHA512 (rust-keylime-0.1.0~20220603gitaed51c7.tar.gz) = 0a045b0caa13a582a1270428edb49a7e20cc7df15b749458a9ddb2b84c05f240225d9e876a0cc082978dc5b52f7e0175cbbc3b937edd1ffed68e252be3ea17f8
|
||||
SHA512 (rust-keylime-0.1.0~20220603gitaed51c7-vendor.tar.xz) = 11bf0e27e5c94acddd04b9b17b2642f5a17a2ad13126075b93f964d07afec46fce2bf376f9bf74840a2c447b11b0e26a1ffe07c74a899685a67461c69254652e
|
||||
SHA512 (rust-keylime-0.1.0~20220805git0186093.tar.gz) = bd5fc911b022938896bb26f2500338c4cf0fc623ab471c3a1e8f846448d5d7b19c9ceb953c63bd306b88d0c52430737ff04650829a8a8a28697647c5dd856445
|
||||
SHA512 (rust-keylime-0.1.0~20220805git0186093-vendor.tar.xz) = e1b810b08ce14aae664efcace9a984f7c7999c878704d7e0c93ca500e6bdf638e00ecec5bc6708ff6d69296c42a0bb29c6511ce7fa3f60d41d05a14e73ed8332
|
||||
|
||||
Loading…
Reference in New Issue
Block a user