mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust: Add tool to manage UV-secrets
Add `pvsecret` a tool to create, add, list, and delete Ultravisor secrets. `pvsecret` uses the functionality from the pv-crate to provide an command line tool to manage the secrets. Add a new target group PV_TARGETS in rust/Makefile that additionally requires openssl and libcurl as pv with the feature "request" uses openssl and libcurl fearures. Acked-by: Jan Höppner <hoeppner@linux.ibm.com> Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com> [hoeppner@linux.ibm.com: Adapt man pages and help output] Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
c6f621d0dc
commit
dd82c26f87
@@ -9,6 +9,7 @@ Release history for s390-tools (MIT version)
|
||||
|
||||
Add new tools / libraries:
|
||||
- rust/pv: Library for pv tools written in rust
|
||||
- rust/pvsecret: Tool to manage UV-secrets
|
||||
|
||||
Changes of existing tools:
|
||||
- genprotimg: add support for add-secret requests
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
include ../common.mak
|
||||
SHELL := /bin/bash
|
||||
HAVE_CARGO ?= 1
|
||||
HAVE_OPENSSL ?= 1
|
||||
HAVE_LIBCURL ?= 1
|
||||
|
||||
INSTALL_TARGETS := skip-build
|
||||
BUILD_TARGETS := skip-build
|
||||
PV_BUILD_TARGETS := skip-pv-build
|
||||
CARGO_TARGETS :=
|
||||
PV_TARGETS :=
|
||||
CARGO_TEST_TARGETS :=
|
||||
|
||||
ifneq (${HAVE_CARGO},0)
|
||||
@@ -14,7 +18,17 @@ ifneq (${HAVE_CARGO},0)
|
||||
INSTALL_TARGETS := install-rust-tools install-man
|
||||
CARGO_TEST_TARGETS = $(addsuffix, _test, $(CARGO_TARGETS))
|
||||
|
||||
endif
|
||||
ifneq (${HAVE_OPENSSL},0)
|
||||
ifneq (${HAVE_LIBCURL},0)
|
||||
PV_TARGETS := pvsecret
|
||||
|
||||
PV_BUILD_TARGETS = $(PV_TARGETS)
|
||||
CARGO_TEST_TARGETS += $(addsuffix, _test, $(PV_TARGETS)) pv
|
||||
endif #LIBCURL
|
||||
endif #OPENSSL
|
||||
endif #CARGO
|
||||
|
||||
BUILD_TARGETS += $(PV_BUILD_TARGETS)
|
||||
|
||||
# build release targets by default
|
||||
ifeq ("${D}","0")
|
||||
@@ -35,9 +49,16 @@ $(CARGO_TEST_TARGETS): .check-cargo .no-cross-compile
|
||||
$(CARGO_TEST) --manifest-path=$@/Cargo.toml --all-features $(CARGOFLAGS)
|
||||
.PHONY: $(CARGO_TEST_TARGETS)
|
||||
|
||||
$(PV_TARGETS): .check-cargo .no-cross-compile .check-dep-pvtools
|
||||
$(CARGO_BUILD) --manifest-path=$@/Cargo.toml $(ALL_CARGOFLAGS)
|
||||
.PHONY: $(PV_TARGETS)
|
||||
|
||||
skip-build:
|
||||
echo " SKIP rust-tools due to unresolved dependencies"
|
||||
|
||||
skip-pv-build:
|
||||
echo " SKIP rust-pv-tools due to unresolved dependencies"
|
||||
|
||||
all: $(BUILD_TARGETS)
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
@@ -47,6 +68,8 @@ print-rust-targets:
|
||||
clean:
|
||||
$(foreach target,$(CARGO_TARGETS),\
|
||||
$(CARGO_CLEAN) --manifest-path=$(target)/Cargo.toml ${ALL_CARGOFLAGS} ;)
|
||||
$(foreach target,$(PV_TARGETS),\
|
||||
$(CARGO_CLEAN) --manifest-path=$(target)/Cargo.toml ${CARGOFLAGS} ;)
|
||||
$(RM) -- .check-dep-pvtools .detect-openssl.dep.c .check-cargo
|
||||
|
||||
rust-test: .check-cargo .no-cross-compile
|
||||
@@ -57,10 +80,14 @@ install-rust-tools: $(BUILD_TARGETS)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
||||
$(foreach target,$(CARGO_TARGETS),\
|
||||
$(INSTALL) $(target)/target/release/$(target) $(DESTDIR)$(USRBINDIR);)
|
||||
$(foreach target,$(PV_TARGETS),\
|
||||
$(INSTALL) $(target)/target/release/$(target) $(DESTDIR)$(USRBINDIR);)
|
||||
|
||||
install-man:
|
||||
$(foreach target,$(CARGO_TARGETS),\
|
||||
$(INSTALL) -m 644 $(target)/man/*.1 -t $(DESTDIR)$(MANDIR)/man1;)
|
||||
$(foreach target,$(PV_TARGETS),\
|
||||
$(INSTALL) -m 644 $(target)/man/*.1 -t $(DESTDIR)$(MANDIR)/man1;)
|
||||
|
||||
.PHONY: all install clean skip-build install-rust-tools print-rust-targets install-man rust-test
|
||||
|
||||
@@ -79,3 +106,27 @@ ifneq ($(HOST_ARCH), $(BUILD_ARCH))
|
||||
$(error Cross compiling is not supported for rust code. Specify HAVE_CARGO=0 to disable rust compilation)
|
||||
endif
|
||||
.PHONY: .no-cross-compile
|
||||
|
||||
.detect-openssl.dep.c:
|
||||
echo "#include <openssl/evp.h>" > $@
|
||||
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
|
||||
echo " #error openssl version 1.1.1 is required" >> $@
|
||||
echo "#endif" >> $@
|
||||
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||
echo " EVP_MD_CTX_free(ctx);" >> $@
|
||||
echo "}" >> $@
|
||||
|
||||
.check-dep-pvtools: .detect-openssl.dep.c
|
||||
$(call check_dep, \
|
||||
"$(BIN_PROGRAM)", \
|
||||
$^, \
|
||||
"openssl-devel / libssl-dev version >= 1.1.1", \
|
||||
"HAVE_OPENSSL=0", \
|
||||
"-I.")
|
||||
$(call check_dep, \
|
||||
"$(BIN_PROGRAM)", \
|
||||
"curl/curl.h", \
|
||||
"libcurl-devel", \
|
||||
"HAVE_LIBCURL=0")
|
||||
touch $@
|
||||
|
||||
1
rust/pvsecret/.gitignore
vendored
Normal file
1
rust/pvsecret/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!Cargo.lock
|
||||
728
rust/pvsecret/Cargo.lock
generated
Normal file
728
rust/pvsecret/Cargo.lock
generated
Normal file
@@ -0,0 +1,728 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is-terminal",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "curl"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22"
|
||||
dependencies = [
|
||||
"curl-sys",
|
||||
"libc",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"socket2",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.63+curl-8.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.146"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl_extensions"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pv"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"clap",
|
||||
"curl",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl_extensions",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pvsecret"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"log",
|
||||
"pv",
|
||||
"serde_yaml",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||
dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "utils"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.0",
|
||||
"windows_aarch64_msvc 0.48.0",
|
||||
"windows_i686_gnu 0.48.0",
|
||||
"windows_i686_msvc 0.48.0",
|
||||
"windows_x86_64_gnu 0.48.0",
|
||||
"windows_x86_64_gnullvm 0.48.0",
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
18
rust/pvsecret/Cargo.toml
Normal file
18
rust/pvsecret/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "pvsecret"
|
||||
version = "0.9.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1", features = ["std"] }
|
||||
clap = { version ="4", features = ["derive", "wrap_help"]}
|
||||
log = { version = "0.4", features = ["std", "release_max_level_debug"] }
|
||||
serde_yaml = "0.9"
|
||||
|
||||
pv = { path = "../pv", features = ["uvsecret", "request"] }
|
||||
utils = { path = "../utils" }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
panic = "abort" # release builds now do not clean up stack after panics. .1 Mb
|
||||
284
rust/pvsecret/README.md
Normal file
284
rust/pvsecret/README.md
Normal file
@@ -0,0 +1,284 @@
|
||||
<!--
|
||||
Copyright 2023 IBM Corp.
|
||||
s390-tools is free software; you can redistribute it and/or modify
|
||||
it under the terms of the MIT license. See LICENSE for details.
|
||||
-->
|
||||
# pvsecret
|
||||
## Description
|
||||
Use **pvsecret** to manage secrets for IBM Secure Execution guests. **pvsecret**
|
||||
can **create** add-secret requests on any architecture. On s390x systems, use
|
||||
**pvsecret** to **add** the secrets to the ultravisor secret store, **list** all
|
||||
secrets in the secret store, or lock the secret store to prevent any
|
||||
modifications in the future.
|
||||
|
||||
The ultravisor secret store stores secrets for the IBM Secure Execution guest.
|
||||
The secret store is cleared on guest reboot.
|
||||
|
||||
Create requests only on trusted systems that are not the IBM Secure Execution
|
||||
guest where you want to inject the secrets. This approach prevents the secrets
|
||||
from being in cleartext on the guest. For extra safety, do an attestation with
|
||||
**pvattest** of your guest beforehand, and include the configuration UID in the
|
||||
secret request using **--cuid**. Refer to **pvsecret-add**(1) for more
|
||||
information. For all certificates, revocation lists, and host-key documents,
|
||||
both the PEM and DER input formats are supported.
|
||||
|
||||
|
||||
## Synopsis
|
||||
`pvsecret [OPTIONS] <COMMAND>`
|
||||
## Commands Overview
|
||||
- **create**
|
||||
Create a new add-secret request
|
||||
- **add**
|
||||
Repeat an add-secret request (s390x only)
|
||||
- **lock**
|
||||
Lock the secret-store (s390x only)
|
||||
- **list**
|
||||
List all ultravisor secrets (s390x only)
|
||||
## Options
|
||||
|
||||
`-v`, `--verbose`
|
||||
<ul>
|
||||
Provide more detailed output
|
||||
</ul>
|
||||
|
||||
|
||||
`--version`
|
||||
<ul>
|
||||
Print version information and exit
|
||||
</ul>
|
||||
|
||||
|
||||
## pvsecret create
|
||||
### Description
|
||||
Create add-secret requests for IBM Secure Execution guests. Only create these
|
||||
requests in a trusted environment, such as your workstation. The **pvattest
|
||||
create** command creates a randomly generated key to protect the request. The
|
||||
generated requests can then be added on an IBM Secure Execution guest using
|
||||
**pvsecret add**. The guest can then use the secrets with the use case
|
||||
depending on the secret type.
|
||||
|
||||
Such a request is bound to a specific IBM Secure Execution image specified with
|
||||
**--hdr**. Optionally, the request can be bound to a specific instance when
|
||||
bound to the Configuration Unique ID from **pvattest** using **--cuid**
|
||||
|
||||
|
||||
### Synopsis
|
||||
`pvsecret create [OPTIONS] --host-key-document <FILE> --hdr <FILE> --output <FILE> <--no-verify|--cert <FILE>> <COMMAND>`
|
||||
### Commands Overview
|
||||
- **meta**
|
||||
Use a meta secret to carry flags to the ultravisor without having to provide
|
||||
an actual secret value. Meta secrets do not appear in the list of secrets
|
||||
- **association**
|
||||
Use an association secret to connect a trusted I/O device to a guest. The
|
||||
`pvapconfig` tool provides more information about association secrets
|
||||
|
||||
### Options
|
||||
|
||||
`-k`, `--host-key-document <FILE>`
|
||||
<ul>
|
||||
Use FILE as a host-key document. Can be specified multiple times and must be
|
||||
used at least once.
|
||||
</ul>
|
||||
|
||||
`--no-verify`
|
||||
<ul>
|
||||
Disable the host-key document verification. Does not require the host-key
|
||||
documents to be valid. Do not use for a production request unless you
|
||||
verified the host-key document beforehand.
|
||||
</ul>
|
||||
|
||||
`-C`, `--cert <FILE>`
|
||||
<ul>
|
||||
Use FILE as a certificate to verify the host key or keys. The certificates
|
||||
are used to establish a chain of trust for the verification of the host-key
|
||||
documents. Specify this option twice to specify the IBM Z signing key and
|
||||
the intermediate CA certificate (signed by the root CA).
|
||||
</ul>
|
||||
|
||||
`--crl <FILE>`
|
||||
<ul>
|
||||
Use FILE as a certificate revocation list. The list is used to check whether
|
||||
a certificate of the chain of trust is revoked. Specify this option multiple
|
||||
times to use multiple CRLs.
|
||||
</ul>
|
||||
|
||||
`--offline`
|
||||
<ul>
|
||||
Make no attempt to download CRLs
|
||||
</ul>
|
||||
|
||||
`--root-ca <ROOT_CA>`
|
||||
<ul>
|
||||
Use FILE as the root-CA certificate for the verification. If omitted, the
|
||||
system-wide root CAs installed on the system are used. Use this only if you
|
||||
trust the specified certificate.
|
||||
</ul>
|
||||
|
||||
`--hdr <FILE>`
|
||||
<ul>
|
||||
Specifies the header of the guest image. Can be an IBM Secure Execution
|
||||
image created by genprotimg or an extracted IBM Secure Execution header. The
|
||||
header must start at a page boundary.
|
||||
</ul>
|
||||
|
||||
`-f`, `--force`
|
||||
<ul>
|
||||
Force the generation of add-secret requests on IBM Secure Execution guests.
|
||||
If the program detects that it is running on an IBM Secure Execution guest,
|
||||
it denies the generation of add-secret requests. The force flag overwrites
|
||||
this behavior.
|
||||
</ul>
|
||||
|
||||
`-o`, `--output <FILE>`
|
||||
<ul>
|
||||
Write the generated request to FILE
|
||||
</ul>
|
||||
|
||||
`--extension-secret <FILE>`
|
||||
<ul>
|
||||
Use the content of FILE as an extension secret. The file must be exactly 32
|
||||
bytes long. If this request is the first, all subsequent requests must have
|
||||
the same extension secret. Only makes sense if bit 1 of the secret control
|
||||
flags of the IBM Secure Execution header is 0. Otherwise the ultravisor
|
||||
rejects the request.
|
||||
</ul>
|
||||
|
||||
`--cck <FILE>`
|
||||
<ul>
|
||||
Use the content of FILE as the customer-communication key (CCK) to derive
|
||||
the extension secret. The file must contain exactly 32 bytes of data. If the
|
||||
target guest was started with bit 1 of the secret control flag set, the
|
||||
ultravisor also derives the secret from the CCK. Otherwise, the ultravisor
|
||||
interprets the extension secret as a normal one. This still works if you
|
||||
use the same CCK for all requests.
|
||||
</ul>
|
||||
|
||||
|
||||
`--cuid-hex <HEXSTRING>`
|
||||
<ul>
|
||||
Use HEXSTRING as the Configuration Unique ID. Must be a hex 128-bit unsigned
|
||||
big endian number string. Leading zeros must be provided. If specified, the
|
||||
value must match with the Config-UID from the attestation result of that
|
||||
guest. If not specified, the CUID will be ignored by the ultravisor during
|
||||
the verification of the request.
|
||||
</ul>
|
||||
|
||||
`--cuid <FILE>`
|
||||
<ul>
|
||||
Use the content of FILE as the Configuration Unique ID. The file must
|
||||
contain exactly 128 bit of data, a hex string, or a yaml with a `cuid`
|
||||
entry. If specified, the value must match the Config-UID from the
|
||||
attestation result of that guest. If not specified, the CUID will be ignored
|
||||
by the Ultravisor during the verification of the request.
|
||||
</ul>
|
||||
|
||||
`--flags <FLAGS>`
|
||||
<ul>
|
||||
Flags for the add-secret request.
|
||||
|
||||
Possible values:
|
||||
- disable-dump: Disables host-initiated dumping for the target guest
|
||||
instance
|
||||
</ul>
|
||||
|
||||
|
||||
### pvsecret create meta
|
||||
#### Description
|
||||
Use a meta secret to carry flags to the ultravisor without having to provide an
|
||||
actual secret value. Meta secrets do not appear in the list of secrets.
|
||||
|
||||
|
||||
#### Synopsis
|
||||
`pvsecret create meta`
|
||||
|
||||
### pvsecret create association
|
||||
#### Description
|
||||
Use an association secret to connect a trusted I/O device to a guest. The
|
||||
`pvapconfig` tool provides more information about association secrets.
|
||||
|
||||
#### Synopsis
|
||||
`pvsecret create association [OPTIONS] <NAME>`
|
||||
#### Arguments
|
||||
|
||||
`<NAME>`
|
||||
<ul>
|
||||
String to identify the new secret. The actual secret is set with
|
||||
--input-secret. The name is saved in `NAME.yaml` with white-spaces
|
||||
mapped to `_`.
|
||||
</ul>
|
||||
|
||||
|
||||
#### Options
|
||||
|
||||
`--stdout`
|
||||
<ul>
|
||||
Print the hashed name to stdout. The hashed name will not be written to
|
||||
`NAME.yaml`
|
||||
</ul>
|
||||
|
||||
|
||||
`--input-secret <FILE>`
|
||||
<ul>
|
||||
Path from which to read the plaintext secret. Uses a random secret if not
|
||||
specified.
|
||||
</ul>
|
||||
|
||||
|
||||
`--output-secret <FILE>`
|
||||
<ul>
|
||||
Save the generated secret as plaintext in FILE. The generated secret can be
|
||||
used to generate add-secret requests for a different guest with the same
|
||||
secret using --input-secret. Destroy the secret when it is not used
|
||||
anymore.
|
||||
</ul>
|
||||
|
||||
|
||||
## pvsecret add
|
||||
### Description
|
||||
Perform an add-secret request using a previously generated add-secret request.
|
||||
Only available on s390x.
|
||||
|
||||
|
||||
### Synopsis
|
||||
`pvsecret add <FILE>`
|
||||
### Arguments
|
||||
|
||||
`<FILE>`
|
||||
<ul>
|
||||
Specify the request to be sent
|
||||
</ul>
|
||||
|
||||
|
||||
## pvsecret lock
|
||||
### Description
|
||||
Lock the secret store (s390x only). After this command executed successfully,
|
||||
all add-secret requests will fail. Only available on s390x.
|
||||
|
||||
|
||||
### Synopsis
|
||||
`pvsecret lock`
|
||||
|
||||
## pvsecret list
|
||||
### Description
|
||||
Lists the IDs of all non-null secrets currently stored in the ultravisor for the
|
||||
currently running IBM Secure Execution guest. Only available on s390x.
|
||||
|
||||
### Synopsis
|
||||
`pvsecret list [OPTIONS] [FILE]`
|
||||
### Arguments
|
||||
|
||||
`<FILE>`
|
||||
<ul>
|
||||
Store the result in FILE. Default value: '-'
|
||||
</ul>
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
`--format <FORMAT>`
|
||||
Define the output format of the list. Default value: 'human'
|
||||
|
||||
Possible values:
|
||||
- human: Human-focused, non-parsable output format
|
||||
- yaml: Use yaml format
|
||||
- bin: Use the format the ultravisor uses to pass the list
|
||||
33
rust/pvsecret/man/pvsecret-add.1
Normal file
33
rust/pvsecret/man/pvsecret-add.1
Normal file
@@ -0,0 +1,33 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret-add 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret add\fP - Repeat an add-secret request (s390x only)
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret add <FILE>
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Perform an add-secret request using a previously generated add-secret request.
|
||||
Only available on s390x.
|
||||
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
<FILE>
|
||||
.RS 4
|
||||
Specify the request to be sent.
|
||||
.RE
|
||||
.RE
|
||||
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret\fR(1)
|
||||
56
rust/pvsecret/man/pvsecret-create-association.1
Normal file
56
rust/pvsecret/man/pvsecret-create-association.1
Normal file
@@ -0,0 +1,56 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret-create-association 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret create association\fP - Use an association secret to connect an I/O device to a guest
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret create association [OPTIONS] <NAME>
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Use an association secret to connect a trusted I/O device to a guest. The
|
||||
`pvapconfig` tool provides more information about association secrets.
|
||||
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
<NAME>
|
||||
.RS 4
|
||||
String to identify the new secret. The actual secret is set with
|
||||
\fB--input-secret\fR. The name is saved in `NAME.yaml` with white-spaces mapped
|
||||
to `_`.
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.PP
|
||||
\-\-stdout
|
||||
.RS 4
|
||||
Print the hashed name to stdout. The hashed name is not written to `NAME.yaml`
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-input-secret <FILE>
|
||||
.RS 4
|
||||
Path from which to read the plaintext secret. Uses a random secret if not
|
||||
specified.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-output-secret <FILE>
|
||||
.RS 4
|
||||
Save the generated secret as plaintext in FILE. The generated secret can be used
|
||||
to generate add-secret requests for a different guest with the same secret using
|
||||
\fB--input-secret\fR. Destroy the secret when it is not used anymore.
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret\fR(1) \fBpvsecret-create\fR(1)
|
||||
24
rust/pvsecret/man/pvsecret-create-meta.1
Normal file
24
rust/pvsecret/man/pvsecret-create-meta.1
Normal file
@@ -0,0 +1,24 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret-create-meta 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret create meta\fP - Use a meta secret to carry flags to the ultravisor
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret create meta
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Use a meta secret to carry flags to the ultravisor without having to provide an
|
||||
actual secret value. Meta secrets do not appear in the list of secrets.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret\fR(1) \fBpvsecret-create\fR(1)
|
||||
154
rust/pvsecret/man/pvsecret-create.1
Normal file
154
rust/pvsecret/man/pvsecret-create.1
Normal file
@@ -0,0 +1,154 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret-create 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret create\fP - Create a new add-secret request
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret create [OPTIONS] --host-key-document <FILE> --hdr <FILE> --output <FILE> <--no-verify|--cert <FILE>> <COMMAND>
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Create add-secret requests for IBM Secure Execution guests. Only create these
|
||||
requests in a trusted environment, such as your workstation. The \fBpvattest
|
||||
create\fR command creates a randomly generated key to protect the request. The
|
||||
generated requests can then be added on an IBM Secure Execution guest using
|
||||
\fBpvsecret add\fR. The guest can then use the secrets with the use case
|
||||
depending on the secret type.
|
||||
|
||||
Such a request is bound to a specific IBM Secure Execution image specified with
|
||||
\fB--hdr\fR. Optionally, the request can be bound to a specific instance when
|
||||
bound to the Configuration Unique ID from \fBpvattest\fR using \fB--cuid\fR
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\-k, \-\-host-key-document <FILE>
|
||||
.RS 4
|
||||
Use FILE as a host-key document. Can be specified multiple times and must be
|
||||
used at least once.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-no-verify
|
||||
.RS 4
|
||||
Disable the host-key document verification. Does not require the host-key
|
||||
documents to be valid. Do not use for a production request unless you verified
|
||||
the host-key document beforehand.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-C, \-\-cert <FILE>
|
||||
.RS 4
|
||||
Use FILE as a certificate to verify the host key or keys. The certificates are
|
||||
used to establish a chain of trust for the verification of the host-key
|
||||
documents. Specify this option twice to specify the IBM Z signing key and the
|
||||
intermediate CA certificate (signed by the root CA).
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-crl <FILE>
|
||||
.RS 4
|
||||
Use FILE as a certificate revocation list. The list is used to check whether a
|
||||
certificate of the chain of trust is revoked. Specify this option multiple times
|
||||
to use multiple CRLs.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-offline
|
||||
.RS 4
|
||||
Make no attempt to download CRLs
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-root-ca <ROOT_CA>
|
||||
.RS 4
|
||||
Use FILE as the root-CA certificate for the verification. If omitted, the
|
||||
system-wide root CAs installed on the system are used. Use this only if you
|
||||
trust the specified certificate.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-hdr <FILE>
|
||||
.RS 4
|
||||
Specifies the header of the guest image. Can be an IBM Secure Execution image
|
||||
created by genprotimg or an extracted IBM Secure Execution header. The header
|
||||
must start at a page boundary.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-f, \-\-force
|
||||
.RS 4
|
||||
Force the generation of add-secret requests on IBM Secure Execution guests. If
|
||||
the program detects that it is running on an IBM Secure Execution guest, it
|
||||
denies the generation of add-secret requests. The force flag overwrites this
|
||||
behavior.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-o, \-\-output <FILE>
|
||||
.RS 4
|
||||
Write the generated request to FILE
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-extension-secret <FILE>
|
||||
.RS 4
|
||||
Use the content of FILE as an extension secret. The file must be exactly 32
|
||||
bytes long. If this request is the first, all subsequent requests must have the
|
||||
same extension secret. Only makes sense if bit 1 of the secret control flags of
|
||||
the IBM Secure Execution header is 0. Otherwise the ultravisor rejects the
|
||||
request.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-cck <FILE>
|
||||
.RS 4
|
||||
Use the content of FILE as the customer-communication key (CCK) to derive the
|
||||
extension secret. The file must contain exactly 32 bytes of data. If the target
|
||||
guest was started with bit 1 of the secret control flag set, the ultravisor also
|
||||
derives the secret from the CCK. Otherwise, the ultravisor interprets the
|
||||
extension secret as a normal one. This still works if you use the same CCK for
|
||||
all requests.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-cuid-hex <HEXSTRING>
|
||||
.RS 4
|
||||
Use HEXSTRING as the Configuration Unique ID. Must be a hex 128-bit unsigned
|
||||
big endian number string. Leading zeros must be provided. If specified, the
|
||||
value must match with the Config-UID from the attestation result of that guest.
|
||||
If not specified, the CUID will be ignored by the ultravisor during the
|
||||
verification of the request.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-cuid <FILE>
|
||||
.RS 4
|
||||
Use the content of FILE as the Configuration Unique ID. The file must contain
|
||||
exactly 128 bit of data, a hex string, or a yaml with a `cuid` entry. If
|
||||
specified, the value must match the Config-UID from the attestation result of
|
||||
that guest. If not specified, the CUID will be ignored by the Ultravisor during
|
||||
the verification of the request.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-flags <FLAGS>
|
||||
.RS 4
|
||||
Flags for the add-secret request.
|
||||
|
||||
Possible values:
|
||||
.RS 4
|
||||
- \fBdisable-dump\fP: Disables host-initiated dumping for the target guest instance.
|
||||
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret\fR(1) \fBpvsecret-create-meta\fR(1) \fBpvsecret-create-association\fR(1)
|
||||
47
rust/pvsecret/man/pvsecret-list.1
Normal file
47
rust/pvsecret/man/pvsecret-list.1
Normal file
@@ -0,0 +1,47 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret-list 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret list\fP - List all ultravisor secrets (s390x only)
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret list [OPTIONS] [FILE]
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Lists the IDs of all non-null secrets currently stored in the ultravisor for the
|
||||
currently running IBM Secure Execution guest. Only available on s390x.
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
<FILE>
|
||||
.RS 4
|
||||
Store the result in FILE. Default value: '-'
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.PP
|
||||
\-\-format <FORMAT>
|
||||
.RS 4
|
||||
Define the output format of the list. Default value: 'human'
|
||||
|
||||
Possible values:
|
||||
.RS 4
|
||||
- \fBhuman\fP: Human-focused, non-parsable output format
|
||||
|
||||
- \fByaml\fP: Use yaml format
|
||||
|
||||
- \fBbin\fP: Use the format the ultravisor uses to pass the list
|
||||
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret\fR(1)
|
||||
26
rust/pvsecret/man/pvsecret-lock.1
Normal file
26
rust/pvsecret/man/pvsecret-lock.1
Normal file
@@ -0,0 +1,26 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret-lock 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret lock\fP - Lock the secret-store (s390x only)
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret lock
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Lock the secret store (s390x only). After this command executed successfully,
|
||||
all add-secret requests will fail. Only available on s390x.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret\fR(1)
|
||||
25
rust/pvsecret/man/pvsecret-version.1
Normal file
25
rust/pvsecret/man/pvsecret-version.1
Normal file
@@ -0,0 +1,25 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret-version 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret version\fP- Print version information and exit
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret version
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Print version information and exit
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret\fR(1)
|
||||
103
rust/pvsecret/man/pvsecret.1
Normal file
103
rust/pvsecret/man/pvsecret.1
Normal file
@@ -0,0 +1,103 @@
|
||||
.\" Copyright 2023 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
|
||||
.TH pvsecret 1 "2023-07-28" "s390-tools" "UV-Secret Manual"
|
||||
.nh
|
||||
.ad l
|
||||
.SH NAME
|
||||
\fBpvsecret\fP - Manage secrets for IBM Secure Execution guests
|
||||
\fB
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.fam C
|
||||
pvsecret [OPTIONS] <COMMAND>
|
||||
.fam C
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Use \fBpvsecret\fR to manage secrets for IBM Secure Execution guests.
|
||||
\fBpvsecret\fR can \fIcreate\fR add-secret requests on any architecture. On
|
||||
s390x systems, use \fBpvsecret\fR to \fIadd\fR the secrets to the ultravisor
|
||||
secret store, \fIlist\fR all secrets in the secret store, or \fIlock\fR the
|
||||
secret store to prevent any modifications in the future.
|
||||
|
||||
The ultravisor secret store stores secrets for the IBM Secure Execution guest.
|
||||
The secret store is cleared on guest reboot.
|
||||
|
||||
Create requests only on trusted systems that are not the IBM Secure Execution
|
||||
guest where you want to inject the secrets. This approach prevents the secrets
|
||||
from being in cleartext on the guest. For extra safety, do an attestation with
|
||||
\fBpvattest\fR of your guest beforehand, and include the configuration UID in
|
||||
the secret request using \fB--cuid\fR. Refer to \fBpvsecret-add\fR(1) for more
|
||||
information. For all certificates, revocation lists, and host-key documents,
|
||||
both the PEM and DER input formats are supported.
|
||||
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\-v, \-\-verbose
|
||||
.RS 4
|
||||
Provide more detailed output.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\-\-version
|
||||
.RS 4
|
||||
Print version information and exit.
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Create the add-secret request on a trusted system. The program generates three
|
||||
files. \fFaddsecreq.bin\fP contains the add-secret request. \fFTEST.yaml\fP
|
||||
contains the non-confidential information about the generated secret. It
|
||||
contains the name and ID of the secret. \fFTEST\fP contains the plaintext secret
|
||||
that is encrypted in the request. It can be used to generate add-secret requests
|
||||
for a different guest with the same secret. Destroy the secret when it is not
|
||||
used anymore.
|
||||
.PP
|
||||
.nf
|
||||
.fam C
|
||||
trusted:~$ pvsecret create -k hkd.crt --cert CA.crt --cert ibmsk.crt --hdr pvimage -o addsecreq.bin association EXAMPLE
|
||||
Successfully generated the request
|
||||
Successfully wrote association info to 'EXAMPLE.yaml'
|
||||
Successfully wrote generated association secret to 'EXAMPLE'
|
||||
.fam T
|
||||
.fi
|
||||
On the SE-guest, \fIadd\fP the secret from request to the secret store.
|
||||
.PP
|
||||
.nf
|
||||
.fam C
|
||||
seguest:~$ pvsecret add addsecreq.bin
|
||||
Successfully added the secret
|
||||
|
||||
.fam T
|
||||
.fi
|
||||
On the SE-guest, \fIlist\fP the secrets currently stored.
|
||||
.PP
|
||||
.nf
|
||||
.fam C
|
||||
seguest:~$ pvsecret list
|
||||
Total number of secrets: 1
|
||||
|
||||
0 Association:
|
||||
94ee059335e587e501cc4bf90613e0814f00a7b08bc7c648fd865a2af6a22cc2
|
||||
.fam T
|
||||
.fi
|
||||
|
||||
On the SE-guest, \fIlock\fP the secret store.
|
||||
.PP
|
||||
.nf
|
||||
.fam C
|
||||
seguest:~$ pvsecret lock
|
||||
Successfully locked secret store
|
||||
seguest:~$ pvsecret add addsecreq.bin
|
||||
error: Ultravisor: 'secret store locked' (0x0102)
|
||||
|
||||
|
||||
.fam T
|
||||
.fi
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBpvsecret-create\fR(1) \fBpvsecret-add\fR(1) \fBpvsecret-lock\fR(1) \fBpvsecret-list\fR(1) \fBpvsecret-version\fR(1)
|
||||
322
rust/pvsecret/src/cli.rs
Normal file
322
rust/pvsecret/src/cli.rs
Normal file
@@ -0,0 +1,322 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use clap::{ArgGroup, Args, CommandFactory, Parser, Subcommand, ValueEnum, ValueHint};
|
||||
use pv::misc::CertificateOptions;
|
||||
#[cfg(target_arch = "s390x")]
|
||||
use pv::misc::STDOUT;
|
||||
|
||||
/// Manage secrets for IBM Secure Execution guests.
|
||||
///
|
||||
/// Use to create and send add-secret requests, list the added secrets and lock the Secret Store.
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct CliOptions {
|
||||
/// Provide more detailed output.
|
||||
#[arg(short='v', long, action = clap::ArgAction::Count, short_alias('V'))]
|
||||
pub verbose: u8,
|
||||
|
||||
/// Print version information and exit.
|
||||
#[arg(long)]
|
||||
pub version: bool,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub cmd: Command,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
|
||||
pub enum CreateSecretFlags {
|
||||
/// Disables host-initiated dumping for the target guest instance.
|
||||
DisableDump,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
#[command(group(ArgGroup::new("as-ext").args(["cck", "extension_secret"])),)]
|
||||
pub struct CreateSecretOpt {
|
||||
#[command(flatten)]
|
||||
pub certificate_args: CertificateOptions,
|
||||
|
||||
/// Specifies the header of the guest image.
|
||||
///
|
||||
/// Can be an IBM Secure Execution image created by genprotimg or an extracted IBM Secure
|
||||
/// Execution header. The header must start at a page boundary.
|
||||
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath)]
|
||||
pub hdr: String,
|
||||
|
||||
/// Force the generation of add-secret requests on IBM Secure Execution guests.
|
||||
///
|
||||
/// If the program detects that it is running on an IBM Secure Execution guest, it denies the
|
||||
/// generation of add-secret requests. The force flag overwrites this behavior.
|
||||
#[arg(short, long)]
|
||||
pub force: bool,
|
||||
|
||||
/// Write the generated request to FILE.
|
||||
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
||||
pub output: String,
|
||||
|
||||
/// Use the content of FILE as an extension secret.
|
||||
///
|
||||
/// The file must be exactly 32 bytes long. If this request is the first, all subsequent
|
||||
/// requests must have the same extension secret. Only makes sense if bit 1 of the secret
|
||||
/// control flags of the IBM Secure Execution header is
|
||||
/// 0. Otherwise the ultravisor rejects the request.
|
||||
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
||||
pub extension_secret: Option<String>,
|
||||
|
||||
/// Use the content of FILE as the customer-communication key (CCK) to derive the extension
|
||||
/// secret.
|
||||
///
|
||||
/// The file must contain exactly 32 bytes of data. If the target guest was started
|
||||
/// with bit 1 of the secret control flag set, the ultravisor also derives the secret from the
|
||||
/// CCK. Otherwise, the ultravisor interprets the extension secret as a normal one. This still
|
||||
/// works if you use the same CCK for all requests.
|
||||
#[arg(long, value_name = "FILE")]
|
||||
pub cck: Option<String>,
|
||||
|
||||
/// Use HEXSTRING as the Configuration Unique ID.
|
||||
///
|
||||
/// Must be a hex 128-bit unsigned big endian number string. Leading zeros must be provided. If
|
||||
/// specified, the value must match with the Config-UID from the attestation result of that
|
||||
/// guest. If not specified, the CUID will be ignored by the ultravisor during the
|
||||
/// verification of the request.
|
||||
#[arg(long, value_name = "HEXSTRING")]
|
||||
pub cuid_hex: Option<String>,
|
||||
|
||||
/// Use the content of FILE as the Configuration Unique ID.
|
||||
///
|
||||
/// The file must contain exactly 128 bit of data, a hex string, or a yaml with a `cuid` entry.
|
||||
/// If specified, the value must match the Config-UID from the attestation result of that
|
||||
/// guest. If not specified, the CUID will be ignored by the Ultravisor during the verification
|
||||
/// of the request.
|
||||
#[arg(long, value_name = "FILE", conflicts_with("cuid_hex"), value_hint = ValueHint::FilePath,)]
|
||||
pub cuid: Option<String>,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub secret: AddSecretType,
|
||||
|
||||
// FLAGS
|
||||
// each flag must conflict with `flags`
|
||||
// `flags` is hidden in the help menu
|
||||
/// Manually set the Add Secret Request flags.
|
||||
///
|
||||
/// No validity checks made. Hidden in user documentation.
|
||||
#[arg(long, hide(true))]
|
||||
pub pcf: Option<String>,
|
||||
|
||||
/// Flags for the add-secret request.
|
||||
#[arg(
|
||||
long,
|
||||
conflicts_with("pcf"),
|
||||
value_enum,
|
||||
value_parser,
|
||||
use_value_delimiter = true,
|
||||
value_delimiter = ','
|
||||
)]
|
||||
pub flags: Vec<CreateSecretFlags>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum AddSecretType {
|
||||
/// Use a meta secret to carry flags to the ultravisor without having to provide an actual
|
||||
/// secret value. Meta secrets do not appear in the list of secrets.
|
||||
Meta,
|
||||
|
||||
/// Use an association secret to connect a trusted I/O device to a guest. The `pvapconfig` tool
|
||||
/// provides more information about association secrets.
|
||||
Association {
|
||||
/// String to identify the new secret.
|
||||
///
|
||||
/// The actual secret is set with --input-secret. The name is saved in `NAME.yaml` with
|
||||
/// white-spaces mapped to `_`.
|
||||
name: String,
|
||||
|
||||
///Print the hashed name to stdout.
|
||||
///
|
||||
///The hashed name will not be written to `NAME.yaml`
|
||||
#[arg(long)]
|
||||
stdout: bool,
|
||||
|
||||
/// Path from which to read the plaintext secret. Uses a random secret if not specified.
|
||||
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath, conflicts_with("output_secret"))]
|
||||
input_secret: Option<String>,
|
||||
|
||||
/// Save the generated secret as plaintext in FILE.
|
||||
///
|
||||
/// The generated secret can be used to generate add-secret requests for a different guest
|
||||
/// with the same secret using --input-secret. Destroy the secret when it is not used
|
||||
/// anymore.
|
||||
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
||||
output_secret: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
// all members s390x only
|
||||
#[derive(Args, Debug)]
|
||||
pub struct AddSecretOpt {
|
||||
/// Specify the request to be sent.
|
||||
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub input: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)]
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub enum ListSecretOutputType {
|
||||
/// Human-focused, non-parsable output format
|
||||
#[default]
|
||||
Human,
|
||||
/// Use yaml format.
|
||||
Yaml,
|
||||
/// Use the format the ultravisor uses to pass the list.
|
||||
Bin,
|
||||
}
|
||||
|
||||
// all members s390x only
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ListSecretOpt {
|
||||
/// Store the result in FILE
|
||||
#[arg(value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath,)]
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub output: String,
|
||||
|
||||
/// Define the output format of the list.
|
||||
#[arg(long, value_enum, default_value_t)]
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub format: ListSecretOutputType,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum Command {
|
||||
/// Create a new add-secret request.
|
||||
///
|
||||
/// Create add-secret requests for IBM Secure Execution guests. Only create these requests in a
|
||||
/// trusted environment, such as your workstation. The `pvattest create` command creates a
|
||||
/// randomly generated key to protect the request. The generated requests can then be added on
|
||||
/// an IBM Secure Execution guest using `pvsecret add`. The guest can then use the secrets with
|
||||
/// the use case depending on the secret type.
|
||||
Create(Box<CreateSecretOpt>),
|
||||
|
||||
/// Repeat an add-secret request (s390x only).
|
||||
///
|
||||
/// Perform an add-secret request using a previously generated add-secret request. Only
|
||||
/// available on s390x.
|
||||
Add(AddSecretOpt),
|
||||
|
||||
/// Lock the secret-store (s390x only).
|
||||
///
|
||||
/// Lock the secret store (s390x only). After this command executed successfully, all
|
||||
/// add-secret requests will fail. Only available on s390x.
|
||||
Lock,
|
||||
|
||||
/// List all ultravisor secrets (s390x only).
|
||||
///
|
||||
/// Lists the IDs of all non-null secrets currently stored in the ultravisor for the currently
|
||||
/// running IBM Secure Execution guest. Only available on s390x.
|
||||
List(ListSecretOpt),
|
||||
|
||||
/// Print version information and exit.
|
||||
#[command(aliases(["--version"]), hide(true))]
|
||||
Version,
|
||||
}
|
||||
|
||||
/// Additional checks to assure, option integrity
|
||||
pub fn validate_cli(cli: &CliOptions) -> Result<(), clap::Error> {
|
||||
if let Command::Create(opt) = &cli.cmd {
|
||||
if let AddSecretType::Association {
|
||||
name,
|
||||
stdout,
|
||||
input_secret: _,
|
||||
output_secret: secret_out,
|
||||
} = &opt.secret
|
||||
{
|
||||
if *stdout {
|
||||
return Ok(());
|
||||
}
|
||||
if secret_out == &Some(format!("{name}.yaml")) {
|
||||
return Err(CliOptions::command().error(
|
||||
clap::error::ErrorKind::ValueValidation,
|
||||
format!("Secret output file and the secret name '{name}.yaml' are the same."),
|
||||
));
|
||||
}
|
||||
if format!("{name}.yaml") == opt.output {
|
||||
return Err(CliOptions::command().error(
|
||||
clap::error::ErrorKind::ValueValidation,
|
||||
format!(
|
||||
"output file and the secret name '{}' are the same.",
|
||||
&opt.output
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn cli_args() {
|
||||
//Verify only that some arguments are optional, we do not want to test clap, only the
|
||||
//configuration
|
||||
let valid_args = [
|
||||
vec!["pvsecret", "lock"],
|
||||
vec!["pvsecret", "version"],
|
||||
vec!["pvsecret", "list"],
|
||||
#[cfg(target_arch = "s390x")]
|
||||
vec!["pvsecret", "add", "abc"],
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
vec!["pvsecret", "add"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "meta"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "association", "name" ],
|
||||
// verify that arguments stay backwards compatible
|
||||
vec!["pvsecret", "create", "-k", "abc,cdef", "--hdr", "abc", "-o", "abc", "-C", "uuu,ggg", "--crl", "yyy,hhh", "--root-ca", "tttt",
|
||||
"--extension-secret", "fff", "--cuid", "cuid", "--flags", "disable-dump", "meta"],
|
||||
vec!["pvsecret", "create", "--host-key-document", "abc", "-k", "y", "--hdr", "abc", "-o", "abc", "--cert", "uuu", "--crl", "yyy",
|
||||
"--root-ca", "tttt", "--cck", "cck", "--cuid-hex", "0x11223344556677889900aabbccddeeff", "--pcf", "0x123", "association", "name", "--stdout",
|
||||
"--output-secret", "secret"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "association", "name", "--output-secret", "secret"],
|
||||
#[cfg(target_arch = "s390x")]
|
||||
vec!["pvsecret", "list", "--format", "human"],
|
||||
#[cfg(target_arch = "s390x")]
|
||||
vec!["pvsecret", "list", "--format", "yaml"],
|
||||
#[cfg(target_arch = "s390x")]
|
||||
vec!["pvsecret", "list", "--format", "bin"],
|
||||
];
|
||||
// Test for the minimal amount of flags to yield an invalid combination
|
||||
let invalid_args = [
|
||||
vec!["pvsecret"],
|
||||
vec!["pvsecret", "list", "--yaml", "--bin"],
|
||||
vec!["pvsecret", "create", "--hdr", "abc", "-o", "abc", "--no-verify" ,"null"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "-o", "abc", "--no-verify", "null"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "--no-verify", "null"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "null"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--cck", "abc", "--extension_secret", "abc", "--no-verify", "null"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "--flags", "disable-dump", "--pcf", "0", "null"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "--cuid", "abc", "--cuid_hex", "9", "null"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "association"],
|
||||
vec!["pvsecret", "create", "-k", "abc", "--hdr", "abc", "-o", "abc", "--no-verify", "association", "name", "--output-secret", "secret", "--input-secret", "secret"],
|
||||
];
|
||||
for arg in valid_args {
|
||||
let res = CliOptions::try_parse_from(&arg);
|
||||
if let Err(e) = &res {
|
||||
println!("arg: {arg:?}");
|
||||
println!("{e}");
|
||||
}
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
for arg in invalid_args {
|
||||
let res = CliOptions::try_parse_from(&arg);
|
||||
assert!(res.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_cli() {
|
||||
use clap::CommandFactory;
|
||||
CliOptions::command().debug_assert()
|
||||
}
|
||||
}
|
||||
22
rust/pvsecret/src/cmd.rs
Normal file
22
rust/pvsecret/src/cmd.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
mod create;
|
||||
pub use create::create;
|
||||
|
||||
// Commands (directly) related to UVCs are only available on s389x
|
||||
#[cfg(target_arch = "s390x")]
|
||||
mod add;
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub use add::add;
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
mod list;
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub use list::list;
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
mod lock;
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub use lock::lock;
|
||||
19
rust/pvsecret/src/cmd/add.rs
Normal file
19
rust/pvsecret/src/cmd/add.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use crate::cli::AddSecretOpt;
|
||||
use anyhow::{Context, Result};
|
||||
use log::warn;
|
||||
use pv::misc::get_reader_from_cli_file_arg;
|
||||
use pv::uv::{AddCmd, UvDevice};
|
||||
|
||||
/// Do an Add Secret UVC
|
||||
pub fn add(opt: &AddSecretOpt) -> Result<()> {
|
||||
let mut rd_in = get_reader_from_cli_file_arg(&opt.input)?;
|
||||
let mut cmd =
|
||||
AddCmd::new(&mut rd_in).context(format!("Processing input file {}", opt.input))?;
|
||||
UvDevice::open()?.send_cmd(&mut cmd)?;
|
||||
warn!("Successfully added the secret");
|
||||
Ok(())
|
||||
}
|
||||
240
rust/pvsecret/src/cmd/create.rs
Normal file
240
rust/pvsecret/src/cmd/create.rs
Normal file
@@ -0,0 +1,240 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use crate::cli::{AddSecretType, CreateSecretFlags, CreateSecretOpt};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use log::{debug, info, trace, warn};
|
||||
use pv::{
|
||||
misc::{
|
||||
get_writer_from_cli_file_arg, parse_hex, pv_guest_bit_set, read_certs, read_exact_file,
|
||||
read_file, try_parse_u128, try_parse_u64,
|
||||
},
|
||||
open_buffered_file,
|
||||
request::{
|
||||
openssl::pkey::{PKey, Public},
|
||||
uvsecret::{AddSecretFlags, AddSecretRequest, AddSecretVersion, ExtSecret, GuestSecret},
|
||||
BootHdrTags, HkdVerifier, ReqEncrCtx, Request, SymKeyType,
|
||||
},
|
||||
uv::ConfigUid,
|
||||
};
|
||||
use serde_yaml::Value;
|
||||
|
||||
fn write_out<D: AsRef<[u8]>>(path: &str, data: D, ctx: &str) -> pv::Result<()> {
|
||||
let mut wr = match get_writer_from_cli_file_arg(path) {
|
||||
Ok(it) => it,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
pv::misc::write(&mut wr, data, path, ctx)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prepare an Add Secret Request
|
||||
pub fn create(opt: &CreateSecretOpt) -> Result<()> {
|
||||
if pv_guest_bit_set() {
|
||||
warn!("The system seems to be a Secure Execution guest");
|
||||
if !opt.force {
|
||||
bail!("Do NOT generate Add-secret requests on a machine where you want to use the secret! Overwrite with '-f'");
|
||||
} else {
|
||||
warn!("WARNING: Enforcing of generating a request on a Secure Execution guest")
|
||||
}
|
||||
}
|
||||
|
||||
let mut asrcb = build_asrcb(opt)?;
|
||||
debug!("Generated Add-secret request");
|
||||
|
||||
// Add host-key documents
|
||||
let verifier = opt.certificate_args.verifier()?;
|
||||
read_and_verify_hkds(&opt.certificate_args.host_key_documents, verifier)?
|
||||
.into_iter()
|
||||
.for_each(|k| asrcb.add_hostkey(k));
|
||||
|
||||
debug!("Added all host-keys");
|
||||
|
||||
// build + encrypt the request
|
||||
let rq = ReqEncrCtx::random(SymKeyType::Aes256).context("Failed to generate random input")?;
|
||||
let ser_asrbc = asrcb.encrypt(&rq)?;
|
||||
warn!("Successfully generated the request");
|
||||
write_out(&opt.output, ser_asrbc, "Add Secret Request")?;
|
||||
info!("Successfully wrote the request to '{}'", &opt.output);
|
||||
|
||||
write_secret(&opt.secret, &asrcb)
|
||||
}
|
||||
|
||||
/// Set-up the `Add Secret Request` from command-line arguments
|
||||
fn build_asrcb(opt: &CreateSecretOpt) -> Result<AddSecretRequest> {
|
||||
debug!("Build Add Secret Request");
|
||||
|
||||
let secret = match &opt.secret {
|
||||
AddSecretType::Meta => GuestSecret::Null,
|
||||
AddSecretType::Association {
|
||||
name,
|
||||
input_secret: Some(p),
|
||||
..
|
||||
} => GuestSecret::association(name, read_exact_file(p, "Association secret")?)?,
|
||||
AddSecretType::Association {
|
||||
name,
|
||||
input_secret: None,
|
||||
..
|
||||
} => GuestSecret::association(name, None)?,
|
||||
};
|
||||
trace!("AddSecret: {secret:x?}");
|
||||
|
||||
let mut flags = match &opt.pcf {
|
||||
Some(v) => (&try_parse_u64(v, "pcf")?).into(),
|
||||
None => AddSecretFlags::default(),
|
||||
};
|
||||
opt.flags.iter().for_each(|v| match v {
|
||||
CreateSecretFlags::DisableDump => flags.set_disable_dump(),
|
||||
});
|
||||
debug!("FLAGS: {flags:x?}");
|
||||
|
||||
let mut se_hdr = open_buffered_file!(&opt.hdr);
|
||||
let mut asrcb = AddSecretRequest::new(
|
||||
AddSecretVersion::One,
|
||||
secret,
|
||||
BootHdrTags::from_se_image(&mut se_hdr)
|
||||
.with_context(|| format!("Provided SE-header in '{}' is malformed", &opt.hdr))?,
|
||||
flags,
|
||||
);
|
||||
|
||||
// Set CUID
|
||||
read_cuid(&mut asrcb, opt)?;
|
||||
|
||||
// Set extension secret
|
||||
if let Some(path) = &opt.extension_secret {
|
||||
asrcb.set_ext_secret(ExtSecret::Simple(
|
||||
read_exact_file(path, "extension secret")?.into(),
|
||||
))?;
|
||||
} else if let Some(path) = &opt.cck {
|
||||
asrcb.set_ext_secret(ExtSecret::Derived(read_exact_file(path, "CCK")?.into()))?;
|
||||
}
|
||||
|
||||
Ok(asrcb)
|
||||
}
|
||||
|
||||
// Try to extract a Config-UId from a yaml structure
|
||||
// The cuid field can be embedded in an abritray amount of Mappings
|
||||
// The function takes the first cuid it founds (width search).
|
||||
fn try_from_val(val: Value) -> anyhow::Result<ConfigUid> {
|
||||
fn get_cuid_from_mapping(val: &Value, depth: u8) -> Option<String> {
|
||||
if depth >= 8 {
|
||||
return None;
|
||||
}
|
||||
match val {
|
||||
Value::Mapping(m) if m.contains_key("cuid") => {
|
||||
return m.get("cuid").and_then(|v| v.as_str()).map(|s| s.to_owned())
|
||||
}
|
||||
Value::Mapping(m) => {
|
||||
for (_, v) in m {
|
||||
if let Some(v) = get_cuid_from_mapping(v, depth + 1) {
|
||||
return Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
None
|
||||
}
|
||||
let cuid = match &val {
|
||||
Value::String(s) => Some(s.clone()),
|
||||
Value::Mapping(_) => get_cuid_from_mapping(&val, 0),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(anyhow!("No 'cuid' entry found"))?;
|
||||
let cuid = cuid
|
||||
.strip_prefix("0x")
|
||||
.ok_or(anyhow!("Value starts not with 0x".to_string()))?
|
||||
.to_owned();
|
||||
if cuid.len() != ::std::mem::size_of::<ConfigUid>() * 2 {
|
||||
return Err(anyhow!(format!("len invalid ({})", cuid.len())));
|
||||
}
|
||||
let cuid: ConfigUid = parse_hex(&cuid)
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("Cannot parse hex number".to_string()))?;
|
||||
Ok(cuid)
|
||||
}
|
||||
|
||||
fn read_cuid(asrcb: &mut AddSecretRequest, opt: &CreateSecretOpt) -> Result<()> {
|
||||
if let Some(path) = &opt.cuid {
|
||||
let cuid = match read_exact_file(path, "The CUID-file") {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
let buf = read_file(path, "The CUID-file")?;
|
||||
let val: Value = serde_yaml::from_slice(&buf).context(
|
||||
"The CUID-file does not contain a 128bit value or a yaml with a 'cuid' field",
|
||||
)?;
|
||||
try_from_val(val)?
|
||||
}
|
||||
};
|
||||
asrcb.set_cuid(cuid);
|
||||
} else if let Some(v) = &opt.cuid_hex {
|
||||
asrcb.set_cuid(try_parse_u128(v, "CUID")?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// reads HKDs into memory, verifies them with the provided HKD verifier.
|
||||
/// returns list of public keys or Err
|
||||
/// Aborts on first error
|
||||
fn read_and_verify_hkds(
|
||||
hkds: &Vec<String>,
|
||||
verifier: Box<dyn HkdVerifier>,
|
||||
) -> Result<Vec<PKey<Public>>> {
|
||||
let mut res = Vec::with_capacity(hkds.len());
|
||||
for hkd in hkds {
|
||||
let hk = read_file(hkd, "host-key document")?;
|
||||
let certs = read_certs(&hk).with_context(|| {
|
||||
format!("The provided Host Key Document in '{hkd}' is not in PEM or DER format")
|
||||
})?;
|
||||
if certs.len() != 1 {
|
||||
warn!("The host key document in '{hkd}' contains more than one certificate!")
|
||||
}
|
||||
|
||||
// len is 1 -> unwrap will succeed
|
||||
let c = certs.first().unwrap();
|
||||
verifier.verify(c)?;
|
||||
res.push(c.public_key()?);
|
||||
info!("Use host-key document at '{hkd}'");
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
/// Write the generated secret (if any) to the specified output stream
|
||||
fn write_secret(secret: &AddSecretType, asrcb: &AddSecretRequest) -> Result<()> {
|
||||
if let AddSecretType::Association {
|
||||
name,
|
||||
stdout,
|
||||
output_secret: secret_out,
|
||||
..
|
||||
} = secret
|
||||
{
|
||||
let gen_path: String = name
|
||||
.chars()
|
||||
.map(|c| if c.is_whitespace() { '_' } else { c })
|
||||
.collect();
|
||||
|
||||
//write non confidential data (=name+id) to a yaml
|
||||
let secret_info = serde_yaml::to_string(asrcb.guest_secret())?;
|
||||
if stdout.to_owned() {
|
||||
println!("{secret_info}");
|
||||
} else {
|
||||
let secret_info_path = format!("{gen_path}.yaml");
|
||||
write_out(&secret_info_path, secret_info, "association secret info")?;
|
||||
debug!(
|
||||
"Non-confidential secret information: {:x?}",
|
||||
asrcb.guest_secret()
|
||||
);
|
||||
warn!("Successfully wrote association info to '{secret_info_path}'");
|
||||
}
|
||||
|
||||
if let Some(path) = secret_out {
|
||||
if let GuestSecret::Association { secret, .. } = asrcb.guest_secret() {
|
||||
write_out(path, secret.value(), "Association secret")?
|
||||
} else {
|
||||
unreachable!("The secret type has to be `association` at this point (bug)!")
|
||||
}
|
||||
info!("Successfully wrote generated association secret to '{path}'");
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
44
rust/pvsecret/src/cmd/list.rs
Normal file
44
rust/pvsecret/src/cmd/list.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use crate::cli::{ListSecretOpt, ListSecretOutputType};
|
||||
use anyhow::{Context, Result};
|
||||
use log::warn;
|
||||
use pv::{
|
||||
misc::{get_writer_from_cli_file_arg, STDOUT},
|
||||
uv::{ListCmd, SecretList, UvDevice, UvcSuccess},
|
||||
};
|
||||
|
||||
/// Do a List Secrets UVC
|
||||
pub fn list(opt: &ListSecretOpt) -> Result<()> {
|
||||
let uv = UvDevice::open()?;
|
||||
let mut cmd = ListCmd::default();
|
||||
match uv.send_cmd(&mut cmd)? {
|
||||
UvcSuccess::RC_SUCCESS => (),
|
||||
UvcSuccess::RC_MORE_DATA => warn!("There is more data available than expected"),
|
||||
};
|
||||
|
||||
let secret_list: SecretList = cmd.try_into()?;
|
||||
let mut wr_out = get_writer_from_cli_file_arg(&opt.output)?;
|
||||
|
||||
match &opt.format {
|
||||
ListSecretOutputType::Human => {
|
||||
write!(wr_out, "{secret_list}").context("Cannot generate output")?
|
||||
}
|
||||
ListSecretOutputType::Yaml => write!(wr_out, "{}", serde_yaml::to_string(&secret_list)?)
|
||||
.context("Cannot generate yaml output")?,
|
||||
ListSecretOutputType::Bin => secret_list
|
||||
.encode(&mut wr_out)
|
||||
.context("Cannot encode secret list")?,
|
||||
}
|
||||
wr_out.flush()?;
|
||||
|
||||
if opt.output != STDOUT {
|
||||
warn!(
|
||||
"Successfully wrote the list of secrets to '{}'",
|
||||
&opt.output
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
14
rust/pvsecret/src/cmd/lock.rs
Normal file
14
rust/pvsecret/src/cmd/lock.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use anyhow::Result;
|
||||
use log::warn;
|
||||
use pv::uv::{LockCmd, UvDevice};
|
||||
|
||||
/// Do a Lock Secret Store UVC
|
||||
pub fn lock() -> Result<()> {
|
||||
UvDevice::open()?.send_cmd(&mut LockCmd)?;
|
||||
warn!("Successfully locked secret store");
|
||||
Ok(())
|
||||
}
|
||||
125
rust/pvsecret/src/main.rs
Normal file
125
rust/pvsecret/src/main.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
mod cli;
|
||||
mod cmd;
|
||||
|
||||
use clap::CommandFactory;
|
||||
use clap::Parser;
|
||||
use cli::{CliOptions, Command};
|
||||
use log::trace;
|
||||
use pv::misc::PvLogger;
|
||||
use std::process::ExitCode;
|
||||
use utils::release_string;
|
||||
|
||||
use crate::cli::validate_cli;
|
||||
|
||||
static LOGGER: PvLogger = PvLogger;
|
||||
static EXIT_LOGGER: u8 = 3;
|
||||
const FEATURES: &[&str] = &[
|
||||
"+create",
|
||||
#[cfg(target_arch = "s390x")]
|
||||
"+add",
|
||||
#[cfg(target_arch = "s390x")]
|
||||
"+lock",
|
||||
#[cfg(target_arch = "s390x")]
|
||||
"+list",
|
||||
];
|
||||
|
||||
fn print_error(e: anyhow::Error, verbosity: u8) -> ExitCode {
|
||||
if verbosity > 0 {
|
||||
// Debug formatter also prints the whole error stack
|
||||
// So only print it when on verbose
|
||||
eprintln!("error: {e:?}")
|
||||
} else {
|
||||
eprintln!("error: {e}")
|
||||
};
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
|
||||
fn print_cli_error(e: clap::Error) -> ExitCode {
|
||||
let ret = if e.use_stderr() {
|
||||
ExitCode::FAILURE
|
||||
} else {
|
||||
ExitCode::SUCCESS
|
||||
};
|
||||
//Ignore any errors during printing of the error
|
||||
let _ = e.format(&mut CliOptions::command()).print();
|
||||
ret
|
||||
}
|
||||
|
||||
fn print_version(verbosity: u8) -> anyhow::Result<()> {
|
||||
println!(
|
||||
"{} version {}\nCopyright IBM Corp. 2023",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
release_string!()
|
||||
);
|
||||
if verbosity > 0 {
|
||||
FEATURES.iter().for_each(|f| print!("{f} "));
|
||||
println!("(compiled)");
|
||||
println!(
|
||||
"\n{}-crate {}",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION")
|
||||
);
|
||||
println!("{}", pv::crate_info());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
fn not_supported() -> anyhow::Result<()> {
|
||||
use anyhow::bail;
|
||||
bail!("Command only available on s390x")
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let cli: CliOptions = match CliOptions::try_parse() {
|
||||
Ok(cli) => match validate_cli(&cli) {
|
||||
Ok(_) => cli,
|
||||
Err(e) => return print_cli_error(e),
|
||||
},
|
||||
Err(e) => return print_cli_error(e),
|
||||
};
|
||||
|
||||
// set up logger/std(out,err)
|
||||
if let Err(e) = LOGGER.start(cli.verbose) {
|
||||
//should(TM) never happen
|
||||
eprintln!("Logger error: {e:?}");
|
||||
return EXIT_LOGGER.into();
|
||||
}
|
||||
|
||||
// NOTE trace verbosity is disabled in release builds
|
||||
trace!("Trace verbosity, may leak secrets to command-line");
|
||||
trace!("Options {cli:?}");
|
||||
|
||||
if cli.version {
|
||||
let _ = print_version(cli.verbose);
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
// perform the command selected by the user
|
||||
let res = match &cli.cmd {
|
||||
#[cfg(target_arch = "s390x")]
|
||||
Command::Add(opt) => cmd::add(opt),
|
||||
#[cfg(target_arch = "s390x")]
|
||||
Command::List(opt) => cmd::list(opt),
|
||||
#[cfg(target_arch = "s390x")]
|
||||
Command::Lock => cmd::lock(),
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
Command::Add(_) => not_supported(),
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
Command::List(_) => not_supported(),
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
Command::Lock => not_supported(),
|
||||
Command::Create(opt) => cmd::create(opt),
|
||||
Command::Version => print_version(cli.verbose),
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(_) => ExitCode::SUCCESS,
|
||||
Err(e) => print_error(e, cli.verbose),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user