mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bb9a9ec5b | ||
|
|
4a3957fab5 | ||
|
|
e506c94839 | ||
|
|
dfd9f52873 | ||
|
|
14ca7c5080 | ||
|
|
4fc1a92a8d | ||
|
|
d73d7f91ac | ||
|
|
800df6bef8 | ||
|
|
3c661da4ee | ||
|
|
bf5ca4367d | ||
|
|
faf26220a7 | ||
|
|
522252d18a | ||
|
|
42889edc0c | ||
|
|
13016ebc5a | ||
|
|
c4546daf34 | ||
|
|
1e18429f69 | ||
|
|
11e78cada5 | ||
|
|
0a7df9e030 | ||
|
|
7dd03eaeec | ||
|
|
663262c962 | ||
|
|
bf9482709f | ||
|
|
cdf0b5d66f | ||
|
|
4aafd6962a | ||
|
|
863e1c3fa4 | ||
|
|
7c47ea8e09 | ||
|
|
c239d99379 | ||
|
|
6c6e3a2b0e | ||
|
|
2dca5d193f | ||
|
|
75675ec627 | ||
|
|
18bf2cce06 | ||
|
|
8781dd3e7b | ||
|
|
6380e77f28 | ||
|
|
733b86c02a | ||
|
|
7827a791c9 | ||
|
|
074de1e14e | ||
|
|
07d181e29b | ||
|
|
895a88b2f8 | ||
|
|
f01f8b240c | ||
|
|
be2bc610b7 | ||
|
|
c48d45ba92 | ||
|
|
886476a207 | ||
|
|
86685f001d | ||
|
|
d619b492e9 | ||
|
|
79e4798061 | ||
|
|
cf2311f1f1 | ||
|
|
7e832da790 | ||
|
|
3b402a0630 | ||
|
|
3437c9bb90 | ||
|
|
8898650266 | ||
|
|
3ae2100d5e | ||
|
|
93e4249fd3 | ||
|
|
8ec4705239 | ||
|
|
cad450fdf9 | ||
|
|
3a1cda59ce | ||
|
|
0566a492ae | ||
|
|
bc7359d2a3 | ||
|
|
db6f272607 | ||
|
|
6db7fbe018 | ||
|
|
2f154fa49d | ||
|
|
148d3f9b64 | ||
|
|
702dc96264 | ||
|
|
313092b202 |
@@ -9,12 +9,14 @@ List of all individuals having contributed content to s390-tools
|
||||
- Arnd Bergmann
|
||||
- Axel Wirbser
|
||||
- Benjamin Block
|
||||
- Brian C. Lane
|
||||
- Carsten Otte
|
||||
- Christian Borntraeger
|
||||
- Christian Ehrhardt
|
||||
- Christof Schmitt
|
||||
- Claudio Imbrenda
|
||||
- Clemens von Mann
|
||||
- Colin Walters
|
||||
- Dan Horak
|
||||
- Despina Papadopoulou
|
||||
- Dimitri John Ledkov
|
||||
@@ -75,11 +77,13 @@ List of all individuals having contributed content to s390-tools
|
||||
- Michael Mueller
|
||||
- Mijo Safradin
|
||||
- Mikhail Zaslonko
|
||||
- Nikita Dubrovskii
|
||||
- Niklas Schnelle
|
||||
- Peter Oberparleiter
|
||||
- Peter Tiedemann
|
||||
- Philipp Kern
|
||||
- Philipp Rudo
|
||||
- Prashanth Sundararaman
|
||||
- Rafael Fonseca
|
||||
- Raimund Schroeder
|
||||
- Ralph Wuerthner
|
||||
@@ -109,7 +113,10 @@ List of all individuals having contributed content to s390-tools
|
||||
- Tuan Hoang
|
||||
- Ursula Braun
|
||||
- Utz Bacher
|
||||
- Vance Morris
|
||||
- Vasily Gorbik
|
||||
- Viktor Mihajlovski
|
||||
- Vineeth Vijayan
|
||||
- Volker Sameske
|
||||
- Wenjia Zhang
|
||||
- Wolfgang Taphorn
|
||||
|
||||
31
CHANGELOG.md
31
CHANGELOG.md
@@ -1,5 +1,36 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
* __v2.16.0 (2021-02-19)__
|
||||
|
||||
For Linux kernel version: 5.10 / 5.11
|
||||
|
||||
Add new tool:
|
||||
- hsci: New tool to manage HSCI (HiperSockets Converged Interfaces)
|
||||
|
||||
Changes of existing tools:
|
||||
- genprotimg: Add host-key document verification support
|
||||
- genprotimg: boot: Make boot loader -march=z900 compatible
|
||||
- libekmfweb: Make install directory for shared libraries configurable
|
||||
- lsdasd: Add FC Endpoint Security information
|
||||
- make: Add address sanitizer support
|
||||
- netboot: Add version information to scripts
|
||||
- netboot: Bump busybox version in pxelinux.0 build
|
||||
- zdev: Add FC Endpoint Security information for DASD devices
|
||||
- zdev: Add build option to update initial RAM-disk by default
|
||||
- zkey-ekmfweb: Avoid sequence number clash when generating keys
|
||||
- zkey/zkey-ekmfweb: Install KMS plugins into configurable location
|
||||
- zkey: Add support to store LUKS2 dummy passphrase in key repository
|
||||
|
||||
Bug Fixes:
|
||||
- dasdfmt: Fix segfault when an incorrect option is specified
|
||||
- genprotimg: Fix several build issues
|
||||
- genprotimg: Require argument for 'ramdisk' and 'parmfile' options
|
||||
- zcryptstats: Fix handling of partial results with many domains
|
||||
- zfcpdbf: Deal with crash 7.2.9 change in caller name formatting
|
||||
- zipl/boot: Fix memory use after free in stage2
|
||||
- zipl/boot: Fix potential heap overflow in stage2
|
||||
- zipl: Fix reading 4k disk's geometry
|
||||
|
||||
* __v2.15.1 (2020-10-28)__
|
||||
|
||||
For Linux kernel version: 5.9
|
||||
|
||||
@@ -72,7 +72,7 @@ In the examples below we use this fictive identity:
|
||||
### Setup GitHub and local git
|
||||
|
||||
1. Create a fork of this repository by clicking the `Fork` button on the top
|
||||
right of the [s390-tools](https://github.com/ibm-s390-tools/s390-tools)
|
||||
right of the [s390-tools](https://github.com/ibm-s390-linux/s390-tools)
|
||||
main page
|
||||
|
||||
2. Clone your forked repository to your local development system
|
||||
@@ -84,7 +84,7 @@ In the examples below we use this fictive identity:
|
||||
s390-tools repository on GitHub
|
||||
```
|
||||
$ cd s390-tools
|
||||
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-tools/s390-tools.git
|
||||
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-linux/s390-tools.git
|
||||
```
|
||||
|
||||
4. Verify your remotes
|
||||
@@ -92,8 +92,8 @@ In the examples below we use this fictive identity:
|
||||
~/s390-tools $ git remote -v
|
||||
origin https://github.com/random-developer/s390-tools.git (fetch)
|
||||
origin https://github.com/random-developer/s390-tools.git (push)
|
||||
upstream https://github.com/ibm-s390-tools/s390-tools.git (fetch)
|
||||
upstream https://github.com/ibm-s390-tools/s390-tools.git (push)
|
||||
upstream https://github.com/ibm-s390-linux/s390-tools.git (fetch)
|
||||
upstream https://github.com/ibm-s390-linux/s390-tools.git (push)
|
||||
```
|
||||
You now have two remotes: The "origin" remote points to your fork
|
||||
and the "upstream" remote to the official s390-tools repository.
|
||||
|
||||
2
Makefile
2
Makefile
@@ -9,7 +9,7 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
||||
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
||||
genprotimg lsstp
|
||||
genprotimg lsstp hsci
|
||||
|
||||
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)
|
||||
|
||||
|
||||
25
README.md
25
README.md
@@ -249,6 +249,9 @@ Package contents
|
||||
Management Foundation - Web Edition, and is used to manage keys in an
|
||||
enterprise.
|
||||
|
||||
* hsci:
|
||||
Manage HiperSockets Converged Interfaces (HSCI).
|
||||
|
||||
For more information refer to the following publications:
|
||||
|
||||
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
|
||||
@@ -277,14 +280,15 @@ build options:
|
||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb |
|
||||
| glib2 | `HAVE_GLIB2` | genprotimg |
|
||||
| libcurl | `HAVE_LIBCURL` | libekmfweb |
|
||||
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb |
|
||||
|
||||
This table lists additional build or install options:
|
||||
|
||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||
|----------------|:----------------:|:-------------------------------:|
|
||||
| dracut | `HAVE_DRACUT` | zdev |
|
||||
| initramfs-tools| `HAVE_INITRAMFS` | zdev |
|
||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||
|------------------|:----------------------------:|:--------------:|
|
||||
| dracut | `HAVE_DRACUT` | zdev |
|
||||
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
|
||||
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
|
||||
|
||||
The s390-tools build process uses "pkg-config" if available and hard-coded
|
||||
compiler and linker options otherwise.
|
||||
@@ -375,6 +379,17 @@ the different tools are provided:
|
||||
Distributors with different boot or RAM-disk mechanisms should provide
|
||||
a custom zdev-root-update helper script.
|
||||
|
||||
- `ZDEV_ALWAYS_UPDATE_INITRD=1` upon modification of any persistent device
|
||||
configuration, chzdev updates the initial RAM-disk by default, without any
|
||||
additional user interaction.
|
||||
|
||||
For some distributions, all the configuration attributes must be copied to
|
||||
the initial RAM-disk. Because the device configuration directives applied
|
||||
in the initial RAM-disk takes precedence over those stored in the root file-
|
||||
system. This copying is done usually by explicitly invoking a command. This
|
||||
build option makes it user-friendly and does this copying without any manual
|
||||
intervention.
|
||||
|
||||
Some functions of zdev require that the following programs are available:
|
||||
|
||||
- modprobe (kmod)
|
||||
|
||||
@@ -299,7 +299,7 @@ static unsigned long dec_to_hex(unsigned long long num)
|
||||
{
|
||||
unsigned long res;
|
||||
|
||||
asm volatile("cvb %0,%1" : "=d" (res) : "m" (num));
|
||||
asm volatile("cvb %0,%1" : "=d" (res) : "Q" (num));
|
||||
return res & 0xffffffff;
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ static unsigned int hex_to_dec(unsigned int num)
|
||||
{
|
||||
unsigned long long res;
|
||||
|
||||
asm volatile("cvd %1,%0" : "=m" (res) : "d" (num));
|
||||
asm volatile("cvd %1,%0" : "=Q" (res) : "d" (num));
|
||||
return res & 0xffffffff;
|
||||
}
|
||||
|
||||
@@ -2050,7 +2050,7 @@ static int update_dir_levels(int blocks)
|
||||
if (blocks < 2)
|
||||
return 0;
|
||||
|
||||
while (blocks / (PTRS_PER_BLOCK + 1)) {
|
||||
while (blocks / PTRS_PER_BLOCK) {
|
||||
levels++;
|
||||
blocks /= PTRS_PER_BLOCK;
|
||||
}
|
||||
@@ -3103,7 +3103,7 @@ static void update_levels(struct file *f)
|
||||
return;
|
||||
}
|
||||
|
||||
while (blocks / (per_block + 1)) {
|
||||
while (blocks / per_block) {
|
||||
levels++;
|
||||
blocks /= per_block;
|
||||
}
|
||||
|
||||
24
common.mak
24
common.mak
@@ -5,8 +5,8 @@ COMMON_INCLUDED = true
|
||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||
VERSION = 2
|
||||
RELEASE = 15
|
||||
PATCHLEVEL = 1
|
||||
RELEASE = 16
|
||||
PATCHLEVEL = 0
|
||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
export S390_TOOLS_RELEASE
|
||||
@@ -106,6 +106,11 @@ endif
|
||||
DEFAULT_CPPFLAGS = -D_GNU_SOURCE
|
||||
DEFAULT_LDFLAGS = -rdynamic
|
||||
|
||||
ifeq ("${ASAN}","1")
|
||||
DEFAULT_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||
DEFAULT_LDFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
#
|
||||
# Check for build dependency
|
||||
#
|
||||
@@ -174,12 +179,20 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
|
||||
# for SYSTEMDSYSTEMUNITDIR (e.g. /lib/systemd/system)
|
||||
SYSTEMDSYSTEMUNITDIR =
|
||||
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
|
||||
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
|
||||
|
||||
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
|
||||
SOINSTALLDIR = $(USRLIB64DIR)
|
||||
else
|
||||
SOINSTALLDIR = $(LIBDIR)
|
||||
endif
|
||||
|
||||
INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
|
||||
$(SYSCONFDIR) $(SYSCONFDIR)/sysconfig \
|
||||
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
|
||||
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
|
||||
$(USRLIB64DIR) $(USRINCLUDEDIR)
|
||||
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
|
||||
$(SOINSTALLDIR)
|
||||
OWNER = $(shell id -un)
|
||||
GROUP = $(shell id -gn)
|
||||
export INSTALLDIR BINDIR LIBDIR USRLIB64DIR MANDIR OWNER GROUP
|
||||
@@ -264,6 +277,7 @@ help:
|
||||
@echo ' G=1 Build with gcov to collect code coverage data'
|
||||
@echo ' V=1 Generate verbose build output'
|
||||
@echo ' W=1 Build with higher warning level'
|
||||
@echo ' ASAN=1 Build with address sanitizer'
|
||||
@echo ''
|
||||
@echo 'EXAMPLES'
|
||||
@echo ' # make clean all D=1 W=1 -j'
|
||||
@@ -366,9 +380,9 @@ install: install_echo install_dirs
|
||||
clean_echo:
|
||||
$(call echocmd," CLEAN ")
|
||||
clean_gcov:
|
||||
rm -f *.gcda *.gcno *.gcov
|
||||
rm -f -- *.gcda *.gcno *.gcov
|
||||
clean_dep:
|
||||
rm -f .*.o.d
|
||||
rm -f -- .*.o.d
|
||||
|
||||
clean: clean_echo clean_gcov clean_dep
|
||||
endif
|
||||
|
||||
@@ -91,13 +91,18 @@ static int read_sfb(unsigned long *min, unsigned long *max)
|
||||
int rc = EXIT_SUCCESS;
|
||||
FILE *fp;
|
||||
|
||||
if (geteuid()) {
|
||||
fprintf(stderr, "Error: Must run as root\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fp = fopen(PERF_SFB_SIZE, "r");
|
||||
if (fp == NULL) {
|
||||
linux_error(PERF_SFB_SIZE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
|
||||
fprintf(stderr, "Error: Can not parse file " PERF_SFB_SIZE);
|
||||
fprintf(stderr, "Error: Can not parse file " PERF_SFB_SIZE
|
||||
"\n");
|
||||
rc = EXIT_FAILURE;
|
||||
} else {
|
||||
if (*min == 0)
|
||||
|
||||
@@ -2572,6 +2572,7 @@ static const char *machine_name(void)
|
||||
case 3906: return "IBM z14";
|
||||
case 3907: return "IBM z14 ZR1";
|
||||
case 8561: return "IBM z15";
|
||||
case 8562: return "IBM z15 Model T02";
|
||||
}
|
||||
return "Unknown hardware model";
|
||||
}
|
||||
@@ -3094,11 +3095,11 @@ int main(int argc, char **argv)
|
||||
util_prg_init(&prg);
|
||||
util_opt_init(opt_vec, NULL);
|
||||
|
||||
ret = read_info();
|
||||
if (ret == EXIT_FAILURE)
|
||||
return ret;
|
||||
ret = parse_args(argc, argv);
|
||||
if (read_info() == EXIT_FAILURE)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
switch ((ret = parse_args(argc, argv))) {
|
||||
switch (ret) {
|
||||
case ACTION_CNT:
|
||||
case ACTION_CNTALL:
|
||||
all = ret == ACTION_CNTALL;
|
||||
@@ -3114,6 +3115,7 @@ int main(int argc, char **argv)
|
||||
case ACTION_NONE:
|
||||
case ACTION_INFO:
|
||||
show_info(&cpumf, ret == ACTION_INFO);
|
||||
ret = EXIT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -1637,7 +1637,7 @@ int main(int argc, char *argv[])
|
||||
/* End of options string - start of devices list */
|
||||
break;
|
||||
default:
|
||||
error("Try '%s --help' for more information.");
|
||||
error("Try '%s --help' for more information.", prog_name);
|
||||
}
|
||||
|
||||
if (rc == -1)
|
||||
|
||||
@@ -41,6 +41,10 @@ static const char mode_str[3][10] = {
|
||||
"Full", "Quick", "Expand"
|
||||
};
|
||||
|
||||
/* Report error, free memory, and exit */
|
||||
static void error(const char *format, ...)
|
||||
__attribute__((__noreturn__, __format__(__printf__, 1, 2)));
|
||||
|
||||
#define DASD_PARTN_BITS 2
|
||||
#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
|
||||
|
||||
|
||||
@@ -1232,7 +1232,7 @@ static void fdasd_reread_partition_table(fdasd_anchor_t *anc)
|
||||
if (!anc->silent)
|
||||
printf("rereading partition table...\n");
|
||||
|
||||
if (dasd_reread_partition_table(options.device, 1) != 0) {
|
||||
if (dasd_reread_partition_table(options.device, 5) != 0) {
|
||||
fdasd_error(anc, unable_to_ioctl, "Error while rereading "
|
||||
"partition table.\nPlease reboot!");
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ clean: clean-recursive
|
||||
$(RECURSIVE_TARGETS):
|
||||
@target=`echo $@ |sed s/-recursive//`; \
|
||||
for d in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$d $$target; \
|
||||
$(MAKE) -C $$d $$target || exit 1; \
|
||||
done
|
||||
|
||||
.PHONY: all install clean $(RECURSIVE_TARGETS)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Entry code for stage 3a boot loader
|
||||
* Entry code for stage 3a and stage 3b boot loader
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
@@ -24,6 +24,8 @@ _start:
|
||||
sam64
|
||||
|
||||
/* Initialize stack */
|
||||
lgfi %r15, STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
||||
basr %r13, 0
|
||||
.Lbase: llgf %r15, .Lstack - .Lbase(%r13)
|
||||
brasl %r14, initialize
|
||||
.Lstack: .long STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
||||
.previous
|
||||
|
||||
@@ -21,6 +21,8 @@ _init:
|
||||
* kernel command line and the address and size of the
|
||||
* ramdisk. Simply ignore this by starting at 0x11000.
|
||||
*/
|
||||
lgfi %r1, STAGE3A_ENTRY
|
||||
basr %r13, 0
|
||||
.Lbase: llgf %r1, .Lstage3a_entry - .Lbase(%r13)
|
||||
br %r1
|
||||
.Lstage3a_entry: .long STAGE3A_ENTRY
|
||||
.previous
|
||||
|
||||
@@ -31,12 +31,12 @@ stage3b_reloc_start:
|
||||
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||
sam64
|
||||
|
||||
.copy_stage3b:
|
||||
/* Location of stage3b in memory */
|
||||
larl %r8, stage3b_start
|
||||
|
||||
/* Destination for stage3b */
|
||||
lgfi %r9, STAGE3B_LOAD_ADDRESS
|
||||
basr %r13, 0
|
||||
.Lbase: llgf %r9, .Lstage3b_load_address - .Lbase(%r13)
|
||||
|
||||
/* Size of stage3b */
|
||||
lghi %r11, stage3b_end - stage3b_start
|
||||
@@ -45,8 +45,10 @@ stage3b_reloc_start:
|
||||
MEMCPY %r9, %r8, %r11
|
||||
|
||||
/* Branch to STAGE3B_ENTRY */
|
||||
lgfi %r9, STAGE3B_ENTRY
|
||||
llgf %r9, .Lstage3b_entry - .Lbase(%r13)
|
||||
br %r9
|
||||
.Lstage3b_load_address: .long STAGE3B_LOAD_ADDRESS
|
||||
.Lstage3b_entry: .long STAGE3B_ENTRY
|
||||
stage3b_start:
|
||||
.incbin "stage3b.bin"
|
||||
stage3b_end:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.\" 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 GENPROTIMG 8 "March 2020" "s390-tools"
|
||||
.TH GENPROTIMG 8 "November 2020" "s390-tools"
|
||||
.SH NAME
|
||||
genprotimg \- Create a protected virtualization image
|
||||
|
||||
@@ -10,6 +10,7 @@ genprotimg \- Create a protected virtualization image
|
||||
.SY
|
||||
.B genprotimg
|
||||
\fB\-k\fR \fIHOST_KEY_DOCUMENT\fR...
|
||||
\fB\-C\fR \fICERTIFICATE\fR...
|
||||
\fB\-i\fR \fIVMLINUZ\fR
|
||||
[\fB\-r\fR \fIRAMDISK\fR]
|
||||
[\fB\-p\fR \fIPARMFILE\fR]
|
||||
@@ -21,15 +22,19 @@ genprotimg \- Create a protected virtualization image
|
||||
.PP
|
||||
Use \fBgenprotimg\fR to generate a single bootable image file with
|
||||
encrypted and integrity-protected parts. The command requires a kernel
|
||||
image, a host-key document, and an output file name. Optionally,
|
||||
specify an initial RAM filesystem, and a file containing the kernel
|
||||
parameters. Should special circumstances require it, you can
|
||||
image, a host-key document, certificates for the host-key document
|
||||
verification, and an output file name. Optionally, specify an initial
|
||||
RAM filesystem, and a file containing the kernel parameters. If the
|
||||
command should be run offline, use the \fB\-\-offline\fR option and
|
||||
specify the certificate revocation lists (CRLs) by using the
|
||||
\fB\-\-crl\fR option. Should special circumstances require it, you can
|
||||
optionally specify your own keys for the encryption by using the
|
||||
experimental options. In the resulting image file, a plain text boot
|
||||
loader, the encrypted components for kernel, initial RAM disk, kernel
|
||||
parameters, and the encrypted and integrity-protected header are
|
||||
concatenated. The header contains metadata necessary for running the
|
||||
guest in protected mode.
|
||||
experimental options. For all certificates, CRLs, and host-key
|
||||
documents, both the PEM and DER input formats are supported. In the
|
||||
resulting image file, a plain text boot loader, the encrypted
|
||||
components for kernel, initial RAM disk, kernel parameters, and the
|
||||
encrypted and integrity-protected header are concatenated. The header
|
||||
contains metadata necessary for running the guest in protected mode.
|
||||
.PP
|
||||
Use this image file as a kernel image for zipl or for a direct kernel
|
||||
boot using QEMU.
|
||||
@@ -53,6 +58,12 @@ Specifies a host-key document. At least one is required. Specify this
|
||||
option multiple times to enable the image to run on more than one
|
||||
host.
|
||||
.TP
|
||||
\fB\-C\fR, \fB\-\-cert\fR=\fI\,FILE\/\fR
|
||||
Specifies the certificate that is 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). Required.
|
||||
.TP
|
||||
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
||||
Specifies the output file. Required.
|
||||
.TP
|
||||
@@ -65,6 +76,20 @@ Specifies the RAM disk image. Optional.
|
||||
\fB\-p\fR, \fB\-\-parmfile\fR=\fI\,PARMFILE\/\fR
|
||||
Specifies the kernel command line stored in \fI\,PARMFILE\/\fR. Optional.
|
||||
.TP
|
||||
\fB\-\-crl\fR=\fI\,FILE\/\fR
|
||||
Specifies the revocation list that is used to check whether a
|
||||
certificate of the chain of trust is revoked. Specify this option
|
||||
multiple times to use multiple CRLs. Optional.
|
||||
.TP
|
||||
\fB\-\-offline\fR
|
||||
Specifies offline mode, in which no attempt is made to download
|
||||
CRLs. Optional.
|
||||
.TP
|
||||
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
||||
Specifies the root CA certificate for the verification. If omitted,
|
||||
the DigiCert root CA certificate installed on the system is used. Use
|
||||
this only if you trust the specified certificate. Optional.
|
||||
.TP
|
||||
\fB\-\-no-verify\fR
|
||||
Do not require the host-key documents to be valid. For testing
|
||||
purposes, do not use for a production image. Optional.
|
||||
@@ -77,11 +102,13 @@ Prints version information, then exits.
|
||||
Generate a protected virtualization image in
|
||||
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR,
|
||||
the initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
||||
\fI\,parmfile\/\fR, and the host-key document in \fI\,host_key.crt\/\fR:
|
||||
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR,
|
||||
the IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
||||
host-key document in \fI\,host_key.crt\/\fR:
|
||||
.PP
|
||||
.Vb 1
|
||||
.EX
|
||||
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-o \fI\,/boot/vmlinuz.pv\/\fR
|
||||
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt \-o \fI\,/boot/vmlinuz.pv\/\fR
|
||||
.EE
|
||||
.Ve
|
||||
.PP
|
||||
|
||||
@@ -15,24 +15,24 @@ INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
|
||||
|
||||
WARNINGS := -Wall -Wextra -Wshadow \
|
||||
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
|
||||
-Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline \
|
||||
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
|
||||
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
|
||||
-Wpointer-arith -Werror \
|
||||
-Wpointer-arith -Werror -Wno-error=inline \
|
||||
$(NULL)
|
||||
|
||||
$(bin_PROGRAM)_SRCS := $(bin_PROGRAM).c pv/pv_stage3.c pv/pv_image.c \
|
||||
pv/pv_comp.c pv/pv_hdr.c pv/pv_ipib.c utils/crypto.c utils/file_utils.c \
|
||||
pv/pv_args.c utils/buffer.c pv/pv_comps.c pv/pv_error.c \
|
||||
pv/pv_opt_item.c \
|
||||
pv/pv_opt_item.c utils/curl.c \
|
||||
$(NULL)
|
||||
$(bin_PROGRAM)_OBJS := $($(bin_PROGRAM)_SRCS:.c=.o)
|
||||
|
||||
ALL_CFLAGS += -std=gnu11 -DPKGDATADIR=$(PKGDATADIR) \
|
||||
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) \
|
||||
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBCURL_CFLAGS) \
|
||||
$(WARNINGS) \
|
||||
$(NULL)
|
||||
ALL_CPPFLAGS += $(INCLUDE_PARMS)
|
||||
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS)
|
||||
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
|
||||
|
||||
|
||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||
@@ -40,21 +40,27 @@ GLIB2_CFLAGS := $(shell pkg-config --silence-errors --cflags glib-2.0)
|
||||
GLIB2_LIBS := $(shell pkg-config --silence-errors --libs glib-2.0)
|
||||
LIBCRYPTO_CFLAGS := $(shell pkg-config --silence-errors --cflags libcrypto)
|
||||
LIBCRYPTO_LIBS := $(shell pkg-config --silence-errors --libs libcrypto)
|
||||
LIBCURL_CFLAGS := $(shell pkg-config --silence-errors --cflags libcurl)
|
||||
LIBCURL_LIBS := $(shell pkg-config --silence-errors --libs libcurl)
|
||||
else
|
||||
GLIB2_CFLAGS := -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
|
||||
GLIB2_LIBS := -lglib-2.0
|
||||
LIBCRYPTO_CFLAGS :=
|
||||
LIBCRYPTO_LIBS := -lcrypto
|
||||
LIBCURL_CFLAGS :=
|
||||
LIBCURL_LIBS := -lcurl
|
||||
endif
|
||||
|
||||
BUILD_TARGETS := skip-$(bin_PROGRAM)
|
||||
INSTALL_TARGETS := skip-$(bin_PROGRAM)
|
||||
ifneq (${HAVE_OPENSSL},0)
|
||||
ifneq (${HAVE_GLIB2},0)
|
||||
ifneq (${HAVE_LIBCURL},0)
|
||||
BUILD_TARGETS := $(bin_PROGRAM)
|
||||
INSTALL_TARGETS := install-$(bin_PROGRAM)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(BUILD_TARGETS)
|
||||
|
||||
@@ -98,4 +104,9 @@ $($(bin_PROGRAM)_OBJS): .check-dep-$(bin_PROGRAM)
|
||||
"openssl-devel / libssl-dev version >= 1.1.0", \
|
||||
"HAVE_OPENSSL=0", \
|
||||
"-I.")
|
||||
$(call check_dep, \
|
||||
"$(bin_PROGRAM)", \
|
||||
"curl/curl.h", \
|
||||
"libcurl-devel", \
|
||||
"HAVE_LIBCURL=0")
|
||||
touch $@
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "common.h"
|
||||
#include "pv/pv_args.h"
|
||||
#include "pv/pv_image.h"
|
||||
#include "utils/crypto.h"
|
||||
#include "utils/curl.h"
|
||||
|
||||
enum {
|
||||
LOG_LEVEL_CRITICAL = 0,
|
||||
@@ -117,6 +119,8 @@ static void remove_signal_handler(const gint *signals, const gsize signals_n)
|
||||
signal(signals[i], SIG_DFL);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) __init(void);
|
||||
static void __attribute__((destructor)) __cleanup(void);
|
||||
gint main(gint argc, gchar *argv[])
|
||||
{
|
||||
g_autoptr(PvArgs) args = pv_args_new();
|
||||
@@ -177,5 +181,20 @@ error:
|
||||
rmdir_recursive(tmp_dir, NULL);
|
||||
remove_signal_handler(signals, G_N_ELEMENTS(signals));
|
||||
g_free(tmp_dir);
|
||||
g_clear_pointer(&img, pv_img_free);
|
||||
g_clear_pointer(&args, pv_args_free);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
static void __init(void)
|
||||
{
|
||||
pv_crypto_init();
|
||||
if (curl_init() != 0)
|
||||
g_abort();
|
||||
}
|
||||
|
||||
static void __cleanup(void)
|
||||
{
|
||||
curl_cleanup();
|
||||
pv_crypto_cleanup();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,24 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
/* IBM signing key subject */
|
||||
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
|
||||
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
|
||||
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
|
||||
#define PV_IBM_Z_SUBJECT_ORGANIZATIONONAL_UNIT_NAME_SUFFIX "Key Signing Service"
|
||||
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
|
||||
#define PV_IBM_Z_SUBJECT_STATE "New York"
|
||||
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
|
||||
|
||||
/* Minimum security level for the keys/certificates used to establish a chain of
|
||||
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
|
||||
* for details).
|
||||
*/
|
||||
#define PV_CERTS_SECURITY_LEVEL 2
|
||||
|
||||
/* SKID for DigiCert Assured ID Root CA */
|
||||
#define DIGICERT_ASSURED_ID_ROOT_CA_SKID "45EBA2AFF492CB82312D518BA7A7219DF36DC80F"
|
||||
|
||||
union ecdh_pub_key {
|
||||
struct {
|
||||
uint8_t x[80];
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
|
||||
static gchar summary[] =
|
||||
"Use genprotimg to create a protected virtualization kernel image file,\n"
|
||||
"which can be loaded using zipl or QEMU.";
|
||||
"which can be loaded using zipl or QEMU. For all certificates, revocation\n"
|
||||
"lists, and host-key documents, both the PEM and DER input formats are\n"
|
||||
"supported.";
|
||||
|
||||
static gint pv_arg_compare(gconstpointer arg_1, gconstpointer arg_2)
|
||||
{
|
||||
@@ -97,9 +99,14 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!args->no_verify) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Use the option '--no-verify' as the verification support is not available yet."));
|
||||
if (!args->no_verify &&
|
||||
(!args->untrusted_cert_paths ||
|
||||
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
||||
g_set_error(
|
||||
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Either specify the IBM Z signing key and (DigiCert) intermediate CA certificate\n"
|
||||
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
|
||||
"host-key document verification completely (at your own risk)."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -141,6 +148,8 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
||||
{
|
||||
gchar **args_option = NULL;
|
||||
|
||||
if (g_str_equal(option, "--root-ca"))
|
||||
args_option = &args->root_ca_path;
|
||||
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
||||
args_option = &args->output_path;
|
||||
if (g_str_equal(option, "--x-comp-key"))
|
||||
@@ -211,6 +220,18 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||
_("FILE specifies a host-key document. At least\n" INDENT
|
||||
"one is required."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "cert",
|
||||
.short_name = 'C',
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY,
|
||||
.arg_data = &args->untrusted_cert_paths,
|
||||
.description = _(
|
||||
"FILE contains a certificate that is used to\n" INDENT
|
||||
"establish a chain of trust for the verification\n" INDENT
|
||||
"of the host-key documents. The IBM Z signing\n" INDENT
|
||||
"key and intermediate CA certificate (signed\n" INDENT
|
||||
"by the root CA) are required."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "output",
|
||||
.short_name = 'o',
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
@@ -227,7 +248,7 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||
.arg_description = _("IMAGE") },
|
||||
{ .long_name = "ramdisk",
|
||||
.short_name = 'r',
|
||||
.flags = G_OPTION_FLAG_OPTIONAL_ARG | G_OPTION_FLAG_FILENAME,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_add_component,
|
||||
.description = _("Use RAMDISK as the initial RAM disk\n" INDENT
|
||||
@@ -235,12 +256,37 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||
.arg_description = _("RAMDISK") },
|
||||
{ .long_name = "parmfile",
|
||||
.short_name = 'p',
|
||||
.flags = G_OPTION_FLAG_OPTIONAL_ARG | G_OPTION_FLAG_FILENAME,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_add_component,
|
||||
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
||||
"(optional)."),
|
||||
.arg_description = _("PARMFILE") },
|
||||
{ .long_name = "crl",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY,
|
||||
.arg_data = &args->crl_paths,
|
||||
.description = _(
|
||||
"FILE contains a certificate revocation list\n" INDENT
|
||||
"(optional)."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "offline",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_NONE,
|
||||
.arg_data = &args->offline,
|
||||
.description = _("Don't download CRLs (optional)."),
|
||||
.arg_description = NULL },
|
||||
{ .long_name = "root-ca",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _(
|
||||
"Set FILE as the trusted root CA and don't use the\n" INDENT
|
||||
"root CAs that are installed on the system (optional)."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "no-verify",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
@@ -378,6 +424,9 @@ void pv_args_free(PvArgs *args)
|
||||
g_free(args->cust_root_key_path);
|
||||
g_free(args->cust_comm_key_path);
|
||||
g_free(args->gcm_iv_path);
|
||||
g_free(args->root_ca_path);
|
||||
g_strfreev(args->crl_paths);
|
||||
g_strfreev(args->untrusted_cert_paths);
|
||||
g_strfreev(args->host_keys);
|
||||
g_free(args->xts_key_path);
|
||||
g_slist_free_full(args->comps, (GDestroyNotify)pv_arg_free);
|
||||
|
||||
@@ -25,6 +25,7 @@ void pv_arg_free(PvArg *arg);
|
||||
typedef struct {
|
||||
gint log_level;
|
||||
gint no_verify;
|
||||
gboolean offline;
|
||||
gchar *pcf;
|
||||
gchar *scf;
|
||||
gchar *psw_addr; /* PSW address which will be used for the start of
|
||||
@@ -34,6 +35,11 @@ typedef struct {
|
||||
gchar *cust_comm_key_path;
|
||||
gchar *gcm_iv_path;
|
||||
gchar **host_keys;
|
||||
gchar *root_ca_path; /* Trusted root CA used for the verification of the
|
||||
* chain of trust (if specified).
|
||||
*/
|
||||
gchar **untrusted_cert_paths;
|
||||
gchar **crl_paths;
|
||||
gchar *xts_key_path;
|
||||
GSList *comps;
|
||||
gchar *output_path;
|
||||
|
||||
@@ -28,6 +28,8 @@ typedef enum {
|
||||
PV_ERROR_IPIB_SIZE,
|
||||
PV_ERROR_PV_HDR_SIZE,
|
||||
PV_ERROR_INTERNAL,
|
||||
PV_ERROR_CURL_INIT_FAILED,
|
||||
PV_ERROR_DOWNLOAD_FAILED,
|
||||
} PvErrors;
|
||||
|
||||
typedef enum {
|
||||
@@ -57,6 +59,31 @@ typedef enum {
|
||||
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||
PV_CRYPTO_ERROR_INVALID_PARM,
|
||||
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
|
||||
PV_CRYPTO_ERROR_INVALID_VALIDITY_PERIOD,
|
||||
PV_CRYPTO_ERROR_EXPIRED,
|
||||
PV_CRYPTO_ERROR_NOT_VALID_YET,
|
||||
PV_CRYPTO_ERROR_LOAD_CRL,
|
||||
PV_CRYPTO_ERROR_NO_PUBLIC_KEY,
|
||||
PV_CRYPTO_ERROR_INVALID_SIGNATURE_ALGORITHM,
|
||||
PV_CRYPTO_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
|
||||
PV_CRYPTO_ERROR_INVALID_URI,
|
||||
PV_CRYPTO_ERROR_CRL_DOWNLOAD_FAILED,
|
||||
PV_CRYPTO_ERROR_CERT_SIGNATURE_INVALID,
|
||||
PV_CRYPTO_ERROR_CRL_SIGNATURE_INVALID,
|
||||
PV_CRYPTO_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
|
||||
PV_CRYPTO_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
|
||||
PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
PV_CRYPTO_ERROR_MALFORMED_CERTIFICATE,
|
||||
PV_CRYPTO_ERROR_NO_CRL,
|
||||
PV_CRYPTO_ERROR_LOAD_ROOT_CA,
|
||||
PV_CRYPTO_ERROR_LOAD_DEFAULT_CA,
|
||||
PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
|
||||
PV_CRYPTO_ERROR_WRONG_CA_USED,
|
||||
PV_CRYPTO_ERROR_SKID_AKID_MISMATCH,
|
||||
PV_CRYPTO_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
||||
PV_CRYPTO_ERROR_FAILED_DOWNLOAD_CRL,
|
||||
PV_CRYPTO_ERROR_NO_CRLDP,
|
||||
PV_CRYPTO_ERROR_CERT_REVOKED,
|
||||
} PvCryptoErrors;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -138,22 +139,18 @@ static EVP_PKEY *pv_img_get_cust_pub_priv_key(gint nid, GError **err)
|
||||
return generate_ec_key(nid, err);
|
||||
}
|
||||
|
||||
static HostKeyList *pv_img_get_host_keys(gchar **host_cert_paths,
|
||||
X509_STORE *store, gint nid,
|
||||
static HostKeyList *pv_img_get_host_keys(GSList *host_keys_with_path, gint nid,
|
||||
GError **err)
|
||||
{
|
||||
g_autoslist(EVP_PKEY) ret = NULL;
|
||||
|
||||
g_assert(host_cert_paths);
|
||||
|
||||
for (gchar **iterator = host_cert_paths; iterator != NULL && *iterator != NULL;
|
||||
iterator++) {
|
||||
for (GSList *iterator = host_keys_with_path; iterator;
|
||||
iterator = iterator->next) {
|
||||
x509_with_path *cert_with_path = iterator->data;
|
||||
g_autoptr(EVP_PKEY) host_key = NULL;
|
||||
const gchar *path = *iterator;
|
||||
X509 *cert = cert_with_path->cert;
|
||||
|
||||
g_assert(path);
|
||||
|
||||
host_key = read_ec_pubkey_cert(store, nid, path, err);
|
||||
host_key = read_ec_pubkey_cert(cert, nid, err);
|
||||
if (!host_key)
|
||||
return NULL;
|
||||
|
||||
@@ -253,10 +250,172 @@ static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
||||
const gchar *root_ca_path,
|
||||
const gchar *const *crl_paths,
|
||||
const gchar *const *untrusted_cert_paths,
|
||||
gboolean offline, GError **err)
|
||||
{
|
||||
g_autoslist(x509_with_path) untrusted_certs_with_path = NULL;
|
||||
g_autoptr(STACK_OF_X509) ibm_signing_certs = NULL;
|
||||
g_autoptr(STACK_OF_X509) untrusted_certs = NULL;
|
||||
g_autoslist(x509_pair) ibm_z_pairs = NULL;
|
||||
g_autoptr(X509_STORE) trusted = NULL;
|
||||
gint ibm_signing_certs_count;
|
||||
|
||||
/* Load trusted root CAs of the system if and only if @root_ca_path is
|
||||
* NULL, otherwise use the root CA specified by @root_ca_path.
|
||||
*/
|
||||
trusted = store_setup(root_ca_path, crl_paths, err);
|
||||
if (!trusted)
|
||||
goto error;
|
||||
|
||||
if (!offline) {
|
||||
g_autoptr(STACK_OF_X509_CRL) downloaded_ibm_signing_crls = NULL;
|
||||
|
||||
/* Set up the download routine for the lookup of CRLs. */
|
||||
store_setup_crl_download(trusted);
|
||||
|
||||
/* Try to download the CRLs of the IBM Z signing certificates
|
||||
* specified in the host-key documents. Ignore download errors
|
||||
* as it's still possible that a CRL is specified via command
|
||||
* line.
|
||||
*/
|
||||
downloaded_ibm_signing_crls = try_load_crls_by_certs(host_key_certs);
|
||||
|
||||
/* Add the downloaded CRLs to the store so they can be used for
|
||||
* the verification later.
|
||||
*/
|
||||
for (int i = 0; i < sk_X509_CRL_num(downloaded_ibm_signing_crls); i++) {
|
||||
X509_CRL *crl = sk_X509_CRL_value(downloaded_ibm_signing_crls, i);
|
||||
|
||||
if (X509_STORE_add_crl(trusted, crl) != 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("failed to load CRL"));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Load all untrusted certificates (e.g. IBM Z signing key and
|
||||
* DigiCert intermediate CA) that are required to establish a chain of
|
||||
* trust starting from the host-key document up to the root CA (if not
|
||||
* otherwise specified that's the DigiCert Assured ID Root CA).
|
||||
*/
|
||||
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
|
||||
if (!untrusted_certs_with_path)
|
||||
goto error;
|
||||
|
||||
/* Convert to STACK_OF(X509) */
|
||||
untrusted_certs = get_x509_stack(untrusted_certs_with_path);
|
||||
|
||||
/* Find all IBM Z signing keys and remove them from the chain as we
|
||||
* have to verify that they're valid. The last step of the chain of
|
||||
* trust verification must be done manually, as the IBM Z signing keys
|
||||
* are not marked as (intermediate) CA and therefore the standard
|
||||
* `X509_verify_cert` function of OpenSSL cannot be used to verify the
|
||||
* actual host-key documents.
|
||||
*/
|
||||
ibm_signing_certs = delete_ibm_signing_certs(untrusted_certs);
|
||||
ibm_signing_certs_count = sk_X509_num(ibm_signing_certs);
|
||||
if (ibm_signing_certs_count < 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
_("please specify at least one IBM Z signing key"));
|
||||
goto error;
|
||||
} else if (ibm_signing_certs_count > 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
_("please specify only one IBM Z signing key"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (store_set_verify_param(trusted, err) < 0)
|
||||
goto error;
|
||||
|
||||
/* Verify that the IBM Z signing keys are trustable.
|
||||
* For this we must check:
|
||||
*
|
||||
* 1. Can a chain of trust be established ending in a root CA
|
||||
* 2. Is the correct root CA ued? It has either to be the
|
||||
* 'DigiCert Assured ID Root CA' or the root CA specified via
|
||||
* command line.
|
||||
*/
|
||||
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
|
||||
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
|
||||
g_autoptr(STACK_OF_X509_CRL) ibm_signing_crls = NULL;
|
||||
g_autoptr(X509_STORE_CTX) ctx = NULL;
|
||||
x509_pair *pair = NULL;
|
||||
|
||||
g_assert(ibm_signing_cert);
|
||||
|
||||
/* Create the verification context and set the trusted
|
||||
* and chain parameters.
|
||||
*/
|
||||
ctx = create_store_ctx(trusted, untrusted_certs, err);
|
||||
if (!ctx)
|
||||
goto error;
|
||||
|
||||
/* Verify the IBM Z signing key */
|
||||
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
|
||||
goto error;
|
||||
|
||||
/* Verify the build chain of trust chain. If the user passes a
|
||||
* trusted root CA on the command line then the check for the
|
||||
* Subject Key Identifier (SKID) is skipped, otherwise let's
|
||||
* check if the SKID meets our expectation.
|
||||
*/
|
||||
if (!root_ca_path &&
|
||||
check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
|
||||
get_digicert_assured_id_root_ca_skid(),
|
||||
err) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
|
||||
if (!ibm_signing_crls) {
|
||||
g_prefix_error(err, _("IBM Z signing key: "));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Increment reference counter of @ibm_signing_cert as the
|
||||
* certificate will now also be owned by @ibm_z_pairs.
|
||||
*/
|
||||
if (X509_up_ref(ibm_signing_cert) != 1)
|
||||
g_abort();
|
||||
|
||||
pair = x509_pair_new(&ibm_signing_cert, &ibm_signing_crls);
|
||||
ibm_z_pairs = g_slist_append(ibm_z_pairs, pair);
|
||||
g_assert(!ibm_signing_cert);
|
||||
g_assert(!ibm_signing_crls);
|
||||
}
|
||||
|
||||
/* Verify host-key documents by using the IBM Z signing
|
||||
* certificates and the corresponding certificate revocation
|
||||
* lists.
|
||||
*/
|
||||
for (GSList *iterator = host_key_certs; iterator; iterator = iterator->next) {
|
||||
x509_with_path *host_key_with_path = iterator->data;
|
||||
const gchar *host_key_path = host_key_with_path->path;
|
||||
X509 *host_key = host_key_with_path->cert;
|
||||
gint flags = X509_V_FLAG_CRL_CHECK;
|
||||
|
||||
if (verify_host_key(host_key, ibm_z_pairs, flags,
|
||||
PV_CERTS_SECURITY_LEVEL, err) < 0) {
|
||||
g_prefix_error(err, "'%s': ", host_key_path);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
g_prefix_error(err, _("Failed to verify host-key document: "));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read in the keys or auto-generate them */
|
||||
static gint pv_img_set_keys(PvImage *img, const PvArgs *args, GError **err)
|
||||
{
|
||||
g_autoptr(X509_STORE) store = NULL;
|
||||
g_autoslist(x509_with_path) host_key_certs = NULL;
|
||||
|
||||
g_assert(img->xts_cipher);
|
||||
g_assert(img->cust_comm_cipher);
|
||||
@@ -285,8 +444,25 @@ static gint pv_img_set_keys(PvImage *img, const PvArgs *args, GError **err)
|
||||
if (!img->cust_pub_priv_key)
|
||||
return -1;
|
||||
|
||||
/* Load all host-key documents specified on the command line */
|
||||
host_key_certs = load_certificates((const gchar **)args->host_keys,
|
||||
err);
|
||||
if (!host_key_certs)
|
||||
return -1;
|
||||
|
||||
if (!args->no_verify &&
|
||||
pv_img_hostkey_verify(host_key_certs, args->root_ca_path,
|
||||
(const gchar * const *)args->crl_paths,
|
||||
(const gchar * const *)args->untrusted_cert_paths,
|
||||
args->offline, err) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Loads the public keys stored in the host-key documents and verify
|
||||
* that the correct elliptic curve is used.
|
||||
*/
|
||||
img->host_pub_keys =
|
||||
pv_img_get_host_keys(args->host_keys, store, img->nid, err);
|
||||
pv_img_get_host_keys(host_key_certs, img->nid, err);
|
||||
if (!img->host_pub_keys)
|
||||
return -1;
|
||||
|
||||
@@ -406,6 +582,9 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
||||
if (args->no_verify)
|
||||
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
||||
|
||||
if (args->root_ca_path)
|
||||
g_warning(_("A different root CA than the default DigiCert root CA is selected. Ensure that this root CA is trusted."));
|
||||
|
||||
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
||||
if (!ret->comps)
|
||||
return NULL;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,14 +11,18 @@
|
||||
#define PV_UTILS_CRYPTO_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/safestack.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -33,6 +37,9 @@
|
||||
#define AES_256_XTS_TWEAK_SIZE 16
|
||||
#define AES_256_XTS_KEY_SIZE 64
|
||||
|
||||
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
|
||||
#define CRL_DOWNLOAD_MAX_SIZE (1024 * 1024) /* in bytes */
|
||||
|
||||
enum PvCryptoMode {
|
||||
PV_ENCRYPT,
|
||||
PV_DECRYPT,
|
||||
@@ -40,7 +47,34 @@ enum PvCryptoMode {
|
||||
|
||||
typedef GSList HostKeyList;
|
||||
|
||||
/* play nice with g_autoptr */
|
||||
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
|
||||
typedef STACK_OF(X509) STACK_OF_X509;
|
||||
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
|
||||
|
||||
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
|
||||
void STACK_OF_X509_free(STACK_OF_X509 *stack);
|
||||
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
|
||||
|
||||
typedef struct {
|
||||
X509 *cert;
|
||||
const gchar *path;
|
||||
} x509_with_path;
|
||||
|
||||
x509_with_path *x509_with_path_new(X509 *cert, const gchar *path);
|
||||
void x509_with_path_free(x509_with_path *cert);
|
||||
|
||||
typedef struct {
|
||||
X509 *cert;
|
||||
STACK_OF_X509_CRL *crls;
|
||||
} x509_pair;
|
||||
|
||||
x509_pair *x509_pair_new(X509 **cert, STACK_OF_X509_CRL **crls);
|
||||
void x509_pair_free(x509_pair *pair);
|
||||
|
||||
/* Register auto cleanup functions */
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
|
||||
@@ -51,10 +85,18 @@ WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free);
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free);
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free);
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_pair, x509_pair_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_with_path, x509_with_path_free)
|
||||
|
||||
union cmp_index {
|
||||
struct {
|
||||
@@ -79,8 +121,37 @@ struct cipher_parms {
|
||||
const Buffer *iv_or_tweak;
|
||||
};
|
||||
|
||||
EVP_PKEY *read_ec_pubkey_cert(X509_STORE *store, gint nid, const gchar *path,
|
||||
GError **err);
|
||||
int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
|
||||
gint verify_flags, GError **err);
|
||||
void pv_crypto_init(void);
|
||||
void pv_crypto_cleanup(void);
|
||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void);
|
||||
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
||||
gint verify_flags, int level, GError **err);
|
||||
X509 *load_cert_from_file(const char *path, GError **err);
|
||||
X509_CRL *load_crl_from_file(const gchar *path, GError **err);
|
||||
GSList *load_certificates(const gchar *const *cert_paths, GError **err);
|
||||
STACK_OF_X509 *get_x509_stack(const GSList *x509_with_path_list);
|
||||
X509_STORE *store_setup(const gchar *root_ca_path,
|
||||
const gchar * const *crl_paths,
|
||||
GError **err);
|
||||
int store_set_verify_param(X509_STORE *store, GError **err);
|
||||
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
|
||||
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
|
||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
||||
const ASN1_OCTET_STRING *skid, GError **err);
|
||||
X509_NAME *c2b_name(const X509_NAME *name);
|
||||
|
||||
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
||||
STACK_OF_X509_CRL *store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert,
|
||||
GError **err);
|
||||
X509_STORE_CTX *create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain,
|
||||
GError **err);
|
||||
gint verify_cert(X509 *cert, X509_STORE_CTX *ctx, GError **err);
|
||||
X509_CRL *get_first_valid_crl(X509_STORE_CTX *ctx, X509 *cert, GError **err);
|
||||
void store_setup_crl_download(X509_STORE *st);
|
||||
EVP_PKEY *read_ec_pubkey_cert(X509 *cert, gint nid, GError **err);
|
||||
|
||||
Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
|
||||
Buffer *generate_aes_key(guint size, GError **err);
|
||||
Buffer *generate_aes_iv(guint size, GError **err);
|
||||
|
||||
121
genprotimg/src/utils/curl.c
Normal file
121
genprotimg/src/utils/curl.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Libcurl utils
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "pv/pv_error.h"
|
||||
|
||||
#include "curl.h"
|
||||
|
||||
struct UserData {
|
||||
GByteArray *buffer;
|
||||
guint max_size;
|
||||
};
|
||||
|
||||
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
g_assert(userdata);
|
||||
struct UserData *data = (struct UserData *)userdata;
|
||||
GByteArray *buffer = data->buffer;
|
||||
guint64 actual_size;
|
||||
size_t err;
|
||||
|
||||
g_assert(buffer);
|
||||
|
||||
if (!g_uint64_checked_mul(&actual_size, size, nmemb))
|
||||
g_abort();
|
||||
|
||||
/* Signal an error condition by returning a amount that differs
|
||||
* from the amount passed to the callback. This results in a
|
||||
* CURLE_WRITE_ERROR.
|
||||
*/
|
||||
err = actual_size + 1;
|
||||
|
||||
if (actual_size > G_MAXUINT)
|
||||
return err;
|
||||
|
||||
data->buffer = g_byte_array_append(buffer, (guchar *)ptr, (guint)actual_size);
|
||||
if (data->buffer->len > data->max_size)
|
||||
return err;
|
||||
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
gint curl_init(void)
|
||||
{
|
||||
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void curl_cleanup(void)
|
||||
{
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
|
||||
GError **err)
|
||||
{
|
||||
g_autoptr(GByteArray) ret = NULL;
|
||||
g_autoptr(CURL) handle = NULL;
|
||||
g_autofree gchar *agent = NULL;
|
||||
struct UserData userdata;
|
||||
CURLcode rc;
|
||||
|
||||
/* set up curl session */
|
||||
handle = curl_easy_init();
|
||||
if (!handle)
|
||||
g_abort();
|
||||
|
||||
/* follow redirection */
|
||||
rc = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1l);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, timeout_ms);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1l);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
agent = g_strdup_printf("%s/%s", tool_name, RELEASE_STRING);
|
||||
rc = curl_easy_setopt(handle, CURLOPT_USERAGENT, agent);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
ret = g_byte_array_new();
|
||||
userdata.buffer = ret;
|
||||
userdata.max_size = max_size;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&userdata);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
|
||||
rc = curl_easy_perform(handle);
|
||||
if (rc != CURLE_OK) {
|
||||
g_set_error(err, PV_ERROR, PV_ERROR_DOWNLOAD_FAILED,
|
||||
_("download failed: %s"), curl_easy_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
curl_err:
|
||||
g_set_error(err, PV_ERROR,
|
||||
PV_ERROR_CURL_INIT_FAILED,
|
||||
_("cURL initialization failed: %s"),
|
||||
curl_easy_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
25
genprotimg/src/utils/curl.h
Normal file
25
genprotimg/src/utils/curl.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Libcurl utils
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_UTILS_LIBCURL_H
|
||||
#define PV_UTILS_LIBCURL_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
|
||||
|
||||
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
|
||||
GError **err);
|
||||
gint curl_init(void);
|
||||
void curl_cleanup(void);
|
||||
|
||||
#endif /* PV_UTILS_LIBCURL_H */
|
||||
16
hsci/Makefile
Normal file
16
hsci/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
include ../common.mak
|
||||
|
||||
all:
|
||||
|
||||
install: hsci
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< hsci >$(DESTDIR)$(BINDIR)/hsci; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(BINDIR)/hsci; \
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/hsci; \
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 hsci.8 \
|
||||
$(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
clean:
|
||||
|
||||
.PHONY: all install clean
|
||||
436
hsci/hsci
Executable file
436
hsci/hsci
Executable file
@@ -0,0 +1,436 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# hsci - Tool to manage HiperSockets Converged Interfaces (HSCI)
|
||||
#
|
||||
# Copyright IBM Corp. 2020
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
|
||||
hsdev=""
|
||||
ndev=""
|
||||
hsci=""
|
||||
hsdev_mac=""
|
||||
hsif_pnetid=""
|
||||
netif_pnetid=""
|
||||
hsci_pnetid=""
|
||||
|
||||
function usage {
|
||||
cat <<-EOD
|
||||
Usage: hsci COMMAND [OPTION]
|
||||
|
||||
This tool is designed to control and show HSCI (HiperSockets Converged
|
||||
Interfaces) settings. A HiperSockets interface and an external network
|
||||
interface are converged into an HSCI interface.
|
||||
|
||||
COMMANDS
|
||||
add HIPERSOCKETS_DEV NET_DEV Adds an HSCI interface
|
||||
del HSCI_NAME Deletes an HSCI interface
|
||||
show Lists the configured HSCI interfaces
|
||||
|
||||
OPTIONS:
|
||||
-v, --version Prints the version number of the hsci tool and exits
|
||||
-h, --help Displays the help information for the command
|
||||
EOD
|
||||
}
|
||||
|
||||
function prereqs_check {
|
||||
if ! [ -x "$(command -v ip)" ]; then
|
||||
echo "Error: No iproute2 installed on this system" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function check_pnetids {
|
||||
# get PNETID of the HS
|
||||
local hsif_pnetids=""
|
||||
local netif_pnetids=""
|
||||
|
||||
if [ -e /sys/class/net/$hsdev/device/util_string ]; then
|
||||
hsif_pnetids="$(cat /sys/class/net/$hsdev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
else
|
||||
if [ -e /sys/class/net/$hsdev/device/chpid ]; then
|
||||
chpid="$(cat /sys/class/net/$hsdev/device/chpid | tr [:upper:] [:lower:])"
|
||||
hsif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
fi
|
||||
fi
|
||||
if [ "$hsif_pnetids" != "" ]; then
|
||||
port_hsif="$(cat /sys/class/net/$hsdev/dev_port)"
|
||||
(( idx=16*$port_hsif+1 ))
|
||||
(( end=$idx+15 ))
|
||||
hsif_pnetid="$(echo "$hsif_pnetids" | cut -c $idx-$end | tr -d ' ')"
|
||||
fi
|
||||
|
||||
# get PNETID of the NET_DEV
|
||||
if [ -e /sys/class/net/$ndev/device/util_string ]; then
|
||||
netif_pnetids="$(cat /sys/class/net/$ndev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
else
|
||||
if [ -e /sys/class/net/$ndev/device/chpid ]; then
|
||||
chpid="$(cat /sys/class/net/$ndev/device/chpid | tr [:upper:] [:lower:])"
|
||||
netif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
fi
|
||||
fi
|
||||
if [ "$netif_pnetids" != "" ]; then
|
||||
port_netif="$(cat /sys/class/net/$ndev/dev_port)"
|
||||
(( idx=16*$port_netif+1 ))
|
||||
(( end=$idx+15 ))
|
||||
netif_pnetid="$(echo "$netif_pnetids" | cut -c $idx-$end | tr -d ' ')"
|
||||
fi
|
||||
|
||||
#Check PNETIDs
|
||||
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" != "$hsif_pnetid" ]; then
|
||||
echo "Error: $hsdev and $ndev have different PNETIDs! They are $hsif_pnetid and $netif_pnetid respectively" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" == "$hsif_pnetid" ]; then
|
||||
hsci_pnetid=$hsif_pnetid
|
||||
fi
|
||||
}
|
||||
|
||||
function verify_precon {
|
||||
echo "Verifying net dev $ndev and HiperSockets dev $hsdev"
|
||||
|
||||
if [ ! -e /sys/class/net/$hsdev ]; then
|
||||
echo "Error: $hsdev does not exist" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$hsdev/device/card_type)" != "HiperSockets" ]; then
|
||||
echo "Error: $hsdev is not a HiperSockets device" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$hsdev/device/layer2)" != "1" ]; then
|
||||
echo "Error: $hsdev is not in layer 2 mode" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ ! -e /sys/class/net/$hsdev/device/vnicc/bridge_invisible ]; then
|
||||
echo "Error: Missing vnic-characteristics support" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$hsdev/device/vnicc/bridge_invisible)" == "n/a" ]; then
|
||||
echo "Error: $hsdev does not support vnicc" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $hsdev | grep UP | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsdev is not in state UP" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(bridge -d link show dev $hsdev self | grep learning_sync | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsdev does not support attribute learning_sync" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $hsdev | grep master | wc -l) -ne 0 ]; then
|
||||
echo "Error: $hsdev is already a bridge port" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#Pre-verify net_dev
|
||||
if [ ! -e /sys/class/net/$ndev ]; then
|
||||
echo "Error: $ndev does not exist" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$ndev/device/card_type)" == "HiperSockets" ]; then
|
||||
echo "Error: $ndev is also a HiperSockets device" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $ndev | grep UP | wc -l) -eq 0 ]; then
|
||||
echo "Error: $ndev is not in state UP" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $ndev | grep master | wc -l) -ne 0 ]; then
|
||||
echo "Error: $ndev is already a bridge port" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#Check PNETIDs
|
||||
check_pnetids
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function clean_up {
|
||||
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
|
||||
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible >/dev/null 2>&1
|
||||
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
|
||||
ip link del $hsci >/dev/null 2>&1
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
## add a new HSCI interface
|
||||
##############################################################################
|
||||
function add_hsci {
|
||||
|
||||
if [ $# != 2 ]; then
|
||||
echo "hsci: Invalid parameters" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
return 1
|
||||
fi
|
||||
hsdev=$1
|
||||
ndev=$2
|
||||
|
||||
#### Verify preconditions
|
||||
verify_precon
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
hsci_postfix="$(readlink /sys/class/net/$hsdev/device/cdev0 | tail -c5)"
|
||||
hsci=hsci$hsci_postfix
|
||||
|
||||
echo "Adding $hsci with a HiperSockets dev $hsdev and an external dev $ndev"
|
||||
|
||||
#### Create bridge
|
||||
ip link add name $hsci type bridge stp_state 0 >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not create a bridge" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#### Prepare hsdev
|
||||
# Set VNICC of hsdev to invisible
|
||||
#(mandatory for co-existence with HS-OSA bridges!)
|
||||
echo 1 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
||||
|
||||
#### Create bridge ports
|
||||
ip link set dev $ndev master $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not set master for $ndev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
ip link set dev $hsdev master $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not set master for $hsdev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# no forwarding between ndev and hsdev -> isolated on
|
||||
# ndev is default for outgoing unknown targets -> flood on
|
||||
# no need to learn external LAN targets into fdb -> learning off
|
||||
bridge link set dev $ndev isolated on learning off flood on mcast_flood on >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set bridge attributes on $ndev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# no forwarding between ndev and hsdev -> isolated on
|
||||
# fdb will be populated by dev-to-bridge-notification, no need to learn
|
||||
# -> learning off
|
||||
# only send to hsdev, if listed in fdb -> flood off
|
||||
# don't send MC/BC on hsdev -> mcast_flood off
|
||||
bridge link set dev $hsdev isolated on learning off flood off mcast_flood off >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set bridge attributes on $hsdev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# NOTE: Although not required, BCs will be sent out on hsdev.
|
||||
# NOTE: We need to receive BCs on hsdev, as z/OS HSCI does ARP requests on HS.
|
||||
|
||||
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
|
||||
echo "Set $hsdev MAC $hsdev_mac on $ndev and $hsci"
|
||||
|
||||
# set HS MAC on OSA as secondary MAC
|
||||
bridge fdb add $hsdev_mac dev $ndev >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set HS MAC on OSA as secondary MAC" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# set HS MAC (common MAC) on HSCI as primary MAC
|
||||
ip link set address $hsdev_mac dev $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set HiperSockets MAC (common MAC) on HSCI as primary MAC" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
ip link set dev $hsci up >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set $hsci up" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Turn on device for bridge notification
|
||||
bridge link set dev $hsdev learning_sync on self >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to turn on device for bridge notification" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
echo "Successfully added HSCI interface $hsci"
|
||||
return 0
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
## Delete HSCI
|
||||
##############################################################################
|
||||
|
||||
function del_hsci {
|
||||
if [ $# != 1 ]; then
|
||||
echo "hsci: invalid parameters" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
return 1
|
||||
fi
|
||||
hsci=$1
|
||||
if [ $(ip link show dev $hsci | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsci does not exit" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show | grep "master $hsci" | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsci is not an active HSCI interface" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
bports="$(ip link show | grep "master $hsci" | awk '{print $2}')"
|
||||
for bport in $bports; do
|
||||
bport=${bport%:}
|
||||
if [[ $bport == *@* ]]; then
|
||||
bport=${bport%@*}
|
||||
fi
|
||||
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
||||
hsdev=$bport
|
||||
else
|
||||
ndev=$bport
|
||||
fi
|
||||
done
|
||||
if [ "$hsdev" == "" ]; then
|
||||
echo "Error: $hsci has no active HiperSockets port" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "Deleting HSCI interface $hsci with the HiperSockets $hsdev and the external $ndev"
|
||||
|
||||
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to turn off learning_sync on $hsdev" >&2
|
||||
return 1
|
||||
fi
|
||||
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
||||
|
||||
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
|
||||
echo "Deleting $hsev MAC $hsdev_mac on $ndev"
|
||||
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to delete $hsev MAC $hsdev_mac on $ndev" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
ip link del $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to delete $hsci" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "Successfully deleted device $hsci"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
## Show HSCI
|
||||
##############################################################################
|
||||
|
||||
function list_active {
|
||||
hsdev=$1
|
||||
local ext=""
|
||||
|
||||
hsci="$(ip link show dev $hsdev | awk '{for(x=1;x<NF;x++) if($x~/master/) print $(x+1)}')"
|
||||
ext="$(ip link show | grep "master $hsci" | grep --invert-match $hsdev | awk '{print $2}')"
|
||||
# remove trailing ':'
|
||||
ndev="${ext%:}"
|
||||
|
||||
check_pnetids
|
||||
|
||||
printf '%-8s %-16s %-15s %-15s\n' "$hsci" "$hsci_pnetid" "$hsdev" "$ndev"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function print_header {
|
||||
if [ $header -eq 0 ]; then
|
||||
echo "HSCI PNET_ID HiperSockets External "
|
||||
echo "------------------------------------------------------------"
|
||||
fi
|
||||
}
|
||||
|
||||
function list_one {
|
||||
local hsnetdev=$1
|
||||
|
||||
if [ $(bridge -d link show dev $hsnetdev | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
||||
print_header
|
||||
list_active $hsnetdev
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function show_hsci {
|
||||
if [ $# != 0 ]; then
|
||||
echo "hsci: invalid parameters" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
return 1
|
||||
fi
|
||||
header=0
|
||||
|
||||
for hs_net_dev in $(ls -1 /sys/class/net/); do
|
||||
list_one $hs_net_dev
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
||||
function print_version()
|
||||
{
|
||||
echo "hsci utility: version %S390_TOOLS_VERSION%"
|
||||
echo "Copyright IBM Corp. 2020"
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
##### Main
|
||||
##############################################################################
|
||||
prereqs_check
|
||||
|
||||
args="$(getopt -u -o hv -l help,version -- $*)"
|
||||
[ $? -ne 0 ] && exit 2
|
||||
set -- $args
|
||||
while true; do
|
||||
case $1 in
|
||||
-v | --version)
|
||||
print_version
|
||||
exit 0
|
||||
;;
|
||||
-h | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--)
|
||||
;;
|
||||
add) shift
|
||||
add_hsci "$@"
|
||||
exit $?
|
||||
;;
|
||||
del) shift
|
||||
del_hsci "$@"
|
||||
exit $?
|
||||
;;
|
||||
show) shift
|
||||
show_hsci "$@"
|
||||
exit $?
|
||||
;;
|
||||
*) echo "hsci: Please specify a valid command or option" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
exit 1
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
100
hsci/hsci.8
Normal file
100
hsci/hsci.8
Normal file
@@ -0,0 +1,100 @@
|
||||
.\" Copyright IBM Corp. 2020
|
||||
|
||||
.TH HSCI 8 "November 2020" "s390-tools" "Linux Programmer's Manual"
|
||||
|
||||
|
||||
.SH NAME
|
||||
.B hsci
|
||||
\- control and show HSCI settings.
|
||||
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B hsci add
|
||||
.I HSDEV
|
||||
.I NETDEV
|
||||
.br
|
||||
.B hsci del
|
||||
.I HSCINAME
|
||||
.br
|
||||
.B hsci show
|
||||
.br
|
||||
.B hsci [\-hv]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.BI hsci
|
||||
is used to control and show HSCI (HiperSockets Converged Interfaces) settings. A HiperSockets interface and an external network interface are converged into an HSCI interface.
|
||||
|
||||
.SH COMMANDS
|
||||
.TP
|
||||
.B add \fIHSDEV\fR \fINETDEV\fR
|
||||
.RS .4i
|
||||
.PP
|
||||
Adds an HSCI interface
|
||||
.PP
|
||||
.I HSDEV
|
||||
is the interface name of the HiperSockets device to be converged into the HSCI interface.
|
||||
.PP
|
||||
.I NETDEV
|
||||
is the interface name of the external network device to be converged into the HSCI interface.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B del \fIHSCINAME\fR
|
||||
.RS .4i
|
||||
.PP
|
||||
Deletes an HSCI interface
|
||||
.PP
|
||||
.I HSCINAME
|
||||
is the name of the HSCI interface for the HiperSockets device and the external network device.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B show
|
||||
.RS .4i
|
||||
.PP
|
||||
Lists the configured HSCI interfaces.
|
||||
.RE
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-v ", " \-\-version
|
||||
Prints the version number of hsci and exits.
|
||||
.TP
|
||||
.BR \-h ", " \-\-help
|
||||
Displays the help information for the command.
|
||||
|
||||
.SH EXIT CODES
|
||||
.TP
|
||||
.BR "0"
|
||||
The hsci command ran successfully.
|
||||
|
||||
.TP
|
||||
.BR "1"
|
||||
An error occurred.
|
||||
|
||||
.SH EXAMPLE
|
||||
.BR "hsci show"
|
||||
.TP
|
||||
.RB
|
||||
Lists the configured HSCI interfaces:
|
||||
.RS 1.2i
|
||||
|
||||
HSCI PNET_ID HiperSockets External
|
||||
.br
|
||||
-----------------------------------------
|
||||
.br
|
||||
hsci8410 NET1 enc8410 encb040
|
||||
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
.nf
|
||||
ip(8), bridge(8)
|
||||
.fi
|
||||
|
||||
.SH AUTHOR
|
||||
.nf
|
||||
Written by Alexandra Winter <wintera@linux.ibm.com>
|
||||
Wenjia Zhang <wenjia@linux.ibm.com>
|
||||
.fi
|
||||
|
||||
@@ -21,7 +21,7 @@ clean: clean-recursive
|
||||
$(RECURSIVE_TARGETS):
|
||||
@target=`echo $@ |sed s/-recursive//`; \
|
||||
for d in $(SUBDIRS); do \
|
||||
(cd $$d && $(MAKE) $$target) \
|
||||
(cd $$d && $(MAKE) $$target) || exit 1; \
|
||||
done
|
||||
|
||||
|
||||
|
||||
@@ -77,11 +77,11 @@ libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o
|
||||
ln -srf libekmfweb.so.$(VERSION) libekmfweb.so
|
||||
|
||||
install-libekmfweb.so.$(VERSION): libekmfweb.so.$(VERSION)
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION)
|
||||
ln -srf $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERM)
|
||||
ln -srf $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION)
|
||||
ln -srf $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERM)
|
||||
ln -srf $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so
|
||||
$(INSTALL) -d -m 770 $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $(rootdir)include/ekmfweb/ekmfweb.h $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 $(rootdir)include/ekmfweb/ekmfweb.h $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb
|
||||
|
||||
install: all $(INSTALL_TARGETS)
|
||||
|
||||
|
||||
@@ -1061,6 +1061,12 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib,
|
||||
pr_verbose(verbose, "Failed to get and decode x");
|
||||
goto out;
|
||||
}
|
||||
if (len != prime_len) {
|
||||
/* RFC 7517: Must be full size of a coordinate */
|
||||
pr_verbose(verbose, "x coordinate length is wrong");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = prime_len;
|
||||
rc = json_object_get_base64url(jwk, "y", &q[1 + prime_len],
|
||||
@@ -1069,6 +1075,12 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib,
|
||||
pr_verbose(verbose, "Failed to get and decode y");
|
||||
goto out;
|
||||
}
|
||||
if (len != prime_len) {
|
||||
/* RFC 7517: Must be full size of a coordinate */
|
||||
pr_verbose(verbose, "y coordinate length is wrong");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rule_array_count = 1;
|
||||
memcpy(rule_array, "ECC-PUBL", CCA_KEYWORD_SIZE);
|
||||
|
||||
@@ -2254,11 +2254,21 @@ int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey)
|
||||
rc = json_object_get_base64url(jwk, "x", x, &len);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
if (len != prime_len) {
|
||||
/* RFC 7517: Must be full size of a coordinate */
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = prime_len;
|
||||
rc = json_object_get_base64url(jwk, "y", y, &len);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
if (len != prime_len) {
|
||||
/* RFC 7517: Must be full size of a coordinate */
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ecc_pub_key_as_pkey(nid, prime_len, x, y, pkey);
|
||||
if (rc != 0)
|
||||
|
||||
@@ -460,7 +460,7 @@ int util_proc_mnt_get_entry(const char *file_name, const char *spec,
|
||||
rc = scan_mnt_entry(&file, entry);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
if (!strcmp(entry->spec, spec)) {
|
||||
if (!strcmp(entry->vfstype, spec)) {
|
||||
rc = 0;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,27 @@
|
||||
|
||||
include ../common.mak
|
||||
|
||||
SCRIPTS = mk-s390image mk-pxelinux-ramfs
|
||||
NETBOOT_SAMPLEDIR=$(TOOLS_DATADIR)/netboot
|
||||
|
||||
all:
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR)
|
||||
$(INSTALL) -m 755 mk-s390image mk-pxelinux-ramfs \
|
||||
$(DESTDIR)$(NETBOOT_SAMPLEDIR)
|
||||
$(INSTALL) -m 644 Dockerfile Makefile.pxelinux.0 README.md \
|
||||
install: install-scripts
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 \
|
||||
Dockerfile Makefile.pxelinux.0 README.md mk-s390image.1 \
|
||||
$(DESTDIR)$(NETBOOT_SAMPLEDIR)
|
||||
|
||||
.PHONY: all install clean
|
||||
install-scripts: $(SCRIPTS)
|
||||
@if [ ! -d $(DESTDIR)$(NETBOOT_SAMPLEDIR) ]; then \
|
||||
mkdir -p $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
|
||||
chmod 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
|
||||
fi; \
|
||||
for i in $^; do \
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< $$i >$(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
|
||||
chmod 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
|
||||
done
|
||||
|
||||
.PHONY: all install clean install-scripts
|
||||
|
||||
@@ -21,7 +21,7 @@ ifeq ($(KERNEL_IMAGE),)
|
||||
$(error Could not find a kernel image under /boot)
|
||||
endif
|
||||
|
||||
BUSYBOX=busybox-1.27.1
|
||||
BUSYBOX=busybox-1.32.0
|
||||
BBINSTALL=$(BUSYBOX)/_install
|
||||
|
||||
all: $(KERNEL_IMAGE) pxelinux.initramfs
|
||||
|
||||
@@ -54,9 +54,18 @@ OPTIONS
|
||||
-b Search installed busybox in directory BUSYBOX_DIR
|
||||
-k Use KERNEL_VERSION instead of currently running kernel
|
||||
-h Print this help, then exit
|
||||
-v Print version information, then exit
|
||||
EOF
|
||||
}
|
||||
|
||||
printversion()
|
||||
{
|
||||
cat <<-EOD
|
||||
$cmd: version %S390_TOOLS_VERSION%
|
||||
Copyright IBM Corp. 2017
|
||||
EOD
|
||||
}
|
||||
|
||||
# Get shared objects for binary
|
||||
sharedobjs()
|
||||
{
|
||||
@@ -64,7 +73,7 @@ sharedobjs()
|
||||
}
|
||||
|
||||
# Check args
|
||||
args=$(getopt b:k:h $*)
|
||||
args=$(getopt b:k:hv $*)
|
||||
if [ $? = 0 ]
|
||||
then
|
||||
set -- $args
|
||||
@@ -74,6 +83,7 @@ then
|
||||
-b) busyboxdir=$2; shift 2;;
|
||||
-k) kernelversion=$2; shift 2;;
|
||||
-h) usage; exit 0;;
|
||||
-v) printversion; exit 0;;
|
||||
--) shift; break;;
|
||||
*) echo "$cmd: Unexpected argument $1, exiting..." >&2; exit 1;;
|
||||
esac
|
||||
|
||||
@@ -60,9 +60,18 @@ OPTIONS
|
||||
-p Use PARMFILE with kernel parameters in the image
|
||||
-r Include RAMDISK in the image
|
||||
-h Print this help, then exit
|
||||
-v Print version information, then exit
|
||||
EOF
|
||||
}
|
||||
|
||||
printversion()
|
||||
{
|
||||
cat <<-EOD
|
||||
$cmd: version %S390_TOOLS_VERSION%
|
||||
Copyright IBM Corp. 2017
|
||||
EOD
|
||||
}
|
||||
|
||||
# Convert decimal number to big endian doubleword
|
||||
dec2be64()
|
||||
{
|
||||
@@ -129,6 +138,9 @@ dobuild()
|
||||
parmfile_size=$(du -b $parmfile | cut -f1)
|
||||
if [ $parmfile_size -le $MAX_PARMFILE_SIZE ]
|
||||
then
|
||||
# Clear any previous parameters
|
||||
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 count=$MAX_PARMFILE_SIZE \
|
||||
if=/dev/zero of=$image conv=notrunc status=none
|
||||
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 if=$parmfile \
|
||||
of=$image conv=notrunc status=none
|
||||
else
|
||||
@@ -142,7 +154,7 @@ dobuild()
|
||||
}
|
||||
|
||||
# check args and build
|
||||
args=$(getopt "r:p:h" $*)
|
||||
args=$(getopt "r:p:hv" $*)
|
||||
if [ $? = 0 ]
|
||||
then
|
||||
set -- $args
|
||||
@@ -152,6 +164,7 @@ then
|
||||
-r) ramdisk=$2; shift 2;;
|
||||
-p) parmfile=$2; shift 2;;
|
||||
-h) usage; exit 0;;
|
||||
-v) printversion; exit 0;;
|
||||
--) shift; break;;
|
||||
*) echo "$cmd: Unexpected argument $1, exiting..." >&2; exit 1;;
|
||||
esac
|
||||
|
||||
17
netboot/mk-s390image.1
Normal file
17
netboot/mk-s390image.1
Normal file
@@ -0,0 +1,17 @@
|
||||
.TH MK-S390IMAGE "1" "November 2020" "s390-tools" "User Commands"
|
||||
.SH NAME
|
||||
mk-s390image \- tool for creating bootable image
|
||||
.SH SYNOPSIS
|
||||
.B mk-s390image
|
||||
\fI\,KERNEL BOOT_IMAGE \/\fR[\fI\,-r RAMDISK\/\fR] [\fI\,-p PARMFILE\/\fR]
|
||||
.SH DESCRIPTION
|
||||
Build an s390 image BOOT_IMAGE suitable for CD/tape/network boot or as a
|
||||
KVM firmware image using a stripped Linux kernel file KERNEL.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-p\fR Use PARMFILE with kernel parameters in the image
|
||||
.TP
|
||||
\fB\-r\fR Include RAMDISK in the image
|
||||
.TP
|
||||
\fB\-h\fR Print usage message, then exit
|
||||
@@ -227,6 +227,16 @@ sub get_common
|
||||
# function name or hexadecimal caller address.
|
||||
#
|
||||
$line =~ s/<\s+/</;
|
||||
#
|
||||
# Since crash 7.2.9 commit
|
||||
# https://github.com/crash-utility/crash/commit/f1f43bf355df2564543c39f5d7e13b15c67eb13d
|
||||
# in support of kernel v5.9 commit 0990d836cecb
|
||||
# ("s390/debug: debug feature version 3"),
|
||||
# the symbolic caller function name is left aligned instead of right
|
||||
# aligned, so now we alternatively have to remove whitespace between
|
||||
# function name and offset.
|
||||
#
|
||||
$line =~ s/<([^+> ]+)[ \t]+/<\1/;
|
||||
@common = split(/\s+/, $line);
|
||||
#
|
||||
# Process symbolic kernel module name, if necessary.
|
||||
@@ -388,6 +398,17 @@ sub get_foreign_records
|
||||
# caller address.
|
||||
#
|
||||
$line =~ s/<\s+/</;
|
||||
#
|
||||
# Since crash 7.2.9 commit
|
||||
# https://github.com/crash-utility/crash/commit/f1f43bf355df2564543c39f5d7e13b15c67eb13d
|
||||
# in support of kernel v5.9 commit 0990d836cecb
|
||||
# ("s390/debug: debug feature version 3"),
|
||||
# the symbolic caller function name is left aligned
|
||||
# instead of right aligned, so now we alternatively
|
||||
# have to remove whitespace between function name and
|
||||
# offset.
|
||||
#
|
||||
$line =~ s/<([^+> ]+)[ \t]+/<\1/;
|
||||
my @raw_rec = split(/\s+/,($line =~ /[|]/) ?
|
||||
substr($line, 0, index($line, '|')):
|
||||
$line);
|
||||
|
||||
@@ -10,10 +10,11 @@ zipl-switch-to-blscfg \- Switch zipl to use BootLoaderSpec configuration
|
||||
\fBzipl-switch-to-blscfg\fP {\-h|\-v}
|
||||
|
||||
.SH DESCRIPTION
|
||||
This script switches the zipl boot-loader configuration to use BootLoaderSpec files
|
||||
to define IPL sections. For each Linux kernel defined in the zipl.conf config file,
|
||||
a BLS fragment is generated in the BLS directory specified. Also, the zipl.conf is
|
||||
modified it only contains global configurations, all IPL sections comes from BLS.
|
||||
This script switches the zipl boot-loader configuration to use BootLoaderSpec
|
||||
files to define IPL sections. For each Linux kernel defined in the zipl.conf
|
||||
config file, a BLS fragment is generated in the BLS directory specified. Also,
|
||||
zipl.conf is modified to only contain global configuration. All IPL sections
|
||||
come from BLS files.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
@@ -30,7 +31,8 @@ The suffix used for backup files, defaults to .bak.
|
||||
|
||||
.TP
|
||||
\fB\-\-bls-directory <DIRECTORY>\fP
|
||||
The DIRECTORY where the BLS fragments will be generated. The directory is created if it doesn't exists, by default /boot/loader/entries is used.
|
||||
The DIRECTORY where the BLS fragments will be stored. The directory is
|
||||
created if it does not exist. By default /boot/loader/entries is used.
|
||||
|
||||
.TP
|
||||
\fB\-\-config-file <FILE>\fP
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
Description=Apply Control Program Identification (CPI)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=local-fs.target
|
||||
After=sysinit.target
|
||||
ConditionPathIsReadWrite=/sys/firmware/cpi
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
#
|
||||
# Specify a file with the environment variables using the EnvironmentFile=
|
||||
# service property.
|
||||
|
||||
@@ -387,6 +387,7 @@ function extended()
|
||||
read EXTSZ 2> /dev/null < $DEVPATH/extent_pool/extent_size
|
||||
read CAPACITY 2> /dev/null < $DEVPATH/capacity/logical_capacity
|
||||
read ALLOCATED 2> /dev/null < $DEVPATH/capacity/space_allocated
|
||||
read FC_SEC 2> /dev/null < $DEVPATH/fc_security
|
||||
|
||||
# convert to hexadecimal values
|
||||
PIM=0x$PIM
|
||||
@@ -521,7 +522,7 @@ function extended()
|
||||
elif [[ "$ALIAS" == 1 ]]; then
|
||||
if [[ "$BASEONLY" == "false" ]]; then
|
||||
ACTIVE="alias"
|
||||
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
|
||||
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
|
||||
"$SORTKEYLEN" "$SORTKEY" \
|
||||
"$BUSID" \
|
||||
"$ACTIVE" \
|
||||
@@ -532,6 +533,7 @@ function extended()
|
||||
"$ERP" \
|
||||
"$HPF" \
|
||||
"$DEV_UID" \
|
||||
"$FC_SEC" \
|
||||
"${INSTALLED_PATHS[@]}" \
|
||||
"${USED_PATHS[@]}" \
|
||||
"${NP_PATHS[@]}" \
|
||||
@@ -563,7 +565,7 @@ function extended()
|
||||
DISCIPLINE="${DISCIPLINE} (ESE)"
|
||||
fi
|
||||
|
||||
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
|
||||
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
|
||||
"$SORTKEYLEN" "$SORTKEY" \
|
||||
"$BUSID" \
|
||||
"$BLOCKNAME" \
|
||||
@@ -584,6 +586,7 @@ function extended()
|
||||
"$ERP" \
|
||||
"$HPF" \
|
||||
"$DEV_UID" \
|
||||
"$FC_SEC" \
|
||||
"${INSTALLED_PATHS[@]}" \
|
||||
"${USED_PATHS[@]}" \
|
||||
"${NP_PATHS[@]}" \
|
||||
|
||||
@@ -1178,8 +1178,14 @@ static int get_apqn_measurement_data(uint8_t card)
|
||||
scdmd_area.request.header.code = 0x102d;
|
||||
scdmd_area.request.header.length =
|
||||
sizeof(struct chsc_scdmd_request);
|
||||
scdmd_area.request.first_drid.ap_index = card;
|
||||
scdmd_area.request.first_drid.domain_index = g.min_domain;
|
||||
if (scdmd_area.response.p) {
|
||||
scdmd_area.request.first_drid =
|
||||
scdmd_area.response.crid;
|
||||
} else {
|
||||
scdmd_area.request.first_drid.ap_index = card;
|
||||
scdmd_area.request.first_drid.domain_index =
|
||||
g.min_domain;
|
||||
}
|
||||
scdmd_area.request.last_drid.ap_index = card;
|
||||
scdmd_area.request.last_drid.domain_index = g.max_domain;
|
||||
scdmd_area.request.s = 1;
|
||||
@@ -1217,10 +1223,6 @@ static int get_apqn_measurement_data(uint8_t card)
|
||||
rc = process_apqn_measurement_data(&scdmd_area);
|
||||
if (rc != 0)
|
||||
break;
|
||||
|
||||
if (scdmd_area.response.p)
|
||||
scdmd_area.request.first_drid =
|
||||
scdmd_area.response.crid;
|
||||
} while (scdmd_area.response.p);
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
|
||||
#include "exit_code.h"
|
||||
|
||||
exit_code_t root_check(void);
|
||||
exit_code_t initrd_check(bool all_pers);
|
||||
|
||||
#endif /* ROOT_H */
|
||||
|
||||
@@ -4,6 +4,16 @@ include ../../common.mak
|
||||
ALL_CPPFLAGS += -I ../include -std=gnu99 -Wno-unused-parameter \
|
||||
-Wno-missing-field-initializers
|
||||
|
||||
# Adding ZDEV_ALWAYS_UPDATE_INITRD=1 option will update the initial RAM-disk
|
||||
# without the user interaction upon the modification of a persistent device
|
||||
# configuration.
|
||||
|
||||
ifeq ($(ZDEV_ALWAYS_UPDATE_INITRD),1)
|
||||
ALL_CPPFLAGS += -DZDEV_ALWAYS_UPDATE_INITRD=true
|
||||
else
|
||||
ALL_CPPFLAGS += -DZDEV_ALWAYS_UPDATE_INITRD=false
|
||||
endif
|
||||
|
||||
# Core
|
||||
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
|
||||
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
||||
|
||||
@@ -3027,7 +3027,7 @@ int main(int argc, char *argv[])
|
||||
!dryrun) {
|
||||
/* If the root device/device type or early devices have been
|
||||
* modified, additional work might be necessary. */
|
||||
rc = root_check();
|
||||
rc = initrd_check(ZDEV_ALWAYS_UPDATE_INITRD);
|
||||
if (rc && !drc)
|
||||
drc = rc;
|
||||
}
|
||||
|
||||
@@ -313,6 +313,22 @@ static struct attrib dasd_attr_safe_offline = {
|
||||
.writeonly = 1,
|
||||
};
|
||||
|
||||
static struct attrib dasd_attr_fc_security = {
|
||||
.name = "fc_security",
|
||||
.title = "Show FC Endpoint Security state of DASD device",
|
||||
.desc =
|
||||
"This read-only attribute shows the Fibre Channel Endpoint Security\n"
|
||||
"status of the connection to the DASD device:\n"
|
||||
" Unsupported : The DASD device does not support Fibre Channel\n"
|
||||
" Endpoint Security\n"
|
||||
" Inconsistent : The operational channel paths of the DASD device\n"
|
||||
" report inconsistent Fibre Channel Endpoint\n"
|
||||
" Security status\n"
|
||||
" Authentication: The connection has been authenticated\n"
|
||||
" Encryption : The connection is encrypted\n",
|
||||
.readonly = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* DASD subtype methods.
|
||||
*/
|
||||
@@ -617,6 +633,7 @@ struct subtype dasd_subtype_eckd = {
|
||||
&dasd_attr_reservation_policy,
|
||||
&dasd_attr_last_known_reservation_state,
|
||||
&dasd_attr_safe_offline,
|
||||
&dasd_attr_fc_security,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
|
||||
@@ -58,11 +58,50 @@ static void add_early_removed(struct util_list *selected)
|
||||
}
|
||||
}
|
||||
|
||||
static void add_pers_removed(struct util_list *strlist)
|
||||
{
|
||||
int i, j;
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
struct device *dev;
|
||||
|
||||
for (i = 0; devtypes[i]; i++) {
|
||||
dt = devtypes[i];
|
||||
for (j = 0; dt->subtypes[j]; j++) {
|
||||
st = dt->subtypes[j];
|
||||
util_list_iterate(&st->devices->hash.list, dev) {
|
||||
if (dev->persistent.deconfigured) {
|
||||
strlist_add(strlist, "%s %s",
|
||||
dev->subtype->devname, dev->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_zdev_early_0(struct selected_dev_node *sel)
|
||||
{
|
||||
struct setting *s;
|
||||
struct device *dev;
|
||||
|
||||
dev = device_list_find(sel->st->devices, sel->id, NULL);
|
||||
if (!dev)
|
||||
return false;
|
||||
s = setting_list_find(dev->persistent.settings,
|
||||
internal_attr_early.name);
|
||||
if (!s)
|
||||
return false;
|
||||
if (s->specified && strcmp(s->value, "0") == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Determine if initial RAM-disk needs updating. If so, run the corresponding
|
||||
* scripts if available. */
|
||||
exit_code_t root_check(void)
|
||||
exit_code_t initrd_check(bool all_pers)
|
||||
{
|
||||
struct util_list *selected, *params, *mod = NULL;
|
||||
struct util_list *selected, *params, *mod = strlist_new();
|
||||
struct selected_dev_node *sel;
|
||||
struct device *dev;
|
||||
char *params_str;
|
||||
@@ -76,6 +115,20 @@ exit_code_t root_check(void)
|
||||
/* Get list of devices that provide the root device or require
|
||||
* early configuration. */
|
||||
selected = selected_dev_list_new();
|
||||
|
||||
if (all_pers) {
|
||||
/* Add all persistently configured devices. */
|
||||
select = select_opts_new();
|
||||
select->configured = 1;
|
||||
select_devices(select, selected, 1, 0, 0, config_persistent,
|
||||
scope_mandatory, err_ignore);
|
||||
select_opts_free(select);
|
||||
|
||||
/* Ensure that removed devices are considered. */
|
||||
add_pers_removed(mod);
|
||||
goto check_mod;
|
||||
}
|
||||
|
||||
/* First add devices that had zdev:early removed or changed to 0.
|
||||
* The subsequent call to select_devices() will filter out any
|
||||
* duplicates. */
|
||||
@@ -95,8 +148,8 @@ exit_code_t root_check(void)
|
||||
err_ignore);
|
||||
select_opts_free(select);
|
||||
|
||||
check_mod:
|
||||
/* Determine if any of the devices or device types has been modified. */
|
||||
mod = strlist_new();
|
||||
util_list_iterate(selected, sel) {
|
||||
dt = sel->st->devtype;
|
||||
|
||||
@@ -127,17 +180,22 @@ exit_code_t root_check(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ask for confirmation. */
|
||||
if (!confirm("Update initial RAM-disk now?")) {
|
||||
rc = EXIT_ABORTED;
|
||||
goto out;
|
||||
if (!all_pers) {
|
||||
/* Ask for confirmation. */
|
||||
if (!confirm("Update initial RAM-disk now?")) {
|
||||
rc = EXIT_ABORTED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build the command line. */
|
||||
params = strlist_new();
|
||||
util_list_iterate(selected, sel) {
|
||||
strlist_add(params, "%s", sel->st->name);
|
||||
strlist_add(params, "%s", sel->id);
|
||||
/* From the selected list, remove the devices with zdev:early=0 */
|
||||
if (!is_zdev_early_0(sel)) {
|
||||
strlist_add(params, "%s", sel->st->name);
|
||||
strlist_add(params, "%s", sel->id);
|
||||
}
|
||||
}
|
||||
params_str = strlist_flatten(params, " ");
|
||||
strlist_free(params);
|
||||
|
||||
@@ -407,7 +407,7 @@ void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
||||
if (size == 0)
|
||||
return;
|
||||
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
|
||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
|
||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
|
||||
l.mem_virt.chunk_cache->volnr = volnr;
|
||||
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ static int pt_load_add(Elf64_Phdr *phdr)
|
||||
STDERR("Dump file \"%s\" is a user space core dump\n",
|
||||
g.opts.device);
|
||||
}
|
||||
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
|
||||
return -EINVAL;
|
||||
if (phdr->p_filesz == 0) {
|
||||
/* Add zero memory chunk */
|
||||
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, NULL,
|
||||
@@ -52,8 +54,6 @@ static int pt_load_add(Elf64_Phdr *phdr)
|
||||
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, off_ptr,
|
||||
dfi_elf_mem_chunk_read_fn, zg_free);
|
||||
}
|
||||
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -280,6 +280,9 @@ off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
|
||||
{
|
||||
off_t rc;
|
||||
|
||||
if (off >= zg_fh->sb.st_size)
|
||||
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
|
||||
|
||||
rc = lseek(zg_fh->fh, off, SEEK_SET);
|
||||
if (rc == -1 && check != ZG_CHECK_NONE)
|
||||
ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);
|
||||
|
||||
@@ -3,6 +3,9 @@ include ../common.mak
|
||||
CPIOINIT = $(call echocmd," CPIOINI ",/$@)./cpioinit
|
||||
INSTALL_SCRIPTS = 10-zfcpdump.install
|
||||
|
||||
ALL_CFLAGS += -fno-sanitize=all
|
||||
ALL_LDFLAGS += -fno-sanitize=all
|
||||
|
||||
ifeq (${HAVE_LIBC_STATIC},0)
|
||||
|
||||
all:
|
||||
|
||||
@@ -10,7 +10,8 @@ ALL_CFLAGS = $(NO_PIE_CFLAGS) -Os -g $(INCLUDE_PARMS) \
|
||||
-fno-delete-null-pointer-checks -fno-stack-protector \
|
||||
-fexec-charset=IBM1047 -m64 -mpacked-stack \
|
||||
-mstack-size=4096 -mstack-guard=128 -msoft-float \
|
||||
-W -Wall -Wformat-security
|
||||
-W -Wall -Wformat-security -fno-sanitize=all
|
||||
ALL_LDFLAGS += -fno-sanitize=all
|
||||
|
||||
FILES = fba0.bin fba1b.bin fba2.bin \
|
||||
eckd0_ldl.bin eckd0_cdl.bin \
|
||||
|
||||
@@ -449,13 +449,14 @@ void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count)
|
||||
* block number
|
||||
*/
|
||||
unsigned long write_dump_segment(unsigned long blk,
|
||||
struct df_s390_dump_segm_hdr *segm,
|
||||
unsigned long zero_page)
|
||||
struct df_s390_dump_segm_hdr *segm)
|
||||
{
|
||||
unsigned long addr, start_blk, blk_count;
|
||||
unsigned long addr, start_blk, blk_count, zero_page;
|
||||
|
||||
/* Write the dump segment header itself (1 page) */
|
||||
zero_page = get_zeroed_page();
|
||||
writeblock(blk, (unsigned long)segm, m2b(PAGE_SIZE), zero_page);
|
||||
free_page(zero_page);
|
||||
blk += m2b(PAGE_SIZE);
|
||||
/* Write the dump segment */
|
||||
addr = segm->start;
|
||||
@@ -464,7 +465,9 @@ unsigned long write_dump_segment(unsigned long blk,
|
||||
/* Remaining blocks to write */
|
||||
blk_count = m2b(segm->len) - (blk - start_blk);
|
||||
blk_count = MIN(blk_count, eckd_blk_max);
|
||||
zero_page = get_zeroed_page();
|
||||
writeblock(blk, addr, blk_count, zero_page);
|
||||
free_page(zero_page);
|
||||
progress_print(addr);
|
||||
blk += blk_count;
|
||||
addr += b2m(blk_count);
|
||||
|
||||
@@ -48,7 +48,6 @@ void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
|
||||
unsigned long zero_page);
|
||||
void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count);
|
||||
unsigned long write_dump_segment(unsigned long blk,
|
||||
struct df_s390_dump_segm_hdr *segm,
|
||||
unsigned long zero_page);
|
||||
struct df_s390_dump_segm_hdr *segm);
|
||||
|
||||
#endif /* ECKD2DUMP_H */
|
||||
|
||||
@@ -192,10 +192,13 @@ void dt_device_enable(void)
|
||||
* Check for the volume timestamp and validate the dump signature
|
||||
* before writing a dump.
|
||||
*/
|
||||
static void check_volume(unsigned long page)
|
||||
static void check_volume(void)
|
||||
{
|
||||
struct mvdump_parm_table *mvdump_table_new;
|
||||
struct df_s390_hdr *hdr_new;
|
||||
unsigned long page;
|
||||
|
||||
page = get_zeroed_page();
|
||||
|
||||
/*
|
||||
* Check whether parameter table on dump device has a valid
|
||||
@@ -222,6 +225,8 @@ static void check_volume(unsigned long page)
|
||||
if (dump_hdr->magic != hdr_new->mvdump_sign)
|
||||
panic(ENOSIGN, "Wrong signature");
|
||||
}
|
||||
|
||||
free_page(page);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -229,10 +234,10 @@ static void check_volume(unsigned long page)
|
||||
* address to write for the next volume or memory size if the dump ended
|
||||
* on this volume
|
||||
*/
|
||||
static unsigned long write_volume(unsigned long addr, unsigned long page,
|
||||
static unsigned long write_volume(unsigned long addr,
|
||||
struct df_s390_dump_segm_hdr *dump_segm)
|
||||
{
|
||||
unsigned long free_space, blk;
|
||||
unsigned long free_space, blk, page;
|
||||
|
||||
/*
|
||||
* Write dump header
|
||||
@@ -245,7 +250,7 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
|
||||
* header and the end marker)
|
||||
*/
|
||||
free_space = b2m(device.blk_end - blk + 1) - b2m(2);
|
||||
memset((void *) page, 0, PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Write dump data
|
||||
*/
|
||||
@@ -257,7 +262,7 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
|
||||
addr = find_dump_segment(addr, dump_hdr->mem_size,
|
||||
ROUND_DOWN(free_space, MIB),
|
||||
dump_segm);
|
||||
blk = write_dump_segment(blk, dump_segm, page);
|
||||
blk = write_dump_segment(blk, dump_segm);
|
||||
/* Update free space left on vol */
|
||||
free_space -= dump_segm->len;
|
||||
/* Reserve one block for the next segment header */
|
||||
@@ -267,8 +272,10 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
|
||||
/* Check if no more dump segments follow */
|
||||
if (dump_segm->stop_marker) {
|
||||
/* Write end marker */
|
||||
page = get_zeroed_page();
|
||||
df_s390_em_page_init(page);
|
||||
writeblock(blk, page, 1, 0);
|
||||
free_page(page);
|
||||
return dump_hdr->mem_size;
|
||||
}
|
||||
/*
|
||||
@@ -286,19 +293,18 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
|
||||
void dt_dump_mem(void)
|
||||
{
|
||||
struct df_s390_dump_segm_hdr *dump_segm;
|
||||
unsigned long addr, page;
|
||||
unsigned long addr;
|
||||
|
||||
dump_hdr->mvdump_sign = DF_S390_MAGIC_EXT;
|
||||
dump_hdr->mvdump = 1;
|
||||
addr = 0;
|
||||
total_dump_size = 0;
|
||||
page = get_zeroed_page();
|
||||
dump_segm = (void *)get_zeroed_page();
|
||||
|
||||
while (1) {
|
||||
printf("Dumping to: 0.%x.%04x", device.sid.ssid, device.devno);
|
||||
check_volume(page);
|
||||
addr = write_volume(addr, page, dump_segm);
|
||||
check_volume();
|
||||
addr = write_volume(addr, dump_segm);
|
||||
if (addr == dump_hdr->mem_size)
|
||||
break;
|
||||
/*
|
||||
@@ -312,7 +318,6 @@ void dt_dump_mem(void)
|
||||
set_device(device.sid, DISABLED);
|
||||
dt_device_enable();
|
||||
}
|
||||
progress_print(addr);
|
||||
free_page(page);
|
||||
free_page(__pa(dump_segm));
|
||||
progress_print(addr);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ void dt_dump_mem(void)
|
||||
struct df_s390_dump_segm_hdr *dump_segm;
|
||||
|
||||
blk = device.blk_start;
|
||||
page = get_zeroed_page();
|
||||
dump_segm = (void *)get_zeroed_page();
|
||||
|
||||
/* Write dump header */
|
||||
@@ -79,18 +78,19 @@ void dt_dump_mem(void)
|
||||
end = dump_hdr->mem_size;
|
||||
while (addr < end) {
|
||||
addr = find_dump_segment(addr, end, 0, dump_segm);
|
||||
blk = write_dump_segment(blk, dump_segm, page);
|
||||
blk = write_dump_segment(blk, dump_segm);
|
||||
total_dump_size += dump_segm->len;
|
||||
if (dump_segm->stop_marker) {
|
||||
addr = end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_page(__pa(dump_segm));
|
||||
progress_print(addr);
|
||||
|
||||
/* Write end marker */
|
||||
page = get_zeroed_page();
|
||||
df_s390_em_page_init(page);
|
||||
writeblock(blk, page, 1, 0);
|
||||
free_page(page);
|
||||
free_page(__pa(dump_segm));
|
||||
}
|
||||
|
||||
@@ -141,13 +141,14 @@ static void writeblock_fba(unsigned long blk, unsigned long addr,
|
||||
* block number
|
||||
*/
|
||||
unsigned long write_dump_segment_fba(unsigned long blk,
|
||||
struct df_s390_dump_segm_hdr *dump_segm,
|
||||
unsigned long zero_page)
|
||||
struct df_s390_dump_segm_hdr *dump_segm)
|
||||
{
|
||||
unsigned long addr, start_blk, blk_count;
|
||||
unsigned long addr, start_blk, blk_count, zero_page;
|
||||
|
||||
/* Write the dump segment header itself (1 page) */
|
||||
zero_page = get_zeroed_page();
|
||||
writeblock_fba(blk, __pa(dump_segm), BLK_PER_PAGE, zero_page);
|
||||
free_page(zero_page);
|
||||
blk += BLK_PER_PAGE;
|
||||
/* Write the dump segment */
|
||||
addr = dump_segm->start;
|
||||
@@ -156,7 +157,9 @@ unsigned long write_dump_segment_fba(unsigned long blk,
|
||||
/* Remaining blocks to write */
|
||||
blk_count = m2b(dump_segm->len) - (blk - start_blk);
|
||||
blk_count = MIN(blk_count, BLK_PWRT);
|
||||
zero_page = get_zeroed_page();
|
||||
writeblock_fba(blk, addr, blk_count, zero_page);
|
||||
free_page(zero_page);
|
||||
progress_print(addr);
|
||||
blk += blk_count;
|
||||
addr += b2m(blk_count);
|
||||
@@ -198,7 +201,6 @@ void dt_dump_mem(void)
|
||||
|
||||
ccw_program_init();
|
||||
blk = device.blk_start;
|
||||
page = get_zeroed_page();
|
||||
dump_segm = (void *)get_zeroed_page();
|
||||
|
||||
/* Write dump header */
|
||||
@@ -211,18 +213,19 @@ void dt_dump_mem(void)
|
||||
end = dump_hdr->mem_size;
|
||||
while (addr < end) {
|
||||
addr = find_dump_segment(addr, end, 0, dump_segm);
|
||||
blk = write_dump_segment_fba(blk, dump_segm, page);
|
||||
blk = write_dump_segment_fba(blk, dump_segm);
|
||||
total_dump_size += dump_segm->len;
|
||||
if (dump_segm->stop_marker) {
|
||||
addr = end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_page(__pa(dump_segm));
|
||||
progress_print(addr);
|
||||
|
||||
/* Write end marker */
|
||||
page = get_zeroed_page();
|
||||
df_s390_em_page_init(page);
|
||||
writeblock_fba(blk, page, 1, 0);
|
||||
free_page(page);
|
||||
free_page(__pa(dump_segm));
|
||||
}
|
||||
|
||||
@@ -32,9 +32,10 @@ struct ex_table_entry {
|
||||
};
|
||||
|
||||
#define MEM_ALLOC_START ((unsigned long) __heap_start)
|
||||
#define MEM_ALLOC_CNT 4
|
||||
#define MEM_ALLOC_END ((unsigned long) __heap_stop)
|
||||
#define MEM_ALLOC_MAX 4
|
||||
|
||||
static uint8_t mem_page_alloc_vec[MEM_ALLOC_CNT];
|
||||
static uint8_t mem_page_alloc_vec[MEM_ALLOC_MAX];
|
||||
|
||||
/*
|
||||
* Initialize memory with value
|
||||
@@ -417,10 +418,11 @@ void printf(const char *fmt, ...)
|
||||
*/
|
||||
unsigned long get_zeroed_page(void)
|
||||
{
|
||||
const int page_count = MIN(MEM_ALLOC_MAX, (int)((MEM_ALLOC_END - MEM_ALLOC_START) / PAGE_SIZE));
|
||||
unsigned long addr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MEM_ALLOC_CNT; i++) {
|
||||
for (i = 0; i < page_count; i++) {
|
||||
if (mem_page_alloc_vec[i] != 0)
|
||||
continue;
|
||||
addr = MEM_ALLOC_START + i * PAGE_SIZE;
|
||||
@@ -436,6 +438,9 @@ unsigned long get_zeroed_page(void)
|
||||
*/
|
||||
void free_page(unsigned long addr)
|
||||
{
|
||||
if (addr < MEM_ALLOC_START || addr >= MEM_ALLOC_END)
|
||||
libc_stop(EINTERNAL);
|
||||
|
||||
mem_page_alloc_vec[(addr - MEM_ALLOC_START) / PAGE_SIZE] = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ void start(void)
|
||||
void *load_address;
|
||||
struct component_entry *entry;
|
||||
disk_blockptr_t *blockptr;
|
||||
uint64_t load_psw;
|
||||
void *load_page;
|
||||
int config_nr;
|
||||
|
||||
@@ -133,11 +134,13 @@ void start(void)
|
||||
if (entry->type != COMPONENT_EXECUTE)
|
||||
panic(EWRONGTYPE, "");
|
||||
|
||||
load_psw = entry->address.load_psw;
|
||||
|
||||
free_page((unsigned long)load_page);
|
||||
io_irq_disable();
|
||||
set_device(subchannel_id, DISABLED);
|
||||
|
||||
execute(entry->address.load_psw);
|
||||
execute(load_psw);
|
||||
}
|
||||
|
||||
void panic_notify(unsigned long UNUSED(reason))
|
||||
|
||||
@@ -444,6 +444,9 @@ type_determined:
|
||||
}
|
||||
/* Convert device size to size in physical blocks */
|
||||
data->phy_blocks = devsize / (data->phy_block_size / 512);
|
||||
/* Adjust start on SCSI according to block_size. device-mapper devices are skipped */
|
||||
if (data->type == disk_type_scsi && target->targetbase == NULL)
|
||||
data->geo.start = data->geo.start / (data->phy_block_size / 512);
|
||||
if (data->partnum != 0)
|
||||
data->partition = stats.st_rdev;
|
||||
/* Try to get device name */
|
||||
|
||||
@@ -34,6 +34,8 @@ endif
|
||||
|
||||
libs = $(rootdir)/libutil/libutil.a
|
||||
|
||||
CFLAGS += -DKMS_PLUGIN_LOCATION=\"$(ZKEYKMSPLUGINDIR)\"
|
||||
|
||||
detect-libcryptsetup.dep:
|
||||
echo "#include <libcryptsetup.h>" > detect-libcryptsetup.dep
|
||||
echo "#ifndef CRYPT_LUKS2" >> detect-libcryptsetup.dep
|
||||
|
||||
@@ -7,8 +7,6 @@ all: zkey-ekmfweb.so
|
||||
|
||||
libs = $(rootdir)/libutil/libutil.a
|
||||
|
||||
export LIBRARY_PATH = $(rootdir)/libekmfweb:$LIBRARY_PATH
|
||||
|
||||
zkey-ekmfweb.o: zkey-ekmfweb.c zkey-ekmfweb.h ../kms-plugin.h \
|
||||
../cca.h ../utils.h ../pkey.h ../properties.h \
|
||||
$(rootdir)include/ekmfweb/ekmfweb.h libekmfweb.dep
|
||||
@@ -29,7 +27,7 @@ utils.o: ../utils.c ../utils.h ../pkey.h ../cca.h ../ep11.h
|
||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
|
||||
|
||||
zkey-ekmfweb.so: ALL_CFLAGS += -fPIC
|
||||
zkey-ekmfweb.so: LDLIBS = -lekmfweb -ldl -lcrypto
|
||||
zkey-ekmfweb.so: LDLIBS = -L$(rootdir)/libekmfweb -lekmfweb -ldl -lcrypto
|
||||
zkey-ekmfweb.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-ekmfweb.map \
|
||||
-Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-ekmfweb.so.$(VERM)
|
||||
zkey-ekmfweb.so: zkey-ekmfweb.o properties.o pkey.o cca.o ep11.o utils.o $(libs)
|
||||
@@ -46,9 +44,8 @@ libekmfweb.dep:
|
||||
install: all install-libekmfweb.dep zkey-ekmfweb.so
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
|
||||
$(INSTALL) -m 644 -c zkey-ekmfweb.1 $(DESTDIR)$(MANDIR)/man1
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRLIB64DIR)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRLIB64DIR)/zkey
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T zkey-ekmfweb.so $(DESTDIR)$(USRLIB64DIR)/zkey/zkey-ekmfweb.so
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(ZKEYKMSPLUGINDIR)
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T zkey-ekmfweb.so $(DESTDIR)$(ZKEYKMSPLUGINDIR)/zkey-ekmfweb.so
|
||||
|
||||
clean:
|
||||
rm -f *.o zkey-ekmfweb.so install-libekmfweb.dep libekmfweb.dep
|
||||
|
||||
@@ -321,7 +321,7 @@ Specifies the subject name for generating a certificate signing request (CSR)
|
||||
or self signed certificate, in the form
|
||||
\fB<type>=<value>(;<type>=<value>)*[;]\fP with types recognized by OpenSSL.
|
||||
.TP
|
||||
.BR \-s ", " \-\-cert\-extensions\~\fIextensions\fP
|
||||
.BR \-e ", " \-\-cert\-extensions\~\fIextensions\fP
|
||||
Specifies the certificate extensions for generating a certificate signing
|
||||
request (CSR) or self signed certificate, in the form
|
||||
\fB<name>=[critical,]<value(s)>(;<name>=[critical,]<value(s)>)*[;]\fP
|
||||
@@ -416,7 +416,7 @@ Configures the connection to the EKMF Web server on 'my.ekmfweb.server'.
|
||||
.B zkey kms configure \-\-ekmfweb\-url https://my.ekmfweb.server \-\-tls\-pin\-server\-pubkey \-\-tls\-verify\-hostname
|
||||
Configures the connection to the EKMF Web server on 'my.ekmfweb.server' and
|
||||
pins the server's public key from the server's TSL certificate as well as
|
||||
enables verification of the host nmae to match the server's Common Name in the
|
||||
enables verification of the host name to match the server's Common Name in the
|
||||
certificate.
|
||||
.TP
|
||||
.B zkey kms configure \-\-gen\-csr csr.pem \-\-cert\-subject \(dqCN=my.zkey.client;OU=Example;C=US\(dq
|
||||
@@ -437,10 +437,10 @@ subject name and a certificate extension to limit the key usage, and stores it
|
||||
in file 'cert.pem'.
|
||||
.TP
|
||||
.B zkey kms configure \-\-register cert.pem
|
||||
Registers the zkey client with EKMF Web using the certifcate in file 'cert.pem'.
|
||||
Registers the zkey client with EKMF Web using the certificate in file 'cert.pem'.
|
||||
.TP
|
||||
.B zkey kms configure \-\-register cert.pem \-\-label\-tags \(dqENV=TEST,APP=LINUX\(dq
|
||||
Registers the zkey client with EKMF Web using the certifcate in file 'cert.pem'
|
||||
Registers the zkey client with EKMF Web using the certificate in file 'cert.pem'
|
||||
and the label tags 'ENV=TEST' and 'APP=LINUX' for the identity key.
|
||||
.TP
|
||||
.B zkey kms info
|
||||
@@ -480,7 +480,7 @@ client is allowed to use it or not.
|
||||
.TP
|
||||
.B zkey kms list \-\-label \(dq*LUKS2*\(dq
|
||||
Displays eligible secure keys managed by EKMF Web where the label name in EKMF
|
||||
Web contains the work 'LUKS2'.
|
||||
Web contains the word 'LUKS2'.
|
||||
.TP
|
||||
.B zkey kms import \-\-name seckey
|
||||
Imports the secure key managed by EKMF Web with a zkey name of 'seckey'.
|
||||
|
||||
@@ -899,24 +899,24 @@ int kms_display_info(const kms_handle_t handle)
|
||||
if (rc == 0) {
|
||||
switch (type) {
|
||||
case EVP_PKEY_EC:
|
||||
printf(" EBMF Web public key: ECC (%s)\n",
|
||||
printf(" EKMF Web public key: ECC (%s)\n",
|
||||
OBJ_nid2sn(curve));
|
||||
break;
|
||||
case EVP_PKEY_RSA:
|
||||
printf(" EBMF Web public key: RSA "
|
||||
printf(" EKMF Web public key: RSA "
|
||||
"(%d bits)\n", mod_bits);
|
||||
break;
|
||||
default:
|
||||
printf(" EBMF Web public key: "
|
||||
printf(" EKMF Web public key: "
|
||||
"(unknown key type)\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf(" EBMF Web public key: (not available)\n");
|
||||
printf(" EKMF Web public key: (not available)\n");
|
||||
}
|
||||
free(tmp);
|
||||
} else {
|
||||
printf(" EBMF Web public key: (configuration required)\n");
|
||||
printf(" EKMF Web public key: (configuration required)\n");
|
||||
}
|
||||
|
||||
printf(" Key templates:\n");
|
||||
@@ -2520,7 +2520,7 @@ static int _configure_connection(struct plugin_handle *ph,
|
||||
"[y/N]? ",
|
||||
program_invocation_short_name);
|
||||
if (!prompt_for_yes(ph->verbose)) {
|
||||
_set_error(ph, "Opertion aborted by user");
|
||||
_set_error(ph, "Operation aborted by user");
|
||||
return -ECANCELED;
|
||||
}
|
||||
}
|
||||
@@ -2651,10 +2651,10 @@ static int _configure_connection(struct plugin_handle *ph,
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
printf("%s: Is this the EKMF Web server you intent to work with "
|
||||
printf("%s: Is this the EKMF Web server you intend to work with "
|
||||
"[y/N]? ", program_invocation_short_name);
|
||||
if (!prompt_for_yes(ph->verbose)) {
|
||||
_set_error(ph, "Opertion aborted by user");
|
||||
_set_error(ph, "Operation aborted by user");
|
||||
rc = -ECANCELED;
|
||||
goto out;
|
||||
}
|
||||
@@ -2948,7 +2948,7 @@ static int _generate_identity_key(struct plugin_handle *ph)
|
||||
printf("%s: Re-generate the identity key [y/N]? ",
|
||||
program_invocation_short_name);
|
||||
if (!prompt_for_yes(ph->verbose)) {
|
||||
_set_error(ph, "Opertion aborted by user");
|
||||
_set_error(ph, "Operation aborted by user");
|
||||
return -ECANCELED;
|
||||
}
|
||||
} else {
|
||||
@@ -3347,45 +3347,6 @@ static void _free_ekmf_tags(struct ekmf_tag_list *ekmf_tag_list)
|
||||
ekmf_tag_list->num_tags = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next sequence number of the template
|
||||
*
|
||||
* @param ph the plugin handle
|
||||
* @param template_uuid the template UUID
|
||||
*
|
||||
* @returns an allocated string, or NULL in case of an error.
|
||||
*/
|
||||
static char *_get_seqno(struct plugin_handle *ph, const char *template_uuid)
|
||||
{
|
||||
unsigned int seqno = 0;
|
||||
char *error_msg = NULL;
|
||||
char *ret = NULL;
|
||||
int rc;
|
||||
|
||||
rc = ekmf_get_last_seq_no(&ph->ekmf_config, &ph->curl_handle,
|
||||
template_uuid, &seqno, &error_msg,
|
||||
ph->verbose);
|
||||
if (rc != 0) {
|
||||
_set_error(ph, "Failed to get last used sequence number for "
|
||||
"template '%s': %s",
|
||||
template_uuid, error_msg != NULL ? error_msg :
|
||||
strerror(-rc));
|
||||
_remove_login_token_if_error(ph, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
seqno++;
|
||||
util_asprintf(&ret, "%05u", seqno);
|
||||
|
||||
pr_verbose(ph, "Seqno: '%s'", ret);
|
||||
|
||||
out:
|
||||
if (error_msg != NULL)
|
||||
free(error_msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the label tags passed in via option (<tag>=<value>;<tag>=<value;....)
|
||||
* and allocates an array of KMS properties. The tags must be freed by the
|
||||
@@ -3450,25 +3411,16 @@ static int _parse_label_tags(struct plugin_handle *ph,
|
||||
if (value != NULL) {
|
||||
ekmf_tag_list->tags[i].value =
|
||||
util_strdup(value);
|
||||
util_str_toupper((char *)
|
||||
ekmf_tag_list->tags[i].value);
|
||||
} else {
|
||||
ekmf_tag_list->tags[i].value =
|
||||
_get_seqno(ph,
|
||||
template_info->uuid);
|
||||
if (ekmf_tag_list->tags[i].value ==
|
||||
NULL) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
util_strdup(EKMFWEB_SEQNO_NEXT);
|
||||
}
|
||||
k++;
|
||||
} else {
|
||||
ekmf_tag_list->tags[i].value =
|
||||
_get_seqno(ph,
|
||||
template_info->uuid);
|
||||
if (ekmf_tag_list->tags[i].value == NULL) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
util_strdup(EKMFWEB_SEQNO_NEXT);
|
||||
}
|
||||
} else {
|
||||
if (tag == NULL) {
|
||||
@@ -3504,11 +3456,10 @@ static int _parse_label_tags(struct plugin_handle *ph,
|
||||
}
|
||||
|
||||
ekmf_tag_list->tags[i].value = util_strdup(value);
|
||||
util_str_toupper((char *)ekmf_tag_list->tags[i].value);
|
||||
k++;
|
||||
}
|
||||
|
||||
util_str_toupper((char *)ekmf_tag_list->tags[i].value);
|
||||
|
||||
pr_verbose(ph, "Tag: '%s', Value: '%s'",
|
||||
ekmf_tag_list->tags[i].name,
|
||||
ekmf_tag_list->tags[i].value);
|
||||
@@ -3649,7 +3600,7 @@ static int _register_client(struct plugin_handle *ph, const char *cert_file,
|
||||
printf("%s: Re-register the zkey client [y/N]? ",
|
||||
program_invocation_short_name);
|
||||
if (!prompt_for_yes(ph->verbose)) {
|
||||
_set_error(ph, "Opertion aborted by user");
|
||||
_set_error(ph, "Operation aborted by user");
|
||||
return -ECANCELED;
|
||||
}
|
||||
}
|
||||
@@ -4566,22 +4517,23 @@ static int _properties_to_ekmf_tags(struct plugin_handle *UNUSED(ph),
|
||||
struct ekmf_tag_list *ekmf_tag_list,
|
||||
bool null_values_only)
|
||||
{
|
||||
size_t i;
|
||||
size_t i, k;
|
||||
|
||||
ekmf_tag_list->num_tags = 0;
|
||||
ekmf_tag_list->tags = util_malloc(
|
||||
sizeof(struct ekmf_tag) * num_properties);
|
||||
|
||||
for (i = 0; i < num_properties; i++) {
|
||||
for (i = 0, k = 0; i < num_properties; i++) {
|
||||
if (!null_values_only && properties[i].value == NULL)
|
||||
continue;
|
||||
if (null_values_only && properties[i].value != NULL)
|
||||
continue;
|
||||
|
||||
ekmf_tag_list->tags[i].name = util_strdup(properties[i].name);
|
||||
ekmf_tag_list->tags[i].value = properties[i].value != NULL ?
|
||||
ekmf_tag_list->tags[k].name = util_strdup(properties[i].name);
|
||||
ekmf_tag_list->tags[k].value = properties[i].value != NULL ?
|
||||
util_strdup(properties[i].value) : NULL;
|
||||
ekmf_tag_list->num_tags++;
|
||||
k++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -4981,10 +4933,10 @@ int kms_set_key_properties(const kms_handle_t handle, const char *key_id,
|
||||
for (i = 0; i < num_properties; i++) {
|
||||
util_assert(properties[i].name != NULL,
|
||||
"Internal error: property name is NULL");
|
||||
util_assert(properties[i].value != NULL,
|
||||
"Internal error: property value is NULL");
|
||||
pr_verbose(ph, " Property '%s': '%s", properties[i].name,
|
||||
properties[i].value);
|
||||
|
||||
pr_verbose(ph, " Property '%s': '%s'", properties[i].name,
|
||||
properties[i].value != NULL ? properties[i].value :
|
||||
"(null)");
|
||||
}
|
||||
|
||||
_clear_error(ph);
|
||||
|
||||
@@ -99,6 +99,7 @@ struct plugin_handle {
|
||||
#define EKMFWEB_CURVE_PRIME "PRIME_CURVE"
|
||||
#define EKMFWEB_CURVE_BAINPOOL "BRAINPOOL_CURVE"
|
||||
#define EKMFWEB_SEQNO_TAG "seqno"
|
||||
#define EKMFWEB_SEQNO_NEXT "next"
|
||||
|
||||
#define DEFAULT_IDENTITY_KEY_PUBLIC_EXPONENT 65537
|
||||
|
||||
|
||||
426
zkey/keystore.c
426
zkey/keystore.c
@@ -40,12 +40,16 @@ struct key_filenames {
|
||||
char *skey_filename;
|
||||
char *info_filename;
|
||||
char *renc_filename;
|
||||
char *pass_filename;
|
||||
};
|
||||
|
||||
#define FILE_EXTENSION_LEN 5
|
||||
#define SKEY_FILE_EXTENSION ".skey"
|
||||
#define INFO_FILE_EXTENSION ".info"
|
||||
#define RENC_FILE_EXTENSION ".renc"
|
||||
#define PASS_FILE_EXTENSION ".pass"
|
||||
|
||||
#define DUMMY_PASSPHRASE_LEN 16
|
||||
|
||||
#define LOCK_FILE_NAME ".lock"
|
||||
|
||||
@@ -76,6 +80,7 @@ struct key_filenames {
|
||||
#define REC_VOLUME_TYPE "Volume type"
|
||||
#define REC_KMS "KMS"
|
||||
#define REC_KMS_KEY_LABEL "KMS key label"
|
||||
#define REC_PASSPHRASE_FILE "Dummy passphrase"
|
||||
|
||||
#define pr_verbose(keystore, fmt...) do { \
|
||||
if (keystore->verbose) \
|
||||
@@ -110,6 +115,8 @@ static int _keystore_get_key_filenames(struct keystore *keystore,
|
||||
name, INFO_FILE_EXTENSION);
|
||||
util_asprintf(&names->renc_filename, "%s/%s%s", keystore->directory,
|
||||
name, RENC_FILE_EXTENSION);
|
||||
util_asprintf(&names->pass_filename, "%s/%s%s", keystore->directory,
|
||||
name, PASS_FILE_EXTENSION);
|
||||
|
||||
pr_verbose(keystore, "File names for key '%s': '%s' and '%s'", name,
|
||||
names->skey_filename, names->info_filename);
|
||||
@@ -128,6 +135,18 @@ static int _keystore_reencipher_key_exists(struct key_filenames *file_names)
|
||||
return util_path_is_reg_file("%s", file_names->renc_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the .pass file exists.
|
||||
*
|
||||
* @param[in] file_names names of the files
|
||||
*
|
||||
* @returns 1 if the file exist, 0 if the file do not exist
|
||||
*/
|
||||
static int _keystore_passphrase_file_exists(struct key_filenames *file_names)
|
||||
{
|
||||
return util_path_is_reg_file("%s", file_names->pass_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if both, the .skey and the .info (and .renc) files exist.
|
||||
*
|
||||
@@ -146,7 +165,8 @@ static int _keystore_exists_keyfiles(struct key_filenames *file_names)
|
||||
if (rc_skey && rc_info)
|
||||
return 1;
|
||||
if (!rc_skey && !rc_info &&
|
||||
_keystore_reencipher_key_exists(file_names) == 0)
|
||||
_keystore_reencipher_key_exists(file_names) == 0 &&
|
||||
_keystore_passphrase_file_exists(file_names) == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
@@ -220,6 +240,8 @@ static void _keystore_free_key_filenames(struct key_filenames *names)
|
||||
free(names->info_filename);
|
||||
if (names->renc_filename)
|
||||
free(names->renc_filename);
|
||||
if (names->pass_filename)
|
||||
free(names->pass_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -985,7 +1007,7 @@ static int _keystore_process_filtered(struct keystore *keystore,
|
||||
process_key_t process_func,
|
||||
void *process_private)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
char **apqn_filter_list = NULL;
|
||||
char **vol_filter_list = NULL;
|
||||
struct properties *key_props;
|
||||
@@ -1593,6 +1615,129 @@ static int _keystore_set_default_properties(struct properties *key_props)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate, Set or remove a dummy LUKS2 passphrase of a key.
|
||||
*
|
||||
* @param[in] keystore the key store
|
||||
* @param[in] name the name of the key
|
||||
* @param[in] file_names the file names of the key
|
||||
* @param[in] properties the properties of the key
|
||||
* @param[in] prompt if true, prompt for removal (if passphrase exists)
|
||||
*
|
||||
* @returns 0 on success, or a negative errno value on error
|
||||
*/
|
||||
static int _keystore_remove_passphrase(struct keystore *keystore,
|
||||
const char *name,
|
||||
const struct key_filenames *filenames,
|
||||
struct properties *properties,
|
||||
bool prompt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (_keystore_passphrase_file_exists((struct key_filenames *)filenames)
|
||||
&& prompt) {
|
||||
util_print_indented("ATTENTION: When you remove the LUKS2 "
|
||||
"dummy passphrase of a key, you might no "
|
||||
"longer be able to open the LUKS2 volumes "
|
||||
"associated with the key, unless you still "
|
||||
"know a passphrase of one of the key slots "
|
||||
"of these volumes!", 0);
|
||||
_keystore_msg_for_volumes("The following volumes are encrypted "
|
||||
"with this key:", properties, NULL);
|
||||
printf("%s: Remove passphrase for key '%s' [y/N]? ",
|
||||
program_invocation_short_name, name);
|
||||
if (!prompt_for_yes(keystore->verbose)) {
|
||||
warnx("Operation aborted");
|
||||
return -ECANCELED;
|
||||
}
|
||||
}
|
||||
|
||||
rc = remove(filenames->pass_filename);
|
||||
if (rc != 0 && errno != ENOENT) {
|
||||
rc = -errno;
|
||||
warnx("Failed to remove file '%s': %s",
|
||||
filenames->pass_filename, strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate, Set or remove a dummy LUKS2 passphrase of a key.
|
||||
*
|
||||
* @param[in] keystore the key store
|
||||
* @param[in] name the name of the key
|
||||
* @param[in] passphrase_file the file name of a file containing a passphrase
|
||||
* for LUKS2. If NULKL, the passphrase is generated by
|
||||
* random.
|
||||
* @param[in] file_names the file names of the key
|
||||
* @param[in] properties the properties of the key
|
||||
* @param[in] prompt if true, prompt for change, if passphrase exists
|
||||
* already
|
||||
*
|
||||
* @returns 0 on success, or a negative errno value on error
|
||||
*/
|
||||
static int _keystore_set_passphrase(struct keystore *keystore,
|
||||
const char *name,
|
||||
const char *passphrase_file,
|
||||
const struct key_filenames *filenames,
|
||||
struct properties *properties,
|
||||
bool prompt)
|
||||
{
|
||||
char *volume_type;
|
||||
int rc;
|
||||
|
||||
if (_keystore_passphrase_file_exists((struct key_filenames *)filenames)
|
||||
&& prompt) {
|
||||
warnx("There is already a LUKS2 dummy passphrase associated "
|
||||
"with key '%s'.", name);
|
||||
util_print_indented("To change a dummy passphrase of a key, "
|
||||
"first remove the currently associated "
|
||||
"passphrase with command 'zkey change "
|
||||
"--name <key> --remove-dummy-passphrase' "
|
||||
"and then set the new dummy passphrase for "
|
||||
"the key.", 0);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
volume_type = _keystore_get_volume_type(properties);
|
||||
if (volume_type == NULL) {
|
||||
pr_verbose(keystore, "No volume type available");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0) {
|
||||
warnx("The LUKS2 dummy passphrase can only be set for keys "
|
||||
"with a volume type of LUKS2.");
|
||||
free(volume_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
free(volume_type);
|
||||
|
||||
if (passphrase_file != NULL) {
|
||||
rc = copy_file(passphrase_file, filenames->pass_filename, 0);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to copy the passphrase phase '%s': %s",
|
||||
passphrase_file, strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
rc = copy_file("/dev/urandom", filenames->pass_filename,
|
||||
DUMMY_PASSPHRASE_LEN);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to generate the dummy passphrase: %s",
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = _keystore_set_file_permission(keystore, filenames->pass_filename);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the key properties for a key
|
||||
*
|
||||
@@ -1615,6 +1760,8 @@ static int _keystore_set_default_properties(struct properties *key_props)
|
||||
* @param[in] key_type the type of the key
|
||||
* @param[in] kms the name of the KMS plugin, or NULL if no KMS is bound
|
||||
* @param[out] props the properties object is allocated and returned
|
||||
*
|
||||
* @returns 0 on success, or a negative errno value on error
|
||||
*/
|
||||
static int _keystore_create_info_props(struct keystore *keystore,
|
||||
const char *name,
|
||||
@@ -1721,7 +1868,7 @@ out:
|
||||
*
|
||||
* @param[in] keystore the key store
|
||||
* @param[in] name the name of the key
|
||||
* @param[in] info_filename the file name of the key info file
|
||||
* @param[in] filenames the file names of the key files
|
||||
* @param[in] description textual description of the key (optional, can be NULL)
|
||||
* @param[in] volumes a comma separated list of volumes associated with this
|
||||
* key (optional, can be NULL)
|
||||
@@ -1735,7 +1882,12 @@ out:
|
||||
* default is used.
|
||||
* @param[in] volume_type the type of volume
|
||||
* @param[in] key_type the type of the key
|
||||
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
|
||||
* @param[in] passphrase_file the file name of a file containing a passphrase
|
||||
* for LUKS2 (optional, can be NULL)
|
||||
* @param[in] kms the name of the KMS plugin, or NULL if no KMS is bound
|
||||
*
|
||||
* @returns 0 on success, or a negative errno value on error
|
||||
*/
|
||||
static int _keystore_create_info_file(struct keystore *keystore,
|
||||
const char *name,
|
||||
@@ -1746,6 +1898,8 @@ static int _keystore_create_info_file(struct keystore *keystore,
|
||||
size_t sector_size,
|
||||
const char *volume_type,
|
||||
const char *key_type,
|
||||
bool gen_passphrase,
|
||||
const char *passphrase_file,
|
||||
const char *kms)
|
||||
{
|
||||
struct properties *key_props = NULL;
|
||||
@@ -1758,12 +1912,24 @@ static int _keystore_create_info_file(struct keystore *keystore,
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (gen_passphrase || passphrase_file != NULL) {
|
||||
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
|
||||
NULL : passphrase_file,
|
||||
filenames, key_props, true);
|
||||
if (rc != 0) {
|
||||
pr_verbose(keystore, "Failed to set the passphrase: %s",
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = _keystore_ensure_vp_exists(keystore, filenames, key_props);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to generate the key verification pattern: %s",
|
||||
strerror(-rc));
|
||||
warnx("Make sure that kernel module 'paes_s390' is loaded and "
|
||||
"that the 'paes' cipher is available");
|
||||
remove(filenames->pass_filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1772,12 +1938,14 @@ static int _keystore_create_info_file(struct keystore *keystore,
|
||||
pr_verbose(keystore,
|
||||
"Key info file '%s' could not be written: %s",
|
||||
filenames->info_filename, strerror(-rc));
|
||||
remove(filenames->pass_filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _keystore_set_file_permission(keystore, filenames->info_filename);
|
||||
if (rc != 0) {
|
||||
remove(filenames->info_filename);
|
||||
remove(filenames->pass_filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1809,6 +1977,9 @@ out:
|
||||
* if NULL, the secure key is generated by random.
|
||||
* @param[in] volume_type the type of volume
|
||||
* @param[in] key_type the type of the key
|
||||
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
|
||||
* @param[in] passphrase_file the file name of a file containing a passphrase
|
||||
* for LUKS2 (optional, can be NULL)
|
||||
* @param[in] pkey_fd the file descriptor of /dev/pkey
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error
|
||||
@@ -1818,9 +1989,10 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
|
||||
const char *apqns, bool noapqncheck,
|
||||
size_t sector_size, size_t keybits, bool xts,
|
||||
const char *clear_key_file, const char *volume_type,
|
||||
const char *key_type, int pkey_fd)
|
||||
const char *key_type, bool gen_passphrase,
|
||||
const char *passphrase_file, int pkey_fd)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
struct properties *key_props = NULL;
|
||||
char **apqn_list = NULL;
|
||||
int rc;
|
||||
@@ -1880,7 +2052,8 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
|
||||
rc = _keystore_create_info_file(keystore, name, &file_names,
|
||||
description, volumes, apqns,
|
||||
noapqncheck, sector_size, volume_type,
|
||||
key_type, NULL);
|
||||
key_type, gen_passphrase,
|
||||
passphrase_file, NULL);
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
|
||||
@@ -1921,6 +2094,9 @@ out_free_key_filenames:
|
||||
* @param[in] xts if true, an XTS key is generated
|
||||
* @param[in] volume_type the type of volume
|
||||
* @param[in] key_type the type of the key (can be NULL)
|
||||
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
|
||||
* @param[in] passphrase_file the file name of a file containing a passphrase
|
||||
* for LUKS2 (optional, can be NULL)
|
||||
* @param[in] kms_options an array of KMS options specified, or NULL if no
|
||||
* KMS options have been specified
|
||||
* @param[in] num_kms_options the number of options in above array
|
||||
@@ -1931,10 +2107,11 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
size_t sector_size, size_t keybits, bool xts,
|
||||
const char *volume_type, const char *key_type,
|
||||
bool gen_passphrase, const char *passphrase_file,
|
||||
struct kms_option *kms_options,
|
||||
size_t num_kms_options)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
struct properties *key_props = NULL;
|
||||
struct kms_info *kms_info;
|
||||
char *apqns = NULL;
|
||||
@@ -2000,8 +2177,21 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
|
||||
if (rc != 0)
|
||||
goto out_free_key_filenames;
|
||||
|
||||
if (gen_passphrase || passphrase_file != NULL) {
|
||||
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
|
||||
NULL : passphrase_file,
|
||||
&file_names, key_props, true);
|
||||
if (rc != 0) {
|
||||
pr_verbose(keystore, "Failed to set the passphrase: %s",
|
||||
strerror(-rc));
|
||||
goto out_free_key_filenames;
|
||||
}
|
||||
}
|
||||
|
||||
rc = generate_kms_key(kms_info, name, key_type, key_props, xts,
|
||||
keybits, file_names.skey_filename,
|
||||
_keystore_passphrase_file_exists(&file_names) ?
|
||||
file_names.pass_filename : NULL,
|
||||
kms_options, num_kms_options, keystore->verbose);
|
||||
if (rc != 0) {
|
||||
warnx("KMS plugin '%s' failed to generate key '%s': %s",
|
||||
@@ -2048,8 +2238,10 @@ out_del_info_file:
|
||||
out_free_props:
|
||||
if (key_props != NULL)
|
||||
properties_free(key_props);
|
||||
if (rc != 0)
|
||||
if (rc != 0) {
|
||||
remove(file_names.skey_filename);
|
||||
remove(file_names.pass_filename);
|
||||
}
|
||||
out_free_key_filenames:
|
||||
_keystore_free_key_filenames(&file_names);
|
||||
if (apqns != NULL)
|
||||
@@ -2081,6 +2273,9 @@ out_free_key_filenames:
|
||||
* default is used.
|
||||
* @param[in] import_file The name of a secure key containing the key to import
|
||||
* @param[in] volume_type the type of volume
|
||||
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
|
||||
* @param[in] passphrase_file the file name of a file containing a passphrase
|
||||
* for LUKS2 (optional, can be NULL)
|
||||
* @param[in] lib the external library struct
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error
|
||||
@@ -2089,9 +2284,10 @@ int keystore_import_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, bool noapqncheck, size_t sector_size,
|
||||
const char *import_file, const char *volume_type,
|
||||
bool gen_passphrase, const char *passphrase_file,
|
||||
struct ext_lib *lib)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
struct properties *key_props = NULL;
|
||||
size_t secure_key_size;
|
||||
const char *key_type;
|
||||
@@ -2206,7 +2402,8 @@ int keystore_import_key(struct keystore *keystore, const char *name,
|
||||
rc = _keystore_create_info_file(keystore, name, &file_names,
|
||||
description, volumes, apqns,
|
||||
noapqncheck, sector_size, volume_type,
|
||||
key_type, NULL);
|
||||
key_type, gen_passphrase,
|
||||
passphrase_file, NULL);
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
|
||||
@@ -2256,23 +2453,33 @@ out_free_key_filenames:
|
||||
* not be changed.
|
||||
* @param[in] volume_type the type of volume. If NULL then the volume type is
|
||||
* not changed.
|
||||
* *
|
||||
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
|
||||
* @param[in] passphrase_file the file name of a file containing a passphrase
|
||||
* for LUKS2 (optional, can be NULL)
|
||||
* @param[in] remove_passphrase if true, remove the (dummy) passphrase
|
||||
* @param[in] quiet if true no confirmation prompt is shown when removing
|
||||
* a (dummy) passphrase
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error
|
||||
*
|
||||
*/
|
||||
int keystore_change_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, bool noapqncheck,
|
||||
long int sector_size, const char *volume_type)
|
||||
long int sector_size, const char *volume_type,
|
||||
bool gen_passphrase, const char *passphrase_file,
|
||||
bool remove_passphrase, bool quiet)
|
||||
{
|
||||
struct volume_check vol_check = { .keystore = keystore, .name = name,
|
||||
.set = 0, .nocheck = 0 };
|
||||
struct apqn_check apqn_check = { .noonlinecheck = noapqncheck,
|
||||
.nomsg = 0 };
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
struct properties *key_props = NULL;
|
||||
const char **passphrase_upd = NULL;
|
||||
char *upd_volume_type = NULL;
|
||||
char *apqns_prop, *key_type;
|
||||
const char *null_ptr = NULL;
|
||||
char *upd_volumes = NULL;
|
||||
size_t secure_key_size;
|
||||
u8 mkvp[MKVP_LENGTH];
|
||||
@@ -2401,6 +2608,38 @@ int keystore_change_key(struct keystore *keystore, const char *name,
|
||||
|
||||
upd_volume_type = properties_get(key_props,
|
||||
PROP_NAME_VOLUME_TYPE);
|
||||
|
||||
/* Remove dummy passphrase if change to PLAIN volume type */
|
||||
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0 &&
|
||||
_keystore_passphrase_file_exists(&file_names)) {
|
||||
rc = _keystore_remove_passphrase(keystore, name,
|
||||
&file_names, key_props,
|
||||
false);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
passphrase_upd = &null_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (gen_passphrase || passphrase_file != NULL) {
|
||||
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
|
||||
NULL : passphrase_file,
|
||||
&file_names, key_props, true);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
passphrase_upd = (const char **)&file_names.pass_filename;
|
||||
}
|
||||
|
||||
if (remove_passphrase) {
|
||||
if (_keystore_passphrase_file_exists(&file_names))
|
||||
passphrase_upd = &null_ptr;
|
||||
|
||||
rc = _keystore_remove_passphrase(keystore, name, &file_names,
|
||||
key_props, !quiet);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kms_bound) {
|
||||
@@ -2412,7 +2651,7 @@ int keystore_change_key(struct keystore *keystore, const char *name,
|
||||
description, upd_volumes,
|
||||
upd_volume_type, sector_size >= 0 ?
|
||||
sect_size : NULL,
|
||||
keystore->verbose);
|
||||
passphrase_upd, keystore->verbose);
|
||||
if (rc != 0) {
|
||||
warnx("KMS plugin '%s' failed to set key properties "
|
||||
"for key '%s': %s",
|
||||
@@ -2441,6 +2680,8 @@ int keystore_change_key(struct keystore *keystore, const char *name,
|
||||
pr_verbose(keystore, "Successfully changed key '%s'", name);
|
||||
|
||||
out:
|
||||
if (rc != 0 && passphrase_upd != NULL && *passphrase_upd != NULL)
|
||||
remove(*passphrase_upd);
|
||||
_keystore_free_key_filenames(&file_names);
|
||||
if (key_props != NULL)
|
||||
properties_free(key_props);
|
||||
@@ -2467,10 +2708,11 @@ out:
|
||||
int keystore_rename_key(struct keystore *keystore, const char *name,
|
||||
const char *newname)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames new_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
struct key_filenames new_names = { 0 };
|
||||
struct properties *key_props = NULL;
|
||||
bool reenc_exists = false;
|
||||
bool pass_exists = false;
|
||||
char *msg;
|
||||
int rc;
|
||||
|
||||
@@ -2516,6 +2758,16 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
|
||||
goto out_rename_info;
|
||||
}
|
||||
}
|
||||
if (_keystore_passphrase_file_exists(&file_names)) {
|
||||
pass_exists = true;
|
||||
if (rename(file_names.pass_filename,
|
||||
new_names.pass_filename) != 0) {
|
||||
rc = -errno;
|
||||
pr_verbose(keystore, "Failed to rename '%s': %s",
|
||||
file_names.pass_filename, strerror(-rc));
|
||||
goto out_rename_info;
|
||||
}
|
||||
}
|
||||
|
||||
key_props = properties_new();
|
||||
rc = properties_load(key_props, new_names.info_filename, 1);
|
||||
@@ -2531,7 +2783,7 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
|
||||
|
||||
rc = set_kms_key_properties(keystore->kms_info, key_props,
|
||||
newname, NULL, NULL, NULL, NULL,
|
||||
keystore->verbose);
|
||||
NULL, keystore->verbose);
|
||||
if (rc != 0) {
|
||||
warnx("KMS plugin '%s' failed to set key properties "
|
||||
"for key '%s': %s",
|
||||
@@ -2549,6 +2801,16 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
|
||||
_keystore_msg_for_volumes(msg, key_props, VOLUME_TYPE_PLAIN);
|
||||
free(msg);
|
||||
|
||||
if (_keystore_passphrase_file_exists(&new_names)) {
|
||||
util_asprintf(&msg, "The following volumes are associated with "
|
||||
"the renamed key '%s'. You should adjust the "
|
||||
"corresponding crypttab entries to use the new "
|
||||
"dummy passphrase file name '%s'.", newname,
|
||||
new_names.pass_filename);
|
||||
_keystore_msg_for_volumes(msg, key_props, VOLUME_TYPE_LUKS2);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
pr_verbose(keystore, "Successfully renamed key '%s' to '%s'", name,
|
||||
newname);
|
||||
|
||||
@@ -2557,6 +2819,8 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
|
||||
out_rename_info:
|
||||
if (reenc_exists)
|
||||
rename(file_names.renc_filename, new_names.renc_filename);
|
||||
if (pass_exists)
|
||||
rename(file_names.pass_filename, new_names.pass_filename);
|
||||
rename(new_names.info_filename, file_names.info_filename);
|
||||
|
||||
out_rename_skey:
|
||||
@@ -2613,6 +2877,8 @@ static struct util_rec *_keystore_setup_record(bool validation)
|
||||
util_rec_def(rec, REC_KMS, UTIL_REC_ALIGN_LEFT, 54, REC_KMS);
|
||||
util_rec_def(rec, REC_KMS_KEY_LABEL, UTIL_REC_ALIGN_LEFT, 54,
|
||||
REC_KMS_KEY_LABEL);
|
||||
util_rec_def(rec, REC_PASSPHRASE_FILE, UTIL_REC_ALIGN_LEFT, 54,
|
||||
REC_PASSPHRASE_FILE);
|
||||
util_rec_def(rec, REC_CREATION_TIME, UTIL_REC_ALIGN_LEFT, 54,
|
||||
REC_CREATION_TIME);
|
||||
util_rec_def(rec, REC_CHANGE_TIME, UTIL_REC_ALIGN_LEFT, 54,
|
||||
@@ -2629,7 +2895,8 @@ static void _keystore_print_record(struct util_rec *rec,
|
||||
bool validation, const char *skey_filename,
|
||||
size_t secure_key_size, bool is_xts,
|
||||
size_t clear_key_bitsize, bool valid,
|
||||
bool is_old_mk, bool reenc_pending, u8 *mkvp)
|
||||
bool is_old_mk, bool reenc_pending, u8 *mkvp,
|
||||
const char *pass_filename)
|
||||
{
|
||||
char temp_vp[VERIFICATION_PATTERN_LEN + 2];
|
||||
char *kms_xts_key1_label = NULL;
|
||||
@@ -2767,6 +3034,10 @@ static void _keystore_print_record(struct util_rec *rec,
|
||||
label_argz_len);
|
||||
else
|
||||
util_rec_set(rec, REC_KMS_KEY_LABEL, "(local)");
|
||||
if (pass_filename != NULL)
|
||||
util_rec_set(rec, REC_PASSPHRASE_FILE, pass_filename);
|
||||
else
|
||||
util_rec_set(rec, REC_PASSPHRASE_FILE, "(none)");
|
||||
util_rec_set(rec, REC_CREATION_TIME, creation);
|
||||
util_rec_set(rec, REC_CHANGE_TIME,
|
||||
change != NULL ? change : "(never)");
|
||||
@@ -2966,7 +3237,9 @@ static int _keystore_process_validate(struct keystore *keystore,
|
||||
is_xts_key(secure_key, secure_key_size),
|
||||
clear_key_bitsize, valid, is_old_mk,
|
||||
_keystore_reencipher_key_exists(file_names),
|
||||
mkvp);
|
||||
mkvp,
|
||||
_keystore_passphrase_file_exists(file_names) ?
|
||||
file_names->pass_filename : NULL);
|
||||
|
||||
if (valid && is_old_mk) {
|
||||
util_print_indented("WARNING: The secure key is currently "
|
||||
@@ -3434,8 +3707,8 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
|
||||
{
|
||||
struct volume_check vol_check = { .keystore = keystore, .name = newname,
|
||||
.set = 0, .nocheck = 0 };
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames new_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
struct key_filenames new_names = { 0 };
|
||||
struct properties *key_prop = NULL;
|
||||
size_t secure_key_size;
|
||||
bool kms_bound = false;
|
||||
@@ -3536,7 +3809,6 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
|
||||
pr_verbose(keystore,
|
||||
"Key info file '%s' could not be written: %s",
|
||||
new_names.info_filename, strerror(-rc));
|
||||
remove(new_names.skey_filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -3544,6 +3816,23 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
if (_keystore_passphrase_file_exists(&file_names)) {
|
||||
rc = copy_file(file_names.skey_filename,
|
||||
new_names.pass_filename, 0);
|
||||
if (rc != 0) {
|
||||
pr_verbose(keystore,
|
||||
"Passphrase file '%s' could not be copied: "
|
||||
"%s", new_names.pass_filename,
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _keystore_set_file_permission(keystore,
|
||||
file_names.pass_filename);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_verbose(keystore, "Successfully copied key '%s' to '%s'", name,
|
||||
newname);
|
||||
|
||||
@@ -3551,6 +3840,7 @@ out:
|
||||
if (rc != 0) {
|
||||
remove(new_names.skey_filename);
|
||||
remove(new_names.info_filename);
|
||||
remove(new_names.pass_filename);
|
||||
}
|
||||
|
||||
_keystore_free_key_filenames(&file_names);
|
||||
@@ -3576,7 +3866,7 @@ out:
|
||||
int keystore_export_key(struct keystore *keystore, const char *name,
|
||||
const char *export_file)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
size_t secure_key_size;
|
||||
u8 *secure_key;
|
||||
int rc;
|
||||
@@ -3675,7 +3965,7 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
|
||||
bool quiet, struct kms_option *kms_options,
|
||||
size_t num_kms_options)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
struct properties *key_props = NULL;
|
||||
int rc;
|
||||
|
||||
@@ -3739,6 +4029,13 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
|
||||
file_names.renc_filename, strerror(-rc));
|
||||
}
|
||||
}
|
||||
if (_keystore_passphrase_file_exists(&file_names)) {
|
||||
if (remove(file_names.pass_filename) != 0) {
|
||||
rc = -errno;
|
||||
pr_verbose(keystore, "Failed to remove '%s': %s",
|
||||
file_names.pass_filename, strerror(-rc));
|
||||
}
|
||||
}
|
||||
pr_verbose(keystore, "Successfully removed key '%s'", name);
|
||||
|
||||
out:
|
||||
@@ -3794,7 +4091,9 @@ static int _keystore_display_key(struct keystore *keystore,
|
||||
is_xts_key(secure_key, secure_key_size),
|
||||
clear_key_bitsize, 0, 0,
|
||||
_keystore_reencipher_key_exists(file_names),
|
||||
NULL);
|
||||
NULL,
|
||||
_keystore_passphrase_file_exists(file_names) ?
|
||||
file_names->pass_filename : NULL);
|
||||
|
||||
out:
|
||||
free(secure_key);
|
||||
@@ -3910,6 +4209,7 @@ struct crypt_info {
|
||||
size_t key_file_size,
|
||||
size_t sector_size,
|
||||
const char *volume_type,
|
||||
const char *passphrase_file,
|
||||
struct crypt_info *info);
|
||||
};
|
||||
|
||||
@@ -3925,6 +4225,7 @@ struct crypt_info {
|
||||
* @param[in] key_file_size the size of the key file in bytes
|
||||
* @param[in] sector_size the sector size in bytes or 0 if not specified
|
||||
* @param[in] volume_type the volume type
|
||||
* @param[in] passphrase_file the passphrase file name (can be NULL)
|
||||
* @param[in] info processing info
|
||||
*
|
||||
* @returns 0 if successful, a negative errno value otherwise
|
||||
@@ -3937,6 +4238,7 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
|
||||
size_t key_file_size,
|
||||
size_t sector_size,
|
||||
const char *volume_type,
|
||||
const char *passphrase_file,
|
||||
struct crypt_info *info)
|
||||
{
|
||||
char *keyfile_opt = NULL, *offset_opt = NULL;
|
||||
@@ -3957,6 +4259,9 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
|
||||
if (info->keyfile_size > 0)
|
||||
util_asprintf(&size_opt, "--keyfile-size %lu ",
|
||||
info->keyfile_size);
|
||||
} else if (passphrase_file != NULL) {
|
||||
util_asprintf(&keyfile_opt, "--key-file '%s' ",
|
||||
passphrase_file);
|
||||
}
|
||||
if (info->tries > 0)
|
||||
util_asprintf(&tries_opt, "--tries %lu ", info->tries);
|
||||
@@ -4069,6 +4374,7 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
|
||||
* @param[in] key_file_size the size of the key file in bytes
|
||||
* @param[in] sector_size the sector size in bytes or 0 if not specified
|
||||
* @param[in] volume_type the volume type
|
||||
* @param[in] passphrase_file the passphrase file name (can be NULL)
|
||||
* @param[in] info processing info (not used here)
|
||||
*
|
||||
* @returns 0 if successful, a negative errno value otherwise
|
||||
@@ -4082,37 +4388,30 @@ static int _keystore_process_crypttab(struct keystore *UNUSED(keystore),
|
||||
size_t key_file_size,
|
||||
size_t sector_size,
|
||||
const char *volume_type,
|
||||
const char *passphrase_file,
|
||||
struct crypt_info *info)
|
||||
{
|
||||
char temp[1000];
|
||||
|
||||
if (strcasecmp(volume_type, VOLUME_TYPE_PLAIN) == 0) {
|
||||
if (sector_size > 0) {
|
||||
sprintf(temp,
|
||||
"WARNING: volume '%s' is using a sector size "
|
||||
"of %lu. At the time this utility was "
|
||||
"developed, systemd's support of crypttab did "
|
||||
"not support to specify a sector size with "
|
||||
"plain dm-crypt devices. The generated "
|
||||
"crypttab entry might or might not work, and "
|
||||
"might need manual adoptions.", volume,
|
||||
sector_size);
|
||||
util_print_indented(temp, 0);
|
||||
}
|
||||
|
||||
sprintf(temp, ",sector-size=%lu", sector_size);
|
||||
printf("%s\t%s\t%s\tplain,cipher=%s,size=%lu%s\n",
|
||||
dmname, volume, key_file_name, cipher_spec,
|
||||
key_file_size * 8, sector_size > 0 ? temp : "");
|
||||
} else if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) {
|
||||
printf("%s\t%s\t%s\tluks", dmname, volume,
|
||||
info->keyfile != NULL ? info->keyfile : "none");
|
||||
if (info->keyfile != NULL) {
|
||||
printf("%s\t%s\t%s\tluks", dmname, volume,
|
||||
info->keyfile);
|
||||
if (info->keyfile_offset > 0)
|
||||
printf(",keyfile-offset=%lu",
|
||||
info->keyfile_offset);
|
||||
if (info->keyfile_size > 0)
|
||||
printf(",keyfile-size=%lu", info->keyfile_size);
|
||||
} else if (passphrase_file != NULL) {
|
||||
printf("%s\t%s\t%s\tluks", dmname, volume,
|
||||
passphrase_file);
|
||||
} else {
|
||||
printf("%s\t%s\tnone\tluks", dmname, volume);
|
||||
}
|
||||
if (info->tries > 0)
|
||||
printf(",tries=%lu", info->tries);
|
||||
@@ -4237,7 +4536,10 @@ static int _keystore_process_crypt(struct keystore *keystore,
|
||||
rc = info->process_func(keystore, vol, dmname,
|
||||
cipher_spec, file_names->skey_filename,
|
||||
secure_key_size, sector_size,
|
||||
volume_type, info);
|
||||
volume_type,
|
||||
_keystore_passphrase_file_exists(file_names) ?
|
||||
file_names->pass_filename : NULL,
|
||||
info);
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
@@ -4403,7 +4705,7 @@ int keystore_convert_key(struct keystore *keystore, const char *name,
|
||||
const char *key_type, bool noapqncheck, bool quiet,
|
||||
int pkey_fd, struct ext_lib *lib)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct key_filenames file_names = { 0 };
|
||||
u8 output_key[2 * MAX_SECURE_KEY_SIZE];
|
||||
struct properties *properties = NULL;
|
||||
int rc, min_level, selected = 1;
|
||||
@@ -4920,6 +5222,7 @@ struct kms_import {
|
||||
* @param[in] volumes the associated volumes of the key (can be NULL)
|
||||
* @param[in] volume_type the volume type of the volume (can be NULL)
|
||||
* @param[in] sector_size the sector size of the volume (0 means default)
|
||||
* @param[in] passphrase the passphrase of the key (can be NULL)
|
||||
* @param[in] addl_info_argz an argz string containing additional KMS plugin
|
||||
* specific infos to be displayed, or NULL if none.
|
||||
* @param[in] addl_info_len length of the argz string in addl_info_argz
|
||||
@@ -4940,12 +5243,13 @@ static int _keystore_process_kms_import(const char *key1_id,
|
||||
const char *volumes,
|
||||
const char *volume_type,
|
||||
size_t sector_size,
|
||||
const char *passphrase,
|
||||
const char *UNUSED(addl_info_argz),
|
||||
size_t UNUSED(addl_info_len),
|
||||
void *private_data)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct kms_import *import_data = private_data;
|
||||
struct key_filenames file_names = { 0 };
|
||||
u8 secure_key[2 * MAX_SECURE_KEY_SIZE];
|
||||
struct properties *key_props = NULL;
|
||||
char vp[VERIFICATION_PATTERN_LEN];
|
||||
@@ -5042,6 +5346,23 @@ prompt_alt_name:
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
if (passphrase != NULL && volume_type != NULL &&
|
||||
strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) {
|
||||
rc = store_passphrase_from_base64(passphrase,
|
||||
file_names.pass_filename,
|
||||
keystore->verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(keystore, "Failed to parse passphrase: %s",
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _keystore_set_file_permission(keystore,
|
||||
file_names.pass_filename);
|
||||
if (rc != 0)
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
rc = properties_set(key_props, xts ? PROP_NAME_KMS_XTS_KEY1_ID :
|
||||
PROP_NAME_KMS_KEY_ID, key1_id);
|
||||
if (rc != 0) {
|
||||
@@ -5267,7 +5588,9 @@ static int _keystore_refresh_kms_key(struct keystore *keystore,
|
||||
rc = refresh_kms_key(keystore->kms_info, properties,
|
||||
&description, &cipher, &iv_mode, &volumes,
|
||||
&volume_type, §or_size,
|
||||
file_names->skey_filename, keystore->verbose);
|
||||
file_names->skey_filename,
|
||||
file_names->pass_filename,
|
||||
keystore->verbose);
|
||||
if (rc != 0) {
|
||||
warnx("KMS plugin '%s' failed to refresh key '%s': %s",
|
||||
keystore->kms_info->plugin_name, name, strerror(-rc));
|
||||
@@ -5277,6 +5600,17 @@ static int _keystore_refresh_kms_key(struct keystore *keystore,
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _keystore_set_file_permission(keystore, file_names->skey_filename);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
if (_keystore_passphrase_file_exists(file_names)) {
|
||||
rc = _keystore_set_file_permission(keystore,
|
||||
file_names->pass_filename);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!refresh_data->refresh_properties)
|
||||
goto save_props;
|
||||
|
||||
@@ -5345,6 +5679,10 @@ save_props:
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _keystore_set_file_permission(keystore, file_names->info_filename);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (rc == 0) {
|
||||
printf("Successfully refreshed key '%s'\n", name);
|
||||
|
||||
@@ -54,12 +54,14 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
|
||||
const char *apqns, bool noapqncheck,
|
||||
size_t sector_size, size_t keybits, bool xts,
|
||||
const char *clear_key_file, const char *volume_type,
|
||||
const char *key_type, int pkey_fd);
|
||||
const char *key_type, bool gen_passphrase,
|
||||
const char *passphrase_file, int pkey_fd);
|
||||
|
||||
int keystore_generate_key_kms(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
size_t sector_size, size_t keybits, bool xts,
|
||||
const char *volume_type, const char *key_type,
|
||||
bool gen_passphrase, const char *passphrase_file,
|
||||
struct kms_option *kms_options,
|
||||
size_t num_kms_options);
|
||||
|
||||
@@ -67,12 +69,15 @@ int keystore_import_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, bool noapqncheck, size_t sector_size,
|
||||
const char *import_file, const char *volume_type,
|
||||
bool gen_passphrase, const char *passphrase_file,
|
||||
struct ext_lib *lib);
|
||||
|
||||
int keystore_change_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, bool noapqncheck,
|
||||
long int sector_size, const char *volume_type);
|
||||
long int sector_size, const char *volume_type,
|
||||
bool gen_passphrase, const char *passphrase_file,
|
||||
bool remove_passphrase, bool quiet);
|
||||
|
||||
int keystore_rename_key(struct keystore *keystore, const char *name,
|
||||
const char *newname);
|
||||
|
||||
94
zkey/kms.c
94
zkey/kms.c
@@ -40,14 +40,16 @@
|
||||
|
||||
#define ENVVAR_ZKEY_KMS_PLUGINS "ZKEY_KMS_PLUGINS"
|
||||
#define DEFAULT_KMS_PLUGINS "/etc/zkey/kms-plugins.conf"
|
||||
#define KMS_PLUGIN_LOCATION "/usr/lib64/zkey"
|
||||
#ifndef KMS_PLUGIN_LOCATION
|
||||
#error KMS_PLUGIN_LOCATION must be defined
|
||||
#endif
|
||||
|
||||
#define KMS_CONFIG_FILE "kms.conf"
|
||||
#define KMS_CONFIG_PROP_KMS "kms"
|
||||
#define KMS_CONFIG_PROP_KMS_CONFIG "config"
|
||||
#define KMS_CONFIG_PROP_APQNS "apqns"
|
||||
#define KMS_CONFIG_PROP_CCA_APQNS "ep11_apqns"
|
||||
#define KMS_CONFIG_PROP_EP11_APQNS "cca_apqns"
|
||||
#define KMS_CONFIG_PROP_CCA_APQNS "cca_apqns"
|
||||
#define KMS_CONFIG_PROP_EP11_APQNS "ep11_apqns"
|
||||
#define KMS_CONFIG_LOCAL "local"
|
||||
|
||||
#define KMS_KEY_PROP_NAME "zkey-name"
|
||||
@@ -62,6 +64,7 @@
|
||||
#define KMS_KEY_PROP_XTS_KEY2_ID "xts-key2-id"
|
||||
#define KMS_KEY_PROP_XTS_KEY1_LABEL "xts-key1-label"
|
||||
#define KMS_KEY_PROP_XTS_KEY2_LABEL "xts-key2-label"
|
||||
#define KMS_KEY_PROP_PASSPHRASE "dummy-passphrase-base64"
|
||||
|
||||
#define KMS_REC_LABEL "Key label"
|
||||
#define KMS_REC_NAME "Name"
|
||||
@@ -2118,6 +2121,8 @@ static char *_get_system_specific_prop_name(const char *prop_name)
|
||||
* @param[in] keybits the key bit size (e.g. 128, 196, 256, 0 to use the
|
||||
* plugin's default)
|
||||
* @param[in] filename the file name to store the key in
|
||||
* @param[in] passphrase_file the file name containing the LUKS2 passphrase,
|
||||
* or NULL if no passphrase is set
|
||||
* @param[in] kms_options an array of KMS options specified, or NULL if no
|
||||
* KMS options have been specified
|
||||
* @param[in] num_kms_options the number of options in above array
|
||||
@@ -2129,6 +2134,7 @@ static char *_get_system_specific_prop_name(const char *prop_name)
|
||||
int generate_kms_key(struct kms_info *kms_info, const char *name,
|
||||
const char *key_type, struct properties *key_props,
|
||||
bool xts, size_t keybits, const char *filename,
|
||||
const char *passphrase_file,
|
||||
struct kms_option *kms_options, size_t num_kms_options,
|
||||
bool verbose)
|
||||
{
|
||||
@@ -2138,12 +2144,13 @@ int generate_kms_key(struct kms_info *kms_info, const char *name,
|
||||
char key2_label[KMS_KEY_LABEL_SIZE + 1] = { 0 };
|
||||
char key1_id[KMS_KEY_ID_SIZE + 1] = { 0 };
|
||||
char key2_id[KMS_KEY_ID_SIZE + 1] = { 0 };
|
||||
struct kms_property kms_props[12];
|
||||
struct kms_property kms_props[13];
|
||||
int xts_mode_prop = -1, rc = 0;
|
||||
size_t key_size, key_blob_size;
|
||||
enum kms_key_mode key_mode;
|
||||
size_t num_kms_props = 0;
|
||||
char *sys_volumes = NULL;
|
||||
char *passphrase = NULL;
|
||||
|
||||
util_assert(kms_info != NULL, "Internal error: kms_info is NULL");
|
||||
util_assert(name != NULL, "Internal error: name is NULL");
|
||||
@@ -2207,6 +2214,19 @@ int generate_kms_key(struct kms_info *kms_info, const char *name,
|
||||
"XTS-KEY-1");
|
||||
}
|
||||
|
||||
if (passphrase_file != NULL) {
|
||||
passphrase = read_passphrase_as_base64(passphrase_file,
|
||||
verbose);
|
||||
if (passphrase == NULL) {
|
||||
pr_verbose(verbose, "Failed to read passphrase from "
|
||||
"file '%s'", passphrase_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ADD_KMS_PROPS(kms_props, num_kms_props, KMS_KEY_PROP_PASSPHRASE,
|
||||
passphrase);
|
||||
}
|
||||
|
||||
key_mode = xts ? KMS_KEY_MODE_XTS_1 : KMS_KEY_MODE_NON_XTS;
|
||||
|
||||
key_blob_size = key_size;
|
||||
@@ -2331,6 +2351,8 @@ out:
|
||||
free(sector_size);
|
||||
if (sys_volumes != NULL)
|
||||
free(sys_volumes);
|
||||
if (passphrase != NULL)
|
||||
free(passphrase);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2346,20 +2368,28 @@ out:
|
||||
* @param[in] volumes the volumes of the key (can be NULL)
|
||||
* @param[in] vol_type the volume type of the key (can be NULL)
|
||||
* @param[in] sector_size the sector_size of the key (can be NULL)
|
||||
* @param[in] passphrase_file an address to a character string containing the
|
||||
* file name containing the LUKS2 passphrase,
|
||||
* or NULL if no passphrase is set. If
|
||||
* passphrase_file itself is NULL, then no change in
|
||||
* the passphrase property.
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
|
||||
int set_kms_key_properties(struct kms_info *kms_info,
|
||||
struct properties *key_props,
|
||||
const char *name, const char *description,
|
||||
const char *volumes, const char *vol_type,
|
||||
const char *sector_size, bool verbose)
|
||||
const char *sector_size,
|
||||
const char **passphrase_file,
|
||||
bool verbose)
|
||||
{
|
||||
char *key1_id = NULL, *key2_id = NULL;
|
||||
struct kms_property kms_props[10];
|
||||
struct kms_property kms_props[11];
|
||||
size_t num_kms_props = 0;
|
||||
char *sys_volumes = NULL;
|
||||
char *passphrase = NULL;
|
||||
char *sys_name = NULL;
|
||||
bool xts = false;
|
||||
|
||||
@@ -2414,6 +2444,22 @@ int set_kms_key_properties(struct kms_info *kms_info,
|
||||
if (sector_size != NULL)
|
||||
ADD_KMS_PROPS(kms_props, num_kms_props,
|
||||
KMS_KEY_PROP_SECTOR_SIZE, sector_size);
|
||||
if (passphrase_file != NULL) {
|
||||
/* *passphrase_file is NULL to remove the propoerty */
|
||||
if (*passphrase_file != NULL) {
|
||||
passphrase =
|
||||
read_passphrase_as_base64(*passphrase_file,
|
||||
verbose);
|
||||
if (passphrase == NULL) {
|
||||
pr_verbose(verbose, "Failed to read passphrase"
|
||||
" from file '%s'", *passphrase_file);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ADD_KMS_PROPS(kms_props, num_kms_props,
|
||||
KMS_KEY_PROP_PASSPHRASE, passphrase);
|
||||
}
|
||||
|
||||
if (num_kms_props == 0)
|
||||
goto out;
|
||||
@@ -2448,6 +2494,8 @@ out:
|
||||
free(key1_id);
|
||||
if (key2_id != NULL)
|
||||
free(key2_id);
|
||||
if (passphrase != NULL)
|
||||
free(passphrase);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2640,6 +2688,7 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
|
||||
const char *name, *volumes, *cipher, *iv_mode, *description;
|
||||
const char *xts_key2_id = NULL, *xts_key2_label = NULL;
|
||||
const char *xts_key, *volume_type, *temp;
|
||||
const char *passphrase;
|
||||
size_t sector_size = 0;
|
||||
bool xts = false;
|
||||
|
||||
@@ -2695,6 +2744,8 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
|
||||
KMS_KEY_PROP_SECTOR_SIZE);
|
||||
if (temp != NULL)
|
||||
sscanf(temp, "%lu", §or_size);
|
||||
passphrase = _find_property(properties, num_properties,
|
||||
KMS_KEY_PROP_PASSPHRASE);
|
||||
|
||||
if (process_data->label_filter != NULL) {
|
||||
if (fnmatch(process_data->label_filter, key_label,
|
||||
@@ -2728,6 +2779,7 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
|
||||
xts ? key_bits * 2 : key_bits,
|
||||
description, cipher, iv_mode,
|
||||
volumes, volume_type, sector_size,
|
||||
passphrase,
|
||||
addl_info_argz, addl_info_len,
|
||||
process_data->private_data);
|
||||
}
|
||||
@@ -2865,6 +2917,7 @@ static int _list_kms_keys_cb(const char *UNUSED(key1_id),
|
||||
const char *UNUSED(cipher),
|
||||
const char *UNUSED(iv_mode), const char *volumes,
|
||||
const char *volume_type, size_t sector_size,
|
||||
const char *UNUSED(passphrase),
|
||||
const char *addl_info_argz, size_t addl_info_len,
|
||||
void *private_data)
|
||||
{
|
||||
@@ -3139,6 +3192,7 @@ out:
|
||||
* @param[out] volume_type on return: the volume_type property
|
||||
* @param[out] sector_size on return: the sector_size property
|
||||
* @param[in] filename the file name to store the refreshed key blob in
|
||||
* @param[in] passphrase_file the file name to store the dummy passphras in
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
@@ -3146,7 +3200,8 @@ out:
|
||||
int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
|
||||
char **description, char **cipher, char **iv_mode,
|
||||
char **volumes, char **volume_type, ssize_t *sector_size,
|
||||
const char *filename, bool verbose)
|
||||
const char *filename, const char *passphrase_file,
|
||||
bool verbose)
|
||||
{
|
||||
struct kms_property *properties = NULL;
|
||||
u8 key_blob[2 * MAX_SECURE_KEY_SIZE];
|
||||
@@ -3239,6 +3294,29 @@ int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
|
||||
if (str != NULL)
|
||||
sscanf(str, "%lu", (long unsigned int *)sector_size);
|
||||
}
|
||||
if (passphrase_file != NULL && volume_type != NULL &&
|
||||
*volume_type != NULL && strcasecmp(*volume_type, "luks2") == 0) {
|
||||
str = _find_property(properties, num_properties,
|
||||
KMS_KEY_PROP_PASSPHRASE);
|
||||
if (str != NULL) {
|
||||
rc = store_passphrase_from_base64(str, passphrase_file,
|
||||
verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose,
|
||||
"Failed to parse passphrase: %s",
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
rc = remove(passphrase_file);
|
||||
if (rc != 0 && errno != ENOENT) {
|
||||
pr_verbose(verbose,
|
||||
"Failed to remove passphrase_file: "
|
||||
"%s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
key_blob_size = sizeof(key_blob);
|
||||
memset(key_blob, 0, key_blob_size);
|
||||
|
||||
@@ -74,6 +74,7 @@ int get_kms_apqns_for_key_type(struct kms_info *kms_info, const char *key_type,
|
||||
int generate_kms_key(struct kms_info *kms_info, const char *name,
|
||||
const char *key_type, struct properties *key_props,
|
||||
bool xts, size_t keybits, const char *filename,
|
||||
const char *passphrase_file,
|
||||
struct kms_option *kms_options, size_t num_kms_options,
|
||||
bool verbose);
|
||||
|
||||
@@ -81,7 +82,9 @@ int set_kms_key_properties(struct kms_info *kms_info,
|
||||
struct properties *key_props,
|
||||
const char *name, const char *description,
|
||||
const char *volumes, const char *vol_type,
|
||||
const char *sector_size, bool verbose);
|
||||
const char *sector_size,
|
||||
const char **passphrase_file,
|
||||
bool verbose);
|
||||
|
||||
int remove_kms_key(struct kms_info *kms_info, struct properties *key_props,
|
||||
struct kms_option *kms_options, size_t num_kms_options,
|
||||
@@ -94,6 +97,7 @@ typedef int (*kms_process_callback)(const char *key1_id, const char *key1_label,
|
||||
const char *description, const char *cipher,
|
||||
const char *iv_mode, const char *volumes,
|
||||
const char *volume_type, size_t sector_size,
|
||||
const char *passphrase,
|
||||
const char *addl_info_argz,
|
||||
size_t addl_info_len,
|
||||
void *private_data);
|
||||
@@ -118,6 +122,7 @@ int import_kms_key(struct kms_info *kms_info, const char *key1_id,
|
||||
int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
|
||||
char **description, char **cipher, char **iv_mode,
|
||||
char **volumes, char **volume_type, ssize_t *sector_size,
|
||||
const char *filename, bool verbose);
|
||||
const char *filename, const char *passphrase_file,
|
||||
bool verbose);
|
||||
|
||||
#endif
|
||||
|
||||
22
zkey/pkey.c
22
zkey/pkey.c
@@ -1337,7 +1337,7 @@ int validate_secure_key(int pkey_fd,
|
||||
int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose)
|
||||
{
|
||||
int tfmfd = -1, opfd = -1, rc = 0;
|
||||
int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0;
|
||||
char null_msg[ENC_ZERO_LEN];
|
||||
char enc_zero[ENC_ZERO_LEN];
|
||||
struct af_alg_iv *alg_iv;
|
||||
@@ -1385,12 +1385,30 @@ int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry_setkey:
|
||||
if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key,
|
||||
key_size) < 0) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "Failed to set the key");
|
||||
pr_verbose(verbose, "Failed to set the key: %s",
|
||||
strerror(-rc));
|
||||
|
||||
/*
|
||||
* After a master key change, it can happen that the setkey
|
||||
* operation returns EINVAL or EAGAIN, although the key is
|
||||
* valid. This is a temporary situation and the operation will
|
||||
* succeed, once the firmware has completed some internal
|
||||
* processing related with the master key change.
|
||||
* Delay 1 second and retry up to 10 times.
|
||||
*/
|
||||
if ((rc == -EINVAL || rc == -EAGAIN) && retry_count < 10) {
|
||||
pr_verbose(verbose, "Retrying after 1 second...");
|
||||
retry_count++;
|
||||
sleep(1);
|
||||
goto retry_setkey;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
opfd = accept(tfmfd, NULL, NULL);
|
||||
if (opfd < 0) {
|
||||
|
||||
201
zkey/utils.c
201
zkey/utils.c
@@ -15,6 +15,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -25,7 +26,8 @@
|
||||
#include "lib/util_rec.h"
|
||||
#include "lib/util_base.h"
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "properties.h"
|
||||
@@ -1128,6 +1130,7 @@ bool prompt_for_yes(bool verbose)
|
||||
{
|
||||
char str[20];
|
||||
|
||||
fflush(stdout);
|
||||
if (fgets(str, sizeof(str), stdin) == NULL)
|
||||
return false;
|
||||
|
||||
@@ -1174,3 +1177,199 @@ char *printable_mkvp(enum card_type cardtype, u8 *mkvp)
|
||||
|
||||
return mkvp_print_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the contents of one file into another file. If num_bytes is zero,
|
||||
* then all content until EOF of the input file is copied. Otherwise only up to
|
||||
* num_bytes is copied.
|
||||
*
|
||||
* @param[in] in_file_name the file name of the input file
|
||||
* @param[in] out_file_name the file name of the output file
|
||||
* @param[in] num_bytes the number of bytes to copy, or 0 to copy until
|
||||
* EOF of the input file
|
||||
*
|
||||
* @returns zero for success, or a negative error in case of an error
|
||||
*/
|
||||
int copy_file(const char *in_file_name, const char *out_file_name,
|
||||
size_t num_bytes)
|
||||
{
|
||||
FILE *fp_in = NULL, *fp_out = NULL;
|
||||
size_t num = 0, len;
|
||||
char buff[1024];
|
||||
int rc = 0;
|
||||
|
||||
fp_in = fopen(in_file_name, "r");
|
||||
if (fp_in == NULL) {
|
||||
rc = -errno;
|
||||
warnx("Failed to open '%s': %s", in_file_name, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
fp_out = fopen(out_file_name, "w");
|
||||
if (fp_out == NULL) {
|
||||
rc = -errno;
|
||||
warnx("Failed to open '%s': %s", out_file_name, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!feof(fp_in) && (num_bytes == 0 || num < num_bytes)) {
|
||||
len = fread(buff, 1, num_bytes == 0 ? sizeof(buff) :
|
||||
MIN(num_bytes - num, sizeof(buff)), fp_in);
|
||||
if (ferror(fp_in)) {
|
||||
rc = -EIO;
|
||||
warnx("Failed to read from '%s': %s", in_file_name,
|
||||
strerror(-rc));
|
||||
break;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
if (fwrite(buff, len, 1, fp_out) != 1) {
|
||||
rc = -errno;
|
||||
warnx("Failed to write to '%s': %s", out_file_name,
|
||||
strerror(-rc));
|
||||
break;
|
||||
}
|
||||
|
||||
num += len;
|
||||
}
|
||||
|
||||
out:
|
||||
if (fp_in != NULL)
|
||||
fclose(fp_in);
|
||||
if (fp_out != NULL)
|
||||
fclose(fp_out);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the passphrase from the specified file and returns the passphrase as
|
||||
* an base64 encoded string. The returned string must be freed by the caller.
|
||||
*
|
||||
* @param[in] filename the file name of the file containing the passphrase
|
||||
* @param[in] verbose if true, additional error messages are printed.
|
||||
*
|
||||
* @returns an allocated string
|
||||
*/
|
||||
char *read_passphrase_as_base64(const char *filename, bool verbose)
|
||||
{
|
||||
unsigned char *ret = NULL, *buf = NULL;
|
||||
int outlen, len;
|
||||
struct stat sb;
|
||||
FILE *fp;
|
||||
|
||||
if (stat(filename, &sb) != 0) {
|
||||
pr_verbose(verbose, "stat on file '%s' failed: %s", filename,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sb.st_size == 0) {
|
||||
pr_verbose(verbose, "File '%s' is empty", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
pr_verbose(verbose, "Open of file '%s' failed: %s", filename,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = malloc(sb.st_size);
|
||||
if (buf == NULL) {
|
||||
pr_verbose(verbose, "Malloc failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fread(buf, sb.st_size, 1, fp) != 1) {
|
||||
pr_verbose(verbose, "Reading file '%s' failed: %s", filename,
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
outlen = (sb.st_size / 3) * 4;
|
||||
if (sb.st_size % 3 > 0)
|
||||
outlen += 4;
|
||||
|
||||
ret = malloc(outlen + 1);
|
||||
if (ret == NULL) {
|
||||
pr_verbose(verbose, "Malloc failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = EVP_EncodeBlock(ret, buf, sb.st_size);
|
||||
if (len != outlen) {
|
||||
pr_verbose(verbose, "EVP_EncodeBlock failed");
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret[outlen] = '\0';
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
fclose(fp);
|
||||
|
||||
return (char *)ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the passphrase into the specified file. Decodes the base64 string into
|
||||
* bytes.
|
||||
*
|
||||
* @param[in] b64_string the passphrase as a base64 string
|
||||
* @param[in] filename the file name of the file containing the passphrase
|
||||
* @param[in] verbose if true, additional error messages are printed.
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
int store_passphrase_from_base64(const char *b64_string, const char *filename,
|
||||
bool verbose)
|
||||
{
|
||||
size_t len, outlen, rawlen, i;
|
||||
unsigned char *buf;
|
||||
FILE *fp = NULL;
|
||||
int rc = 0;
|
||||
|
||||
len = strlen(b64_string);
|
||||
rawlen = outlen = (len / 4) * 3;
|
||||
for (i = len - 1; b64_string[i] == '='; i--, rawlen--)
|
||||
;
|
||||
|
||||
buf = malloc(outlen);
|
||||
if (buf == NULL) {
|
||||
pr_verbose(verbose, "Malloc failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fp = fopen(filename, "w");
|
||||
if (fp == NULL) {
|
||||
pr_verbose(verbose, "Open of file '%s' failed: %s", filename,
|
||||
strerror(errno));
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = EVP_DecodeBlock(buf, (unsigned char *)b64_string, len);
|
||||
if (len != outlen) {
|
||||
pr_verbose(verbose, "EVP_DecodeBlock failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwrite(buf, rawlen, 1, fp) != 1) {
|
||||
pr_verbose(verbose, "Writing file '%s' failed: %s", filename,
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,4 +77,11 @@ bool prompt_for_yes(bool verbose);
|
||||
|
||||
char *printable_mkvp(enum card_type cardtype, u8 *mkvp);
|
||||
|
||||
int copy_file(const char *in_file_name, const char *out_file_name,
|
||||
size_t num_bytes);
|
||||
|
||||
char *read_passphrase_as_base64(const char *filename, bool verbose);
|
||||
int store_passphrase_from_base64(const char *hex_string, const char *filename,
|
||||
bool verbose);
|
||||
|
||||
#endif
|
||||
|
||||
110
zkey/zkey.1
110
zkey/zkey.1
@@ -126,6 +126,9 @@ key repository.
|
||||
.RB [ \-\-key-type | \-K
|
||||
.IR type ]
|
||||
.RB [ \-\-local | \-L ]
|
||||
.RB [ \-\-gen\-dummy\-passphrase ]
|
||||
.RB [ \-\-set\-dummy\-passphrase
|
||||
.IR passphrase\-file ]
|
||||
.RB [ KMS\-plugin\ specific\ options ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.PP
|
||||
@@ -379,6 +382,9 @@ EP11-AES to be installed. For the supported environments and downloads, see:
|
||||
.IR bytes ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-gen\-dummy\-passphrase ]
|
||||
.RB [ \-\-set\-dummy\-passphrase
|
||||
.IR passphrase\-file ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -515,6 +521,11 @@ because the secure key is contained in the LUKS2 header.
|
||||
.IR bytes ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
.RB [ \-\-gen\-dummy\-passphrase ]
|
||||
.RB [ \-\-set\-dummy\-passphrase
|
||||
.IR passphrase\-file ]
|
||||
.RB [ \-\-remove\-dummy\-passphrase ]
|
||||
.RB [ \-\-force | \-F ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -661,7 +672,7 @@ option to generate crypttab entries for the specified volume type only.
|
||||
For LUKS2 volumes, a passphrase is required. You are prompted for the
|
||||
passphrase during system startup when crypttab is evaluated, unless option
|
||||
.B \-\-key\-file
|
||||
is specified. Option
|
||||
is specified, or a dummy passphrase is associated with the secure key. Option
|
||||
.B \-\-tries
|
||||
specifies how often a passphrase can be re-entered. When option
|
||||
.B \-\-key\-file
|
||||
@@ -734,7 +745,7 @@ LUKS key slots is of less relevance.
|
||||
For LUKS2 volumes, a passphrase is required. You are prompted for the
|
||||
passphrase when running the generated commands, unless option
|
||||
.B \-\-key\-file
|
||||
is specified. Option
|
||||
is specified, or a dummy passphrase is associated with the secure key. Option
|
||||
.B \-\-tries
|
||||
specifies how often a passphrase can be re-entered. When option
|
||||
.B \-\-key\-file
|
||||
@@ -1236,6 +1247,26 @@ system plugin (KMS plugin) is bound to the secure key repository. If the
|
||||
repository is bound to a key management system plugin, then keys are generated
|
||||
using the key management system by default.
|
||||
.TP
|
||||
.BR \-\-gen\-dummy\-passphrase
|
||||
Generate a dummy passphrase randomly and associate it with the secure AES key
|
||||
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
|
||||
for the security of the volume(s), when an secure AES key is used to encrypt the
|
||||
volume(s), and can therefore be stored insecurely inside the secure key
|
||||
repository. If for a certain usage the passphrase is of relevance for
|
||||
security, then do not use this option. This option can only be specified for
|
||||
keys with a volume type of \fBluks2\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
|
||||
Set a dummy passphrase that is read from the specified file and associate it
|
||||
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
|
||||
is of less or no relevance for the security of the volume(s), when an secure
|
||||
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
|
||||
inside the secure key repository. If for a certain usage the passphrase is of
|
||||
relevance for security, then do not use this option. This option can only be
|
||||
specified for keys with a volume type of \fBluks2\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.B KMS-plugin specific options
|
||||
A key management system plugin may offer and even require plugin specific
|
||||
options that can be specified with the generate command when the secure key
|
||||
@@ -1372,6 +1403,26 @@ This option is only available if
|
||||
has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled,
|
||||
the default volume type is \fBplain\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-\-gen\-dummy\-passphrase
|
||||
Generate a dummy passphrase randomly and associate it with the secure AES key
|
||||
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
|
||||
for the security of the volume(s), when an secure AES key is used to encrypt the
|
||||
volume(s), and can therefore be stored insecurely inside the secure key
|
||||
repository. If for a certain usage the passphrase is of relevance for
|
||||
security, then do not use this option. This option can only be specified for
|
||||
keys with a volume type of \fBluks2\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
|
||||
Set a dummy passphrase that is read from the specified file and associate it
|
||||
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
|
||||
is of less or no relevance for the security of the volume(s), when an secure
|
||||
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
|
||||
inside the secure key repository. If for a certain usage the passphrase is of
|
||||
relevance for security, then do not use this option. This option can only be
|
||||
specified for keys with a volume type of \fBluks2\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
.
|
||||
@@ -1523,6 +1574,47 @@ This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-\-gen\-dummy\-passphrase
|
||||
Generate a dummy passphrase randomly and associate it with the secure AES key
|
||||
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
|
||||
for the security of the volume(s), when an secure AES key is used to encrypt the
|
||||
volume(s), and can therefore be stored insecurely inside the secure key
|
||||
repository. If for a certain usage the passphrase is of relevance for
|
||||
security, then do not use this option. This option can only be specified for
|
||||
keys with a volume type of \fBluks2\fP. When there is already a dummy
|
||||
passphrase associated with the key, you muts first remove the dummy passphrase
|
||||
with option \fB\-\-remove\-dummy\-passphrase\fP before you can associate a new
|
||||
dummy passphrase.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
|
||||
Set a dummy passphrase that is read from the specified file and associate it
|
||||
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
|
||||
is of less or no relevance for the security of the volume(s), when an secure
|
||||
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
|
||||
inside the secure key repository. If for a certain usage the passphrase is of
|
||||
relevance for security, then do not use this option. This option can only be
|
||||
specified for keys with a volume type of \fBluks2\fP. When there is already a
|
||||
dummy passphrase associated with the key, you muts first remove the dummy
|
||||
passphrase with option \fB\-\-remove\-dummy\-passphrase\fP before you can
|
||||
associate a new dummy passphrase.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-\-remove\-dummy\-passphrase
|
||||
Remove the associated dummy passphrase used with LUKS2 volume(s).
|
||||
The user is prompted to confirm the removal of the associated dummy passphrase.
|
||||
Use the \fB\-\-force\fP option to remove the associated dummy passphrase without
|
||||
prompting for a confirmation.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-F ", " \-\-force\fP
|
||||
The user is prompted to confirm the removal of the associated dummy passphrase.
|
||||
Use this option to remove the associated dummy passphrase without prompting for
|
||||
a confirmation.
|
||||
This option is only used for secure keys contained in the secure key repository,
|
||||
and can only be specified together with option
|
||||
\fB\-\-remove\-dummy\-passphrase\fP.
|
||||
.
|
||||
.
|
||||
.
|
||||
@@ -1590,8 +1682,9 @@ has been compiled with LUKS2 support enabled.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-\-key\-file\~\fIfile\-name\fP
|
||||
Reads the passphrase from the specified file. If this option is omitted, then
|
||||
you are prompted to enter the passphrase interactively during system startup.
|
||||
Reads the passphrase from the specified file. If this option is omitted, and
|
||||
no dummy passphrase is associated with the secure key, then you are prompted to
|
||||
enter the passphrase interactively during system startup.
|
||||
This option is passed to the generated crypttab entries for LUKS2 volumes, and
|
||||
is only available if
|
||||
.B zkey
|
||||
@@ -1677,10 +1770,11 @@ option, and is only available if
|
||||
has been compiled with LUKS2 support enabled.
|
||||
.TP
|
||||
.BR \-\-key\-file\~\fIfile\-name\fP
|
||||
Reads the passphrase from the specified file. If this option is omitted,
|
||||
or if the file\-name is \fI-\fP (a dash), then you are prompted to enter the
|
||||
passphrase interactively. This option is passed to the generated command(s)
|
||||
for LUKS2 volumes, and is only available if
|
||||
Reads the passphrase from the specified file. If this option is omitted, and
|
||||
no dummy passphrase is associated with the secure key, or if the file\-name is
|
||||
\fI-\fP (a dash), then you are prompted to enter the passphrase interactively.
|
||||
This option is passed to the generated command(s) for LUKS2 volumes, and is
|
||||
only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled.
|
||||
.TP
|
||||
|
||||
171
zkey/zkey.c
171
zkey/zkey.c
@@ -79,6 +79,9 @@ static struct zkey_globals {
|
||||
char *key_type;
|
||||
char *label;
|
||||
bool local;
|
||||
bool gen_passphrase;
|
||||
char *passphrase_file;
|
||||
bool remove_passphrase;
|
||||
bool kms_bound;
|
||||
bool run;
|
||||
bool batch_mode;
|
||||
@@ -156,6 +159,9 @@ static struct zkey_globals {
|
||||
#define OPT_NO_APQN_CHECK 262
|
||||
#define OPT_NO_VOLUME_CHECK 263
|
||||
#define OPT_REFRESH_PROPERTIES 264
|
||||
#define OPT_GEN_DUMMY_PASSPHRASE 265
|
||||
#define OPT_SET_DUMMY_PASSPHRASE 266
|
||||
#define OPT_REMOVE_DUMMY_PASSPHRASE 267
|
||||
|
||||
/*
|
||||
* Configuration of command line options
|
||||
@@ -271,6 +277,31 @@ static struct util_opt opt_vec[] = {
|
||||
"generated by the KMS per default.",
|
||||
.command = COMMAND_GENERATE,
|
||||
},
|
||||
{
|
||||
.option = { "gen-dummy-passphrase", 0, NULL,
|
||||
OPT_GEN_DUMMY_PASSPHRASE},
|
||||
.desc = "Generate a dummy passphrase and associate it with the "
|
||||
"secure AES key used to encrypt LUKS2 volume(s). The "
|
||||
"LUKS2 passphrase is of less or no relevance for the "
|
||||
"security of the volume(s), when an secure AES key is "
|
||||
"used to encrypt the volume(s), and can therefore be "
|
||||
"stored insecurely inside the secure key repository.",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
.command = COMMAND_GENERATE,
|
||||
},
|
||||
{
|
||||
.option = { "set-dummy-passphrase", required_argument, NULL,
|
||||
OPT_SET_DUMMY_PASSPHRASE},
|
||||
.argument = "passphrase-file",
|
||||
.desc = "Set a dummy passphrase to be associated with the "
|
||||
"secure AES key used to encrypt LUKS2 volume(s). The "
|
||||
"LUKS2 passphrase is of less or no relevance for the "
|
||||
"security of the volume(s), when an secure AES key is "
|
||||
"used to encrypt the volume(s), and can therefore be "
|
||||
"stored insecurely inside the secure key repository.",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
.command = COMMAND_GENERATE,
|
||||
},
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -429,6 +460,31 @@ static struct util_opt opt_vec[] = {
|
||||
.command = COMMAND_IMPORT,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.option = { "gen-dummy-passphrase", 0, NULL,
|
||||
OPT_GEN_DUMMY_PASSPHRASE},
|
||||
.desc = "Generate a dummy passphrase and associate it with the "
|
||||
"secure AES key used to encrypt LUKS2 volume(s). The "
|
||||
"LUKS2 passphrase is of less or no relevance for the "
|
||||
"security of the volume(s), when an secure AES key is "
|
||||
"used to encrypt the volume(s), and can therefore be "
|
||||
"stored insecurely inside the secure key repository.",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
.command = COMMAND_IMPORT,
|
||||
},
|
||||
{
|
||||
.option = { "set-dummy-passphrase", required_argument, NULL,
|
||||
OPT_SET_DUMMY_PASSPHRASE},
|
||||
.argument = "passphrase-file",
|
||||
.desc = "Set a dummy passphrase to be associated with the "
|
||||
"secure AES key used to encrypt LUKS2 volume(s). The "
|
||||
"LUKS2 passphrase is of less or no relevance for the "
|
||||
"security of the volume(s), when an secure AES key is "
|
||||
"used to encrypt the volume(s), and can therefore be "
|
||||
"stored insecurely inside the secure key repository.",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
.command = COMMAND_IMPORT,
|
||||
},
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -593,6 +649,45 @@ static struct util_opt opt_vec[] = {
|
||||
.command = COMMAND_CHANGE,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.option = { "gen-dummy-passphrase", 0, NULL,
|
||||
OPT_GEN_DUMMY_PASSPHRASE},
|
||||
.desc = "Generate a dummy passphrase and associate it with the "
|
||||
"secure AES key used to encrypt LUKS2 volume(s). The "
|
||||
"LUKS2 passphrase is of less or no relevance for the "
|
||||
"security of the volume(s), when an secure AES key is "
|
||||
"used to encrypt the volume(s), and can therefore be "
|
||||
"stored insecurely inside the secure key repository.",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
.command = COMMAND_CHANGE,
|
||||
},
|
||||
{
|
||||
.option = { "set-dummy-passphrase", required_argument, NULL,
|
||||
OPT_SET_DUMMY_PASSPHRASE},
|
||||
.argument = "passphrase-file",
|
||||
.desc = "Set a dummy passphrase to be associated with the "
|
||||
"secure AES key used to encrypt LUKS2 volume(s). The "
|
||||
"LUKS2 passphrase is of less or no relevance for the "
|
||||
"security of the volume(s), when an secure AES key is "
|
||||
"used to encrypt the volume(s), and can therefore be "
|
||||
"stored insecurely inside the secure key repository.",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
.command = COMMAND_CHANGE,
|
||||
},
|
||||
{
|
||||
.option = { "remove-dummy-passphrase", 0, NULL,
|
||||
OPT_REMOVE_DUMMY_PASSPHRASE},
|
||||
.desc = "Remove an associated dummy passphrase used with LUKS2 "
|
||||
"volume(s).",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
.command = COMMAND_CHANGE,
|
||||
},
|
||||
{
|
||||
.option = {"force", 0, NULL, 'F'},
|
||||
.desc = "Do not prompt for a confirmation when removing an "
|
||||
"associated dummy passphrase",
|
||||
.command = COMMAND_CHANGE,
|
||||
},
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -1631,6 +1726,14 @@ static int command_generate_repository(void)
|
||||
if (g.sector_size < 0)
|
||||
g.sector_size = 0;
|
||||
|
||||
if (g.gen_passphrase && g.passphrase_file != NULL) {
|
||||
warnx("Either '--gen-dummy-passphrase' or "
|
||||
"'--set-dummy-passphrase' can be specified, but not "
|
||||
"both");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (g.kms_info.plugin_lib != NULL && !g.local) {
|
||||
if (g.apqns != NULL) {
|
||||
warnx("Option '--apqns|-a' is not valid for "
|
||||
@@ -1655,6 +1758,8 @@ static int command_generate_repository(void)
|
||||
g.description, g.volumes,
|
||||
g.sector_size, g.keybits, g.xts,
|
||||
g.volume_type, g.key_type,
|
||||
g.gen_passphrase,
|
||||
g.passphrase_file,
|
||||
g.kms_options,
|
||||
g.num_kms_options);
|
||||
goto out;
|
||||
@@ -1666,7 +1771,8 @@ static int command_generate_repository(void)
|
||||
rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.noapqncheck, g.sector_size,
|
||||
g.keybits, g.xts, g.clearkeyfile,
|
||||
g.volume_type, g.key_type, g.pkey_fd);
|
||||
g.volume_type, g.key_type, g.gen_passphrase,
|
||||
g.passphrase_file, g.pkey_fd);
|
||||
|
||||
out:
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
@@ -1729,6 +1835,18 @@ static int command_generate(void)
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (g.gen_passphrase) {
|
||||
warnx("Option '--gen-dummy-passphrase' is not valid "
|
||||
"for generating a key outside of the repository");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (g.passphrase_file != NULL) {
|
||||
warnx("Option '--sen-dummy-passphrase' is not valid "
|
||||
"for generating a key outside of the repository");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rc = cross_check_apqns(NULL, NULL,
|
||||
get_min_card_level_for_keytype(g.key_type),
|
||||
@@ -2111,10 +2229,19 @@ static int command_import(void)
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (g.gen_passphrase && g.passphrase_file != NULL) {
|
||||
warnx("Either '--gen-dummy-passphrase' or "
|
||||
"'--set-dummy-passphrase' can be specified, but not "
|
||||
"both");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.noapqncheck, g.sector_size,
|
||||
g.pos_arg, g.volume_type, &g.lib);
|
||||
g.pos_arg, g.volume_type, g.gen_passphrase,
|
||||
g.passphrase_file, &g.lib);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -2200,10 +2327,39 @@ static int command_change(void)
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (g.gen_passphrase && g.passphrase_file != NULL) {
|
||||
warnx("Either '--gen-dummy-passphrase' or "
|
||||
"'--set-dummy-passphrase' can be specified, but not "
|
||||
"both");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (g.gen_passphrase && g.remove_passphrase) {
|
||||
warnx("Either '--gen-dummy-passphrase' or "
|
||||
"'--remove-dummy-passphrase' can be specified, but not "
|
||||
"both");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (g.passphrase_file != NULL && g.remove_passphrase) {
|
||||
warnx("Either '--set-dummy-passphrase' or "
|
||||
"'--remove-dummy-passphrase' can be specified, but not "
|
||||
"both");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (g.force && !g.remove_passphrase) {
|
||||
warnx("Option '--force|-F' is only valid together with "
|
||||
"the '--remove-dummy-passphrase' option");
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.noapqncheck, g.sector_size,
|
||||
g.volume_type);
|
||||
g.volume_type, g.gen_passphrase,
|
||||
g.passphrase_file, g.remove_passphrase,
|
||||
g.force);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -3056,6 +3212,15 @@ int main(int argc, char *argv[])
|
||||
case 'P':
|
||||
g.refresh_properties = 1;
|
||||
break;
|
||||
case OPT_GEN_DUMMY_PASSPHRASE:
|
||||
g.gen_passphrase = 1;
|
||||
break;
|
||||
case OPT_SET_DUMMY_PASSPHRASE:
|
||||
g.passphrase_file = optarg;
|
||||
break;
|
||||
case OPT_REMOVE_DUMMY_PASSPHRASE:
|
||||
g.remove_passphrase = 1;
|
||||
break;
|
||||
case 'h':
|
||||
print_help(command, sub_command);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user