Compare commits

..

79 Commits

Author SHA1 Message Date
Jan Höppner
094905af87 New release s390-tools-2.12.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-17 13:51:48 +01:00
Jan Höppner
dcce14923c zipl: Add missing options to help output
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Ingo Franzki
1fd78d9f5e zkey: Fix convert command to use an associated APQN of a key
The zkey convert command must select an CCA adapter out of the
list of associated APQNs (if any) to perform the key conversion.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Marc Hartmayer
9d1baaa594 zipl: stfle: use uint64_t instead of u64
As the definition of `stfle_fac_list` in the lowcore uses uint64_t, we
should also use uint64_t for the `stfle_fac_list` parameter of the
`stfle/__stfle_asm` function.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Marc Hartmayer
efcfbce386 netboot/zipl: use '$(MAKE)' instead of 'make'
Use '$(MAKE)' to pass down the makefile flags.

This fixes the warning:

make[4]: warning: jobserver unavailable: using -j1.  Add '+' to parent make rule.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Jan Höppner
3d74c534bf libdasd: Fix flag for opening read-only devices
dasd_is_ro() uses the O_RDWR flag when opening the file descriptor.
However, an attempt to open the file descriptor of a device that is in
read-only state will fail and the BLKROGET ioctl that is used to
actually determine the read-only state can't be issued.
Change the flag to O_RDONLY to fix this.

Fixes: a5c1923d32 ("libdasd: Add common DASD ioctl's to the lib")
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Jan Höppner
ca2ffe9e18 libdasd: Close file descriptor after use
Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/77
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Ingo Franzki
52192908eb zkey: Fix typo in help output
The help output for 'zkey generate' has a typo in the description
of the '-N, --name' option mentioning a non-existing '-M' option.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Ingo Franzki
d4cee7e65a zkey: Fix APQN checking
An invalid APQN like '01.00xx' is not treated as invalid, but results
in APQN '01.0000'. Fix the checking to treat such invalid APQNs as
invalid.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Jan Höppner
bfbf456b83 dasdview: Fix exit status in error cases
In error cases, dasdview returns -1 which results in the return value
255. This is due to the fact that only the low-order 8 bits are used for
the status value. See 2.13 Status Information [1] in the POSIX standard
and the exit() POSIX man page [2] for more details.

Instead of returning -1, use the EXIT_FAILURE constant to indicate
unsuccessful termination properly. This change also makes the exit
status consistent for all error cases in dasdview, as some exit() calls
already use EXIT_FAILURE.

[1]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html
[2]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/exit.html

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Sa Liu
235e997a77 dbginfo: journalctl from the current system time with more number of lines and precise timestamp
Signed-off-by: Sa Liu <saliu@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Sa Liu
c079e48d7d dbginfo: Collect all files under /usr/lib/systemd/system/
Signed-off-by: Sa Liu <saliu@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
4762e65acb zipl: Consolidate STAGE{2,3} macros
Increase consistency with the other macros by moving and renaming
the STAGE{2,3} macros in zipl.h.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
cb614ed1ee zipl: Consolidate IMAGE macros
Combine the different macros for 0x10000 and use a consistent naming
schema.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
8face3e63e zipl/libc: Use stdint.h instead of self defined macros
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
ea14f5471c zipl: Make address/size/mask macros UL
While at it also fix some white space damages.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
b2ae5a91ac zipl/sclp: Remove duplicate macros
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
edfb6a03d8 zipl/stage3: Mark start_kernel __noreturn
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
5eace91ee7 zipl: Define __noinline macro and make use of it
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
86856f98db zipl: Make use of __noreturn macro
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
154734efc7 zipl: define __section macro and make use of it
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
c7fcb457b0 zfcpdump: Make use of __packed macro
Make use of the pre-defined __packed macro throughout zfcpdump.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
244bf4e550 zdump: Make use of __packed macro
Make use of the pre-defined __packed macro throughout zdump.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
0f7ed7d4fc zipl: Make use of __packed macro
Make use of the pre-defined __packed macro throughout zipl. This
requires adding the global include dir to ALL_CFLAGS.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
121d5d8013 zipl: Fix dependency generation in zipl/boot
When adding new header from zipl/include to a .c file within zipl/boot
a compiler error appears

	stage3.c:16:10: fatal error: zipl.h: No such file or directory
	 #include "zipl.h"
	          ^~~~~~~~
	compilation terminated.
	  CC      zipl/boot/stage3.o

This is because the rule to generate dependencies (*.o.d) does not use
the CFLAGS_BOOT. Thus it cannot find the header and fails. Note this
only applies to the dependency generation, the actual build succeeds.

To fix this rename the CFLAGS_BOOT to ALL_CFLAGS. Using ALL_CFLAGS
instead of e.g. ALL_CPPFLAGS is important to also overwrite flags given
on the commandline via OPT_FLAGS, e.g.

	make V=1 OPT_FLAGS="-D__FOO__"

While at it also remove the unused and wrong '-D__ASSEMBLY__'.

Fixes: 5a6605fe ("zipl: Ensure that boot loader CFLAGS are not overwritten")
Fixes: aa913b1e ("build process: Add automatic dependency generation")
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Philipp Rudo
abe0ba7412 zipl: Fix entry point for stand-alone kdump
Currently zipl doesn't differentiate between the load address and the
entry point of an image, causing stage3 to strip away the entry point at
0x10000 for stand-alone kdump. This breaks the kdump kernel as it jumps
to 0x10000 after the special handling needed for kdump has been
performed.

Fix this by differentiating between the load address and the entry point
of an image.

Fixes: d142fbd5 ("zipl: Do not strip kernel image IPL header")
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Marc Hartmayer
2227bb8330 zipl: remove some useless __packed___ attributes
The __packed__ attribute is not needed for these structures as they
don't need any padding to meet the size and alignment constraints
defined in the Linux for zSeries ABI.

Reported by GCC 9.2.1 when building with '-Waddress-of-packed-member'.

stage3.c: In function 'is_verified_address':
stage3.c:241:26: warning: taking address of packed member of 'struct ipl_rb_components' may result in an unaligned pointer value [-Waddress-of-packed-member]
  241 |  for_each_rb_entry(comp, comps) {
      |                          ^~~~~
stage3.c:18:15: note: in definition of macro 'for_each_rb_entry'
   18 |  for (entry = rb->entries; \
      |               ^~
  CC      zipl/boot/kdump3.o
  CC      zipl/boot/sclp_stage3.o
sclp_stage3.c: In function '__sclp_hsa_copy':
sclp_stage3.c:75:34: warning: converting a packed 'struct sdias_sccb' pointer (alignment 1) to a 'struct read_sccb' pointer (alignment 4096) may result in an unaligned pointer value [-Waddress-of-packed-member]
   75 |   if (sclp_hsa_copy_wait((struct read_sccb *)sccb))
      |                                  ^~~~~~~~~
In file included from sclp_stage3.c:13:
sclp_stage3.h:43:8: note: defined here
   43 | struct sdias_sccb {
      |        ^~~~~~~~~~
In file included from sclp_stage3.c:12:
sclp.h:149:8: note: defined here
  149 | struct read_sccb {
      |        ^~~~~~~~~
sclp_stage3.c: In function 'sclp_hsa_get_size':
sclp_stage3.c:126:34: warning: converting a packed 'struct sdias_sccb' pointer (alignment 1) to a 'struct read_sccb' pointer (alignment 4096) may result in an unaligned pointer value [-Waddress-of-packed-member]
  126 |   if (sclp_hsa_copy_wait((struct read_sccb *)sccb))
      |                                  ^~~~~~~~~
In file included from sclp_stage3.c:13:
sclp_stage3.h:43:8: note: defined here
   43 | struct sdias_sccb {
      |        ^~~~~~~~~~
In file included from sclp_stage3.c:12:
sclp.h:149:8: note: defined here
  149 | struct read_sccb {
      |        ^~~~~~~~~

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Marc Hartmayer
aa09b29248 zipl: fix -Waddress-of-packed-member
Reported by GCC 9.2.1 when building with '-Waddress-of-packed-member'.

menu.c: In function 'menu_read':
menu.c:30:22: warning: taking address of packed member of 'struct boot_stage2_params' may result in an unaligned pointer value [-Waddress-of-packed-member]
   30 |  uint16_t *configs = __stage2_params.config;
      |                      ^~~~~~~~~~~~~~~
menu.c: In function 'menu_list':
menu.c:83:22: warning: taking address of packed member of 'struct boot_stage2_params' may result in an unaligned pointer value [-Waddress-of-packed-member]
   83 |  uint16_t *configs = __stage2_params.config;
      |                      ^~~~~~~~~~~~~~~
menu.c: In function 'menu':
menu.c:139:22: warning: taking address of packed member of 'struct boot_stage2_params' may result in an unaligned pointer value [-Waddress-of-packed-member]
  139 |  uint16_t *configs = __stage2_params.config;
      |                      ^~~~~~~~~~~~~~~

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Marc Hartmayer
2790d4faaa zipl: fix -Wmaybe-uninitialized
Reported by GCC 9.2.1 when building with '-Wmaybe-uninitialized'.

job.c: In function 'job_get':
job.c:1817:14: warning: 'filename' may be used uninitialized in this function [-Wmaybe-uninitialized]
 1817 |  scan_size = scan_file(filename, &scan);
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~
job.c:1791:14: note: 'filename' was declared here
 1791 |  const char *filename;
      |              ^~~~~~~~

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Marc Hartmayer
bbc46edaf5 zipl: fix -Wdiscarded-qualifiers
Reported by GCC 9.2.1 when building with '-Wdiscarded-qualifiers'.

job.c: In function 'get_job_from_config_file':
job.c:1810:14: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Jan Höppner
e5c0fb249b ziomon: Move dependency check for blktrace
When calling ziomon --version (or --help) the tool already checks
whether blktrace is present and prevents any output for those command
options when it isn't. This is unnecessary as no actual command is
issued during the parameter check and all other dependencies are checked
at a later point as well.

Move the dependency check to ensure a working --version and --help
option at any time.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Jan Höppner
b6d8e5833c libdasd: Use DASD_BUS_ID_SIZE
Use the define instead of an hardcoded number.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-12-12 18:04:32 +01:00
Tuan Hoang
d71628326d zipl: add value of target= as search path for BLS case
In the BLS files, the 'linux' and 'initrd' fields are relative to the
$BOOT directory. If $BOOT is a mount point of boot partition, 'linux'
and 'initrd' fields are relative to boot partition. If not, the paths
are relative to $BOOT directory of root partition.

zipl always starts searching at / regardless of partitions and mount
points.

This commit extends the semantics of target= field in zipl.conf to make
it as a second search path, besides /, for those 2 BLS fields.

See issues #69 for more details.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/69
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/74
Signed-off-by: Tuan Hoang <tmhoang@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-10-17 16:35:01 +02:00
Javier Martinez Canillas
8bfe18e674 zipl: fix the scanned tokens array size calculation
The zipl config file (zipl.conf) and the BootLoaderSpec (BLS) fragments
in /boot/loader/entries define a set of tokens that are parsed by zipl.

These are stored in an array of tokens whose size is calculated to make
sure that there is enough memory allocated for all the scanned tokens.

But the size calculation logic was wrong, since it was checking if the
current size was enough to store a single token per BLS fragment, while
up to 4 tokens can be defined in a BLS file: a section heading and the
image, ramdisk and parameter keywords.

This led to zipl being killed by a SIGABRT signal when trying to parse
more tokens than the ones that could fit in the scanned tokens array:

Using config file '/etc/zipl.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-9.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-8.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-7.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-6.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-5.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-4.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-3.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-2.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-1.conf'
Using BLS config file '/boot/loader/entries/vmlinuz-0.conf'
double free or corruption (out)
Aborted (core dumped)

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/68
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/73
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-10-17 16:35:01 +02:00
Tuan Hoang
275105fe3d zipl: allow check for other locations of zipl.conf
Allow zipl to find zipl.conf in following order:
/run/zipl/zipl.conf
/etc/zipl.conf
/lib/s390-tools/zipl.conf

Whichever is found first will be used.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/70
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/71
Signed-off-by: Tuan Hoang <tmhoang@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-10-17 16:35:01 +02:00
Tuan Hoang
19259aeb65 zipl: ship a minimal zipl.conf
Ship a minimal zipl configuration file at /lib/s390-tools/zipl.conf by
default which would help systems using BLS files, without having to
create the traditional /etc/zipl.conf file.

GitHub-ID: https://github.com/ibm-s390-tools/s390-tools/issues/70
GitHub-ID: https://github.com/ibm-s390-tools/s390-tools/pull/71
Signed-off-by: Tuan Hoang <tmhoang@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-10-17 16:35:01 +02:00
Julian Wiedmann
125df52887 dbginfo: collect qdisc statistics
This can be helpful in diagnosing network-related issues.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-10-17 16:35:01 +02:00
Julian Wiedmann
852fb9dfb8 dbginfo: collect extended network interface statistics
The basic statistics are already collected via ifconfig. But that tool
is deprecated, and provides no way of collecting the extended stats.
So also gather data from 'ip link'.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-10-17 16:35:01 +02:00
Jens Remus
b0fe75b92f zipl: remove duplicate statement
The duplicate statement does not have any effect. Therefore remove it.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-10-17 16:35:01 +02:00
Ingo Franzki
bc987c8d18 zkey: Allow 'zkey-cryptsetup setkey' to set different key types
When a secure key has been converted from type CCA-AESDATA to type
CCA-AESCIPHER, the secure key stored in the LUKS2 header of a volume
encrypted with that key should also changed.

Command 'zkey-cryptsetup setkey' allows to set (replace) the volume
key in the LUKS2 header. It now accepts keys to be set that have
a different size of the original volume keys. CCA-AESCIPHER keys
are larger than CCA-AESDATA keys.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
a86e41a518 zkey: Add 'convert' command to convert keys from one type to another
Add a new 'convert' command. It allows to convert a secure key from
one key type to another. Currently only keys of type CCA-AESDATA can be
converted to CCA-AESCIPHER.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
0d9e42264d zkey: Add key checks when importing a CCA-AESCIPHER key
Perform extended checks on a secure key that is imported into
the key repository. Warn the user if the imported key is by
any means insecure, e.g. has been originally created in an
insecure way. Prompt the user to continue the import if a
potential insecurity is detected.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
7fede7021e zkey: Add helper function to check an AES CIPHER key
The helper function performs a deep check of the AES CIPHER key
token and checks for any potentially insecure attributes.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
e7d79d5c5c zkey: Add helper function to restrict export of secure keys
Secure keys of type CCA-AESCIPHER can be export restricted, so that
these keys can not be exported by another key.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
7d4b1e18b6 zkey: Add helper function to convert secure keys between key types
Add a helper function to convert a secure key from key type
CCA-AESDATA to CCA-AESCIPHER.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
b0cc0e4737 zkey: Add helper function to query the CCA firmware version
Some future functions are dependent on the firmware version of the
CCA crypto adapter. This helper function allows to query the version
of the currently selected CCA adapter.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
b7bb90c552 zkey: Check crypto card level during APQN cross checking
Secure keys of type CCA-AESCIPHER require a CEX6C or newer crypto
card. Also check for the minimum required card level during cross
checking of APQNs. Also display the card level in the APQN report.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
560b672bfa zkey: Add support for re-enciphering AES CIPHER keys
For secure keys of type CCA-AESCIPHER the CCA verb CSNBKTC2
(Key Token Change2) is used. CCA-AESDATA keys will continue
to use CCA verb CSNBKTC (Key Token Change).

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
0fab6bdf2a zkey: Add support for validating AES CIPHER keys
Add support for validating secure keys using the new pkey
IOCTLs. This allows to validate secure keys of type CCA-AESDATA
as well as CCA-AESCIPHER.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
b56c74fe7b zkey: Add support for generating AES CIPHER keys
Add support for generating secure keys using the new pkey
IOCTLs. This allows to generate secure keys of type CCA-AESDATA
as well as CCA-AESCIPHER, either by random inside the crypto
card, or from a given clear key.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
663d362ff3 zkey: Add helper functions to build lists of APQNs
The new IOCTLs are based on list of APQNs that they try to send
the request to. Add some helper functions to build such lists
of APQNs based on the key type, and optionally a given mkvp.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
d4027e6506 zkey: Add wrappers for the new IOCTLs with fallback to the old once
By default the new pkey IOCTL are used. In case the pkey device does not
support the new IOCTLs (i.e. errno ENOTTY is returned), then the wrapper
falls back to the old IOCTLs. The old IOCTLs only support secure keys of
type CCA-AESDATA.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
ddde3f354f zkey: Introduce the CCA-AESCIPHER key type
Add definitions and helper functions to support the new
CCA-AESCIPHER key type. Also enhance existing helper functions
to support CCA-AESCIPHER keys.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
298fab68fe zkey: Preparations for introducing a new key type
Introduce helper functions and definitions to allow key type
independent code in the keystore implementation

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
b47007b8ac zkey: Allow to specify the key type with the generate command
The zkey generate command allows to specify the --key-type|-K
option to specify the key type. If not specified, then the
default is CCA-AESDATA.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
91c35543ca zkey: Allow to filter list output by key type
The zkey list command now accepts option --key-type|-K type
to filter the displayed keys by key type. If not specified,
then all key types are displayed.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
9de85f4295 zkey: Display key type with list and validate commands
For the 'zkey list', 'zkey validate' and 'zkey-cryptsetup validate'
commands, display the key type.

As of today there is only one possible key type (CCA-AESDATA),
but in the future there might be additional key types.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
e15e8a1bfa zcryptstats: Add support for CEX7
Add the CEX7 crypto card to the list of known crypto cards.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Harald Freudenberger
4fc0c3cfef zcrypt: CEX7S exploitation support
This patch adds CEX7S exploitation support to lszcrypt and chzcrypt.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
a0ed6709cf zkey-cryptsetup: Add --to-new and --from-old options
To allow better control about the secure AES volume key re-enciphering
with 'zkey-cryptsetup reencipher', add options '--to-new' and '--from-old'
to specify if a re-enciphering from CURRENT to NEW, or OLD to CURRENT master
key registers is to be performed. If these options are not specified, then
it is auto-detected, based on the master key that the secure key is currently
re-enciphered with.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
552a915465 zkey: Select CCA adapter when re-enciphering
When re-enciphering secure AES keys, select the correct APQN for used
with the CCA host library. Re-enciphering a secure key requires the use
of the CCA host library. The APQN is selected based on the master key
verification pattern obtained from the secure key to re-encipher.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
1091b0bf65 zkey: Add function to select a CCA adapter by mkvp
Add a utility function to select an APQN that is set up with
a specific master key for use with the CCA host library. The
selection is based on the master key verification pattern, which
is typically obtained from an existing secure AES key.

The function iterates over a set of APQNs to find one that is setup
with the desired master key in the CURRENT or OLD master key register,
and optionally has a new master key loaded. It then selects the found
APQN for use with the CCA host library.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
016a0a56fc zkey: Add function to select a specific CCA adapter
Some operations require the CCA host library to be used, such as
re-enciphering a secure key. The CCA host library uses a different
approach to select the APQN it operates with. To ensure that the
desired APQN is used for an operation, a utility function is added
to select a specific APQN for usage with the CCA host library.

The CCA host library allows to set environment variables to override
the default CCA APQN selection. The environment variables are inspected
during CCA host library initialization only. To select a specific
domain for CCA, the CSU_DEFAULT_DOMAIN environment variable is set,
and then the CCA host library is un-loaded and re-loaded again.
Furthermore, the 'Cryptographic Resource Allocate' verb of the CCA
host library is used together with the 'Cryptographic Facility Query
function' verb to iterate over the crypto cards known by the CCA host
library, and to identify the desired crypto card based on its serial
number. That way, a specific APQN can be selected for use with
subsequent CCA verbs.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
0b4cbf0041 zkey: Cross check APQNs when changing APQN associations
Perform a cross check of the APQNs when the APQN association of a
secure AES key in the key repository is changed. When adding new APQNs,
or associating a new set of APQNs to a secure key, then the APQNs are
cross checked. If all associated APQNs are removed, then all currently
available APQNs are cross checked. If a master key mismatch is detected,
then the change is rejected.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
d854aed4b8 zkey: Cross check APQNs when importing secure keys
Perform a cross check of the APQNs when an existing secure AES key is
imported into the key repository. When a set of APQNs are associated to
the imported secure key, these APQNs are cross checked. If no APQNs are
associated to imported secure key, then all currently available
APQNs are cross checked. If a master key mismatch is detected, then
the key import is rejected.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
7f8e31e861 zkey: Cross check APQNs when validating secure keys
Perform a cross check of the APQNs when a secure AES key is validated.
When a set of APQNs are associated to a secure key, these APQNs are
cross checked. If a secure key is validated outside of the key repository,
or no APQNs are associated to a secure key inside the key repository,
then all currently available APQNs are cross checked. If a master key
mismatch is detected, then an error message is issued.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
a5b58038a0 zkey: Cross check APQNs when generating secure keys
Perform a cross check of the APQNs when a new secure AES key is
generated. When a set of APQNs are associated to a new secure key,
these APQNs are cross checked. If a new secure key is generated
outside of the key repository, or no APQNs are associated to a secure
key generated inside the key repository, then all currently available
APQNs are cross checked. If a master key mismatch is detected, then
the key generation is rejected.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
c2244a5795 zkey: Display MKVP when validating a secure key
Display the master key verification pattern of a secure key while
'zkey validate' and 'zkey-cryptsetup validate'

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
ea7cc9ea60 zkey: Add function to obtain the mkvp of a secure key
A secure AES key token contains the master key verification pattern
of the master key it is encrypted with. Add a function to obtain the
master key verification pattern of a secure key token.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
b32c031474 zkey: Add function to cross check APQNs for valid master keys
Add a utility function to cross check the master keys of a set of
APQNs. It checks for valid master keys in the CURRENT and OLD
master key registers, as well as newly loaded master keys in the NEW
register. It issues information and warning messages for various
findings and also indicates improper master key setup to the caller.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
bfc3dd018c zkey: Add function to print the MKVPs of APQNs
Add a utility function to print the master key verification patterns
of a set of APQNs. This allows the user to visually check which
master keys are set on which APQNs.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
625b81130a zkey: add function to iterate over all available CCA APQNs
Add a utility function to iterate over all available APQNs of
type CCA-Coprocessor. This function is required for various
future enhancements.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
bf8872e94a zkey: Add utility function to get the mkvp of a crypto card
With recent changes in the zcrypt device driver, the master key verifi-
cation patterns of the AES master key of am APQN can be obtained by
reading the sysfs attribute 'mkvps' of an APQN device of type CCA-
Coprocessor. The sysfs attribute can be found under
'/sys/devices/ap/cardnn/nn.mmmm/', where nn specifies the card number
in hex, and mmmm specifies the domain number on hex.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
a84d1c5d58 zkey: Add utility function to get the serial number of a crypto card
With recent changes in the zcrypt device driver, the serial number of
a crypto card can be obtained by reading the sysfs attribute 'serialnr'
of a crypto card device of type CCA-Coprocessor. The sysfs attribute
can be found under '/sys/devices/ap/cardnn/', where nn specifies the
card number in hex.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
696e8458f0 zkey: Move utility functions into separate source file
As preparation for future changes, move a sysfs specific functions
into a separate source file (utils.c).

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Ingo Franzki
95c7258ea7 zkey: Separate and rework CCA host library loading
As preparation for future changes, rework the loading of the
CCA host library so that the exported symbols are not passed
individually to the functions that use it. Pass a structure
that contains all entry points of all loaded CCA functions
instead. This will make it easier to add further CCA functions
at a later time.

Also add a version query for the CCA host library since some
future functions might be dependent on the library version.

While at it, separate the CCA related functions and definitions,
and move them into a separate source file (cca.h/cca.h).

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Thomas Richter
21de913a5e cpumf/bin/cpumf_helper.in: Add IBM z15 machine name
Add IBM z15 as official machine name to lscpumf command
output.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Sa Liu
7a2a96e8a3 dbginfo: add hyptop output for z/VM and LPAR.
Signed-off-by: Sa Liu <saliu@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-18 12:55:17 +02:00
Jan Höppner
7a569c7e33 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2019-09-06 14:13:49 +02:00
72 changed files with 5220 additions and 976 deletions

View File

@@ -98,6 +98,7 @@ List of all individuals having contributed content to s390-tools
- Thomas Richter
- Thomas Spatzier
- Thomas Weber
- Tuan Hoang
- Ursula Braun
- Utz Bacher
- Vasily Gorbik

View File

@@ -1,5 +1,33 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.12.0 (2019-12-17)__
For Linux kernel version: 5.4
Changes of existing tools:
- dbginfo: Gather qdisc related data (using 'tc')
- dbginfo: Gather extended network statistics (using 'ip link')
- dbginfo: Collect all files under /usr/lib/systemd/system/
- cpumf/cpumf_helper: Add IBM z15 machine name
- zkey: Display MKVP when validating a secure key
- zkey: Cross check APQNs when generating, validating, or importing secure keys,
and when changing APQN associations
- zkey: Check crypto card level during APQN cross checking
- zkey: Add support for generating, validating, and re-enciphering AES CIPHER keys
- zkey-cryptsetup: Add --to-new and --from-old options
- zkey-cryptsetup: Allow setkey to set different key types
- lszcrypt/chzcrypt: CEX7S exploitation support
- zcryptstats: Add support for CEX7 crypto card
- zipl: Ship a minimal zipl.conf
- zipl: Add value of target= as search path for BLS case
Bug Fixes:
- dasdview: Fix exit status in error cases
- zipl: Fix various compile warnings
- zipl: Fix dependency generation in zipl/boot
- zipl: Fix entry point for stand-alone kdump
- zipl: Add missing options to help output
* __v2.11.0 (2019-09-06)__
For Linux kernel version: 5.3

View File

@@ -5,7 +5,7 @@ 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 = 11
RELEASE = 12
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)

View File

@@ -213,6 +213,7 @@ my $system_z_hwtype_map = {
2965 => 'IBM z13s',
3906 => 'IBM z14',
3907 => 'IBM z14 ZR1',
8561 => 'IBM z15',
};
sub get_hardware_type()

View File

@@ -160,19 +160,19 @@ dasdview_get_info(dasdview_info_t *info)
if (err != EBADF)
zt_error_print("dasdview: "
"Could not retrieve geo information!\n");
exit(-1);
exit(EXIT_FAILURE);
}
if (dasd_get_blocksize(info->device, &info->blksize) != 0) {
zt_error_print("dasdview: "
"Could not retrieve blocksize information!\n");
exit(-1);
exit(EXIT_FAILURE);
}
if (dasd_get_info(info->device, &info->dasd_info) != 0) {
zt_error_print("dasdview: "
"Could not retrieve disk information!\n");
exit(-1);
exit(EXIT_FAILURE);
}
characteristics = (struct dasd_eckd_characteristics *)
@@ -261,7 +261,7 @@ dasdview_parse_input(unsigned long long *p, dasdview_info_t *info, char *s)
error:
zt_error_print("dasdview: usage error\n"
"%s is not a valid begin/size value!", s);
exit(-1);
exit(EXIT_FAILURE);
}
/*
@@ -454,7 +454,7 @@ dasdview_print_vlabel(dasdview_info_t *info)
if (rc) {
zt_error_print("error when reading label from device:"
" rc=%d\n", rc);
exit(-1);
exit(EXIT_FAILURE);
}
lzds_dasd_get_vlabel(info->dasd, &tmpvlabel);
memcpy(&vlabel, tmpvlabel, sizeof(vlabel));
@@ -600,7 +600,7 @@ dasdview_print_volser(dasdview_info_t *info)
if (rc) {
zt_error_print("error when reading label from device:"
" rc=%d\n", rc);
exit(-1);
exit(EXIT_FAILURE);
}
lzds_dasd_get_vlabel(info->dasd, &tmpvlabel);
memcpy(&vlabel, tmpvlabel, sizeof(vlabel));
@@ -644,7 +644,7 @@ dasdview_read_vtoc(dasdview_info_t *info)
zt_error_print("dasdview: disk layout error\n"
"%s is not formatted with the z/OS "
"compatible disk layout!\n", info->device);
exit(-1);
exit(EXIT_FAILURE);
}
vtocblk = (u_int64_t)vtoc_get_cyl_from_cchhb(&vlabel.vtoc) *
@@ -664,7 +664,7 @@ dasdview_read_vtoc(dasdview_info_t *info)
if ((vtocblk <= 0) || (vtocblk > maxblk)) {
zt_error_print("dasdview: VTOC error\n"
"Volume label VTOC pointer is not valid!\n");
exit(-1);
exit(EXIT_FAILURE);
}
vtoc_read_label(info->device, (vtocblk - 1) * info->blksize,
@@ -676,7 +676,7 @@ dasdview_read_vtoc(dasdview_info_t *info)
/* format4 DSCB is invalid */
zt_error_print("dasdview: VTOC error\n"
"Format 4 DSCB is invalid!\n");
exit(-1);
exit(EXIT_FAILURE);
}
info->f4c++;
@@ -724,19 +724,19 @@ dasdview_read_vtoc(dasdview_info_t *info)
if (info->f4c > 1) {
zt_error_print("dasdview: VTOC error\n"
"More than one FMT4 DSCB!\n");
exit(-1);
exit(EXIT_FAILURE);
}
if (info->f5c > 1) {
zt_error_print("dasdview: VTOC error\n"
"More than one FMT5 DSCB!\n");
exit(-1);
exit(EXIT_FAILURE);
}
if (info->f7c > 1) {
zt_error_print("dasdview: VTOC error\n"
"More than one FMT7 DSCB!\n");
exit(-1);
exit(EXIT_FAILURE);
}
}
@@ -975,7 +975,7 @@ static void dasdview_print_format1_8_short_info_raw(format1_label_t *f1,
}
if (rc) {
zt_error_print("dasdview: Broken format 3 DSCB chain \n");
exit(-1);
exit(EXIT_FAILURE);
}
f3 = (dscb && dscb->fmtid == 0xf3) ? (format3_label_t *)dscb : NULL;
@@ -990,7 +990,7 @@ static void dasdview_print_format1_8_short_info_raw(format1_label_t *f1,
if (f3->DS3FMTID != 0xf3) {
zt_error_print("dasdview: Broken format 3 DSCB"
" chain \n");
exit(-1);
exit(EXIT_FAILURE);
}
for (j = 0; j < 4; ++j)
dasdview_print_short_info_extent_raw(&f3->DS3EXTNT[j]);
@@ -1002,7 +1002,7 @@ static void dasdview_print_format1_8_short_info_raw(format1_label_t *f1,
if (rc) {
zt_error_print("dasdview: Broken format 3 DSCB"
" chain \n");
exit(-1);
exit(EXIT_FAILURE);
}
}
printf("\n");
@@ -1025,7 +1025,7 @@ static void dasdview_print_vtoc_info_raw(dasdview_info_t *info)
rc = lzds_raw_vtoc_alloc_dscbiterator(info->rawvtoc, &it);
if (rc) {
zt_error_print("dasdview: could not allocate DSCB iterator \n");
exit(-1);
exit(EXIT_FAILURE);
}
while (!lzds_dscbiterator_get_next_dscb(it, &dscb)) {
if (dscb->fmtid == 0xf1)
@@ -1058,7 +1058,7 @@ static void dasdview_print_vtoc_info_raw(dasdview_info_t *info)
rc = lzds_raw_vtoc_alloc_dscbiterator(info->rawvtoc, &it);
if (rc) {
zt_error_print("dasdview: could not allocate DSCB iterator \n");
exit(-1);
exit(EXIT_FAILURE);
}
while (!lzds_dscbiterator_get_next_dscb(it, &dscb)) {
if (dscb->fmtid == 0xf1 || dscb->fmtid == 0xf8)
@@ -1739,23 +1739,23 @@ static void dasdview_print_vtoc_raw(dasdview_info_t *info)
if (rc) {
zt_error_print("error when reading label from device:"
" rc=%d\n", rc);
exit(-1);
exit(EXIT_FAILURE);
}
rc = lzds_dasd_alloc_rawvtoc(info->dasd);
if (rc == EINVAL) {
zt_error_print("dasdview: Cannot read VTOC because disk does"
" not contain valid VOL1 label.\n",
info->device);
exit(-1);
exit(EXIT_FAILURE);
} else if (rc) {
zt_error_print("error when reading vtoc from device:"
" rc=%d\n", rc);
exit(-1);
exit(EXIT_FAILURE);
}
rc = lzds_dasd_get_rawvtoc(info->dasd, &info->rawvtoc);
if (rc || !info->rawvtoc) {
zt_error_print("dasdview: libvtoc could not read vtoc\n");
exit(-1);
exit(EXIT_FAILURE);
}
if (info->vtoc_info || info->vtoc_all)
@@ -1764,7 +1764,7 @@ static void dasdview_print_vtoc_raw(dasdview_info_t *info)
rc = lzds_raw_vtoc_alloc_dscbiterator(info->rawvtoc, &it);
if (rc) {
zt_error_print("dasdview: could not allocate DSCB iterator\n");
exit(-1);
exit(EXIT_FAILURE);
}
while (!lzds_dscbiterator_get_next_dscb(it, &record))
dasdview_print_vtoc_dscb(info, record);
@@ -1858,7 +1858,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
zt_error_print("dasdview: open error\n"
"Unable to open device %s in read-only mode!\n",
info->device);
exit(-1);
exit(EXIT_FAILURE);
}
j = (info->begin / SEEK_STEP);
@@ -1877,7 +1877,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
zt_error_print("dasdview: seek error\n"
"Unable to seek in device %s!\n",
info->device);
exit(-1);
exit(EXIT_FAILURE);
}
b++;
a += SEEK_STEP;
@@ -1890,7 +1890,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
zt_error_print("dasdview: seek error\n"
"Unable to seek in device %s!\n",
info->device);
exit(-1);
exit(EXIT_FAILURE);
}
}
@@ -1926,7 +1926,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
zt_error_print("dasdview: read error\n"
"Unable to read from device %s!\n",
info->device);
exit(-1);
exit(EXIT_FAILURE);
}
if (info->format1)
@@ -1945,7 +1945,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
zt_error_print("dasdview: read error\n"
"Unable to read from device %s!\n",
info->device);
exit(-1);
exit(EXIT_FAILURE);
}
if (info->format1)
@@ -2112,18 +2112,18 @@ static void dasdview_view_raw(dasdview_info_t *info)
trackdata = memalign(4096, trckbuffsize * RAWTRACKSIZE);
if (!trackdata) {
zt_error_print("failed to allocate memory\n");
exit(-1);
exit(EXIT_FAILURE);
}
rc = lzds_dasd_alloc_dasdhandle(info->dasd, &dasdh);
if (rc) {
zt_error_print("failed to allocate memory\n");
exit(-1);
exit(EXIT_FAILURE);
}
rc = lzds_dasdhandle_open(dasdh);
if (rc) {
lzds_dasdhandle_free(dasdh);
zt_error_print("failed to open device\n");
exit(-1);
exit(EXIT_FAILURE);
}
/* residual is the number of tracks we still have to read */
residual = tracks_to_read;
@@ -2135,7 +2135,7 @@ static void dasdview_view_raw(dasdview_info_t *info)
trckend, trackdata);
if (rc) {
perror("Error on read");
exit(-1);
exit(EXIT_FAILURE);
}
data = trackdata;
for (i = 0; i < trckcount; ++i) {
@@ -2153,7 +2153,7 @@ static void dasdview_view_raw(dasdview_info_t *info)
lzds_dasdhandle_free(dasdh);
if (rc < 0) {
perror("Error on closing file");
exit(-1);
exit(EXIT_FAILURE);
}
}
@@ -2253,7 +2253,7 @@ int main(int argc, char *argv[])
zt_error_print("dasdview: usage error\n"
"%s is no valid argument for"
" option -t/--vtoc\n", optarg);
exit(-1);
exit(EXIT_FAILURE);
}
info.vtoc = 1;
info.action_specified = 1;
@@ -2301,13 +2301,13 @@ int main(int argc, char *argv[])
rc = lzds_zdsroot_alloc(&info.zdsroot);
if (rc) {
zt_error_print("Could not allocate index\n");
exit(-1);
exit(EXIT_FAILURE);
}
rc = lzds_zdsroot_add_device(info.zdsroot, info.device,
&info.dasd);
if (rc) {
zt_error_print("Could not add device to index\n");
exit(-1);
exit(EXIT_FAILURE);
}
}
@@ -2328,7 +2328,7 @@ int main(int argc, char *argv[])
if (info.begin > max) {
zt_error_print("dasdview: usage error\n"
"'begin' value is not within disk range!");
exit(-1);
exit(EXIT_FAILURE);
}
if (info.size_specified)
@@ -2343,7 +2343,7 @@ int main(int argc, char *argv[])
zt_error_print("dasdview: usage error\n"
"'begin' + 'size' is not within "
"disk range!");
exit(-1);
exit(EXIT_FAILURE);
}
if ((info.begin_specified || info.size_specified) &&
@@ -2355,7 +2355,7 @@ int main(int argc, char *argv[])
zt_error_print("dasdview: usage error\n"
"Options -1 or -2 make only sense with "
"options -b or -s!");
exit(-1);
exit(EXIT_FAILURE);
}
/* do the output */

View File

@@ -31,6 +31,8 @@
#define __packed __attribute__((packed))
#define __aligned(x) __attribute__((aligned(x)))
#define __may_alias __attribute__((may_alias))
#define __section(x) __attribute__((__section__(#x)))
#define __noinline __attribute__((__noinline__))
typedef unsigned long long u64;
typedef signed long long s64;

View File

@@ -146,9 +146,10 @@ int dasd_is_ro(const char *device, bool *ro)
{
int fd, val;
fd = dasd_open_device(device, O_RDWR);
fd = dasd_open_device(device, O_RDONLY);
RUN_IOCTL(fd, BLKROGET, &val);
*ro = (val != 0) ? true : false;
dasd_close_device(fd);
return 0;
}

View File

@@ -210,7 +210,7 @@ int dasd_reset_chpid(char *devnode, char *chpid_char)
*/
int dasd_get_host_access_count(char *device)
{
char busid[9];
char busid[DASD_BUS_ID_SIZE];
char *path;
long value;

View File

@@ -15,10 +15,10 @@
#include <sys/resource.h>
#include <sys/time.h>
#include "lib/zt_common.h"
#include "lib/util_panic.h"
/* Make functions noinline to have a nice backtrace */
#define __noinline __attribute__((noinline))
/*
* Test util_panic()

View File

@@ -33,8 +33,8 @@ pxelinux.initramfs: $(BBINSTALL)
$(BUSYBOX)/_install:
wget https://busybox.net/downloads/$(BUSYBOX).tar.bz2
tar xjf $(BUSYBOX).tar.bz2
make -C $(BUSYBOX) defconfig
make -C $(BUSYBOX) install
$(MAKE) -C $(BUSYBOX) defconfig
$(MAKE) -C $(BUSYBOX) install
install:

View File

@@ -176,6 +176,9 @@ readonly OUTPUT_FILE_OSAOAT="${WORKPATH}osa_oat"
# File that includes content of Ethtool commands
readonly OUTPUT_FILE_ETHTOOL="${WORKPATH}ethtool.out"
# File that includes content of tc commands
readonly OUTPUT_FILE_TC="${WORKPATH}tc.out"
# File that includes the output of journalctl
readonly OUTPUT_FILE_JOURNALCTL="${WORKPATH}journalctl.out"
@@ -195,7 +198,7 @@ readonly OUTPUT_FILE_NVME="${WORKPATH}nvme.out"
readonly MOUNT_POINT_DEBUGFS="/sys/kernel/debug"
# The amount of steps running the whole collections
readonly COLLECTION_COUNT=13
readonly COLLECTION_COUNT=14
# The kernel version (e.g. '2' from 2.6.32 or '3' from 3.2.1)
readonly KERNEL_VERSION=$(uname -r 2>/dev/null | cut -d'.' -f1)
@@ -374,7 +377,7 @@ CONFIGFILES="\
$(find /lib/modules -name modules.dep 2>/dev/null)\
/etc/docker\
/lib/systemd/system/docker.service\
/usr/lib/systemd/system/docker.service\
/usr/lib/systemd/system\
/etc/apparmor.d\
"
@@ -401,6 +404,7 @@ CMDS="uname -a\
:ip link show\
:ip ntable\
:ip a sh\
:ip -s -s link\
:firewall-cmd --list-all\
:ipcs -a\
:netstat -pantu\
@@ -459,7 +463,7 @@ CMDS="uname -a\
:java -version\
:cat /root/.bash_history\
:env\
:journalctl --all --no-pager --since=$(date -d '5 day ago' +%Y-%m-%d) --until=now --lines=50000 \
:journalctl --all --no-pager --lines=100000 --output=short-precise\
> '${OUTPUT_FILE_JOURNALCTL}'\
:openssl engine\
:systemd-delta\
@@ -561,6 +565,11 @@ collect_cmdsout() {
done
IFS="${ifs_orig}"
if echo "${RUNTIME_ENVIRONMENT}" | grep -qi "z/VM" >/dev/null 2>&1; then
call_run_command "hyptop -b -d 1 -n 5 -f \#,c,m,C:s,M:s,o -S c" "${OUTPUT_FILE_CMD}"
else call_run_command "hyptop -b -d 1 -n 5 -f \#,T,c,e,m,C:s,E:s,M:s,o -S c" "${OUTPUT_FILE_CMD}"
fi
pr_log_stdout " "
}
@@ -786,6 +795,28 @@ collect_ethtool() {
pr_log_stdout " "
}
########################################
collect_tc() {
local network_devices
local network_device
network_devices=$(ls /sys/class/net 2>/dev/null)
if which tc >/dev/null 2>&1; then
if test -n "${network_devices}"; then
pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting tc output"
for network_device in ${network_devices}; do
call_run_command "tc -s qdisc show dev ${network_device}" "${OUTPUT_FILE_TC}"
done
else
pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting tc output skipped - no devices"
fi
else
pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting tc output skipped - not available"
fi
pr_log_stdout " "
}
########################################
# OpenVSwitch
collect_ovs() {
@@ -802,7 +833,7 @@ collect_ovs() {
:ovsdb-client dump\
"
if test -n "${br_list}"; then
pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output"
pr_syslog_stdout "10 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output"
IFS=:
for ovscmd in ${ovscmds}; do
IFS=${ifs_orig} call_run_command "${ovscmd}" "${OUTPUT_FILE_OVS}.out"
@@ -821,7 +852,7 @@ collect_ovs() {
IFS="${ifs_orig}"
done
else
pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output skipped"
pr_syslog_stdout "10 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output skipped"
fi
pr_log_stdout " "
@@ -834,12 +865,12 @@ collect_domain_xml() {
domain_list=$(virsh list --all --name)
if test -n "${domain_list}"; then
pr_syslog_stdout "10 of ${COLLECTION_COUNT}: Collecting domain xml files"
pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Collecting domain xml files"
for domain in ${domain_list}; do
call_run_command "virsh dumpxml ${domain}" "${OUTPUT_FILE_XML}_${domain}.xml"
done
else
pr_syslog_stdout "10 of ${COLLECTION_COUNT}: Collecting domain xml files skipped"
pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Collecting domain xml files skipped"
fi
pr_log_stdout " "
@@ -853,23 +884,23 @@ collect_docker() {
# call docker inspect for all containers
item_list=$(docker ps -qa)
if test -n "${item_list}"; then
pr_syslog_stdout "11a of ${COLLECTION_COUNT}: Collecting docker container output"
pr_syslog_stdout "12a of ${COLLECTION_COUNT}: Collecting docker container output"
for item in ${item_list}; do
call_run_command "docker inspect ${item}" "${OUTPUT_FILE_DOCKER}"
done
else
pr_syslog_stdout "11a of ${COLLECTION_COUNT}: Collecting docker container output skipped"
pr_syslog_stdout "12a of ${COLLECTION_COUNT}: Collecting docker container output skipped"
fi
# call docker inspect for all networks
item_list=$(docker network ls -q)
if test -n "${item_list}"; then
pr_syslog_stdout "11b of ${COLLECTION_COUNT}: Collecting docker network output"
pr_syslog_stdout "12b of ${COLLECTION_COUNT}: Collecting docker network output"
for item in ${item_list}; do
call_run_command "docker network inspect ${item}" "${OUTPUT_FILE_DOCKER}"
done
else
pr_syslog_stdout "11b of ${COLLECTION_COUNT}: Collecting docker network output skipped"
pr_syslog_stdout "12b of ${COLLECTION_COUNT}: Collecting docker network output skipped"
fi
pr_log_stdout " "
@@ -879,7 +910,7 @@ collect_docker() {
collect_nvme() {
local NVME
pr_syslog_stdout "12 of ${COLLECTION_COUNT}: Collecting nvme output"
pr_syslog_stdout "13 of ${COLLECTION_COUNT}: Collecting nvme output"
call_run_command "nvme list" "${OUTPUT_FILE_NVME}"
for NVME in /dev/nvme[0-9]*; do
@@ -1188,6 +1219,8 @@ collect_osaoat
collect_ethtool
collect_tc
collect_ovs
collect_domain_xml

View File

@@ -60,32 +60,34 @@ Kernel version = <kernel\-version>
.br
Runtime environment = z/VM
.PP
1 of 13: Collecting command output
1 of 14: Collecting command output
.PP
2 of 13: Collecting z/VM command output
2 of 14: Collecting z/VM command output
.PP
3 of 13: Collecting procfs
3 of 14: Collecting procfs
.PP
4 of 13: Collecting sysfs
4 of 14: Collecting sysfs
.PP
5 of 13: Collecting log files
5 of 14: Collecting log files
.PP
6 of 13: Collecting config files
6 of 14: Collecting config files
.PP
7 of 13: Collecting osa oat output skipped \- not available
7 of 14: Collecting osa oat output skipped \- not available
.PP
8 of 13: Collecting ethtool output
8 of 14: Collecting ethtool output
.PP
9 of 13: Collecting OpenVSwitch output
9 of 14: Collecting tc output
.pp
10 of 14: Collecting OpenVSwitch output
.PP
10 of 13: Collecting domain xml files
11 of 14: Collecting domain xml files
.PP
11a of 13: Collecting docker container output
11b of 13: Collecting docker network output
12a of 14: Collecting docker container output
12b of 14: Collecting docker network output
.PP
12 of 13: Collecting nvme output
13 of 14: Collecting nvme output
.PP
13 of 13: Postprocessing
14 of 14: Postprocessing
.PP
Finalizing: Creating archive with collected data
.PP

View File

@@ -1,8 +1,8 @@
.\" Copyright 2017 IBM Corp.
.\" Copyright 2019 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH CHZCRYPT 8 "OCT 2017" "s390-tools"
.TH CHZCRYPT 8 "AUG 2019" "s390-tools"
.SH NAME
chzcrypt \- modify zcrypt configuration
.SH SYNOPSIS

View File

@@ -1,7 +1,7 @@
/*
* chzcrypt - Tool to modify zcrypt configuration
*
* Copyright IBM Corp. 2008, 2017
* Copyright IBM Corp. 2008, 2019
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -47,7 +47,7 @@ const struct util_prg prg = {
{
.owner = "IBM Corp.",
.pub_first = 2008,
.pub_last = 2017,
.pub_last = 2019,
},
UTIL_PRG_COPYRIGHT_END
}

View File

@@ -1,6 +1,6 @@
.\" lszcrypt.8
.\"
.\" Copyright 2017 IBM Corp.
.\" Copyright 2019 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
@@ -10,7 +10,7 @@
.\" nroff -man lszcrypt.8
.\" to process this source
.\"
.TH LSZCRYPT 8 "JAN 2019" "s390-tools"
.TH LSZCRYPT 8 "AUG 2019" "s390-tools"
.SH NAME
lszcrypt \- display zcrypt device and configuration information
.SH SYNOPSIS
@@ -118,7 +118,7 @@ explanation:
.B TYPE and HWTYPE
The HWTYPE is a numeric value showing which type of hardware the zcrypt
device driver presumes that this crypto card is. The currently known values
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5 and 12=CEX6.
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6 and 13=CEX7.
.br
The TYPE is a human readable value showing the hardware type and the basic
function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So
@@ -167,7 +167,7 @@ operations within the guests.
.B DRIVER
.br
Shows which card or queue device driver currently handles this crypto
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX6
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX7
hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware),
cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved
for use by kvm hypervisor for kvm guests and not accessible to host

View File

@@ -1,7 +1,7 @@
/**
* lszcrypt - Display zcrypt devices and configuration settings
*
* Copyright IBM Corp. 2008, 2018
* Copyright IBM Corp. 2008, 2019
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -86,7 +86,7 @@ const struct util_prg prg = {
{
.owner = "IBM Corp.",
.pub_first = 2008,
.pub_last = 2018,
.pub_last = 2019,
},
UTIL_PRG_COPYRIGHT_END
}
@@ -302,9 +302,10 @@ static void show_capability(const char *id_str)
printf("%s\n", CAP_CCA);
printf("%s", CAP_RNG);
break;
case 10:
case 11:
case 12:
case 10: /* CEX4S */
case 11: /* CEX5S */
case 12: /* CEX6S */
case 13: /* CEX7S */
if (func_val & MASK_ACCEL) {
if (func_val & MASK_RSA4K)
printf("%s", CAP_RSA4K);

View File

@@ -147,8 +147,9 @@ struct chsc_cmb_area {
#define CRYPTO_TYPE_CEX4S 10
#define CRYPTO_TYPE_CEX5S 11
#define CRYPTO_TYPE_CEX6S 12
#define CRYPTO_TYPE_CEX7S 13
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX6S
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX7S
struct crypto_counter {
const char *name;
@@ -235,8 +236,8 @@ const struct crypto_mode mode_pcica[1] = {
.counters = counter_pcica },
};
#define NUM_CEX456_MODES 11
const struct crypto_mode mode_cex456[NUM_CEX456_MODES] = {
#define NUM_CEX4567_MODES 11
const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = {
{ 0 },
{ 0 },
{ 0 },
@@ -256,7 +257,7 @@ const struct crypto_mode mode_cex456[NUM_CEX456_MODES] = {
.counters = counter_ep11 },
};
#define NUM_CRYPTO_TYPES 13
#define NUM_CRYPTO_TYPES 14
const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
{ 0 },
{ 0 },
@@ -275,12 +276,14 @@ const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
.modes = mode_accel },
{ .name = "CEX3C", .num_modes = NUM_COPROC_MODES,
.modes = mode_coproc },
{ .name = "CEX4", .num_modes = NUM_CEX456_MODES,
.modes = mode_cex456 },
{ .name = "CEX5", .num_modes = NUM_CEX456_MODES,
.modes = mode_cex456 },
{ .name = "CEX6", .num_modes = NUM_CEX456_MODES,
.modes = mode_cex456 },
{ .name = "CEX4", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
{ .name = "CEX5", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
{ .name = "CEX6", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
{ .name = "CEX7", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
};

View File

@@ -15,6 +15,8 @@
#include <elf.h>
#include <linux/types.h>
#include "lib/zt_common.h"
#include "dfo.h"
#include "zg.h"
@@ -80,7 +82,7 @@ struct nt_prstatus_64 {
u64 orig_gpr2;
u32 pr_fpvalid;
u8 pad3[4];
} __attribute__ ((packed));
} __packed;
/*
* fpregset ELF Note
@@ -89,7 +91,7 @@ struct nt_fpregset_64 {
u32 fpc;
u32 pad;
u64 fprs[16];
} __attribute__ ((packed));
} __packed;
/*
* prpsinfo ELF Note

View File

@@ -12,6 +12,8 @@
#ifndef DF_LKCD_H
#define DF_LKCD_H
#include "lib/zt_common.h"
#define DF_LKCD_MAGIC 0xa8190173618f23edULL
#define DF_LKCD_MAGIC_ASM 0x733339302d64756dULL
#define DF_LKCD_VERSION 0x8 /* dump version number */
@@ -53,7 +55,7 @@ struct df_lkcd_hdr {
u32 dump_compress;
u32 dump_flags;
u32 dump_device;
} __attribute__((packed));
} __packed;
/*
* s390 LKCD asm header
@@ -65,7 +67,7 @@ struct df_lkcd_hdr_asm {
u16 cpu_cnt;
u16 real_cpu_cnt;
u32 lc_vec[512];
} __attribute__((packed));
} __packed;
/*
* Page header
@@ -74,6 +76,6 @@ struct df_lkcd_pg_hdr {
u64 addr; /* Address of dump page */
u32 size; /* Size of dump page */
u32 flags; /* flags (DF_LKCD_COMPRESSED, DF_LKCD_RAW,...) */
} __attribute__((packed));
} __packed;
#endif /* DF_LKCD_H */

View File

@@ -12,6 +12,8 @@
#ifndef DF_S390_H
#define DF_S390_H
#include "lib/zt_common.h"
#include "dt.h"
#include "zg.h"
@@ -59,7 +61,7 @@ struct df_s390_hdr {
u64 mvdump_zipl_time; /* 0x208 */
u8 end_pad2[0x800-0x210]; /* 0x210 */
u32 lc_vec[DF_S390_CPU_MAX]; /* 0x800 */
} __attribute__((packed));
} __packed;
/*
* End marker: Should be at the end of every valid s390 crash dump.
@@ -67,7 +69,7 @@ struct df_s390_hdr {
struct df_s390_em {
char str[8];
u64 tod;
} __attribute__((packed));
} __packed;
/*
* Segment header for s390 extended dump format
@@ -77,7 +79,7 @@ struct df_s390_dump_segm_hdr {
u64 len;
u64 stop_marker;
u8 reserved[0x1000 - 24];
} __attribute__((packed));
} __packed;
/*
* Convert DFI arch to s390 arch
@@ -118,7 +120,7 @@ struct df_s390_dumper {
u32 size;
u8 force;
u64 mem;
} __attribute__ ((packed));
} __packed;
/*
* s390 dump helpers

View File

@@ -13,7 +13,10 @@
#define DFI_H
#include <linux/utsname.h>
#include "lib/zt_common.h"
#include "lib/util_list.h"
#include "zg.h"
/*
@@ -68,7 +71,7 @@ struct dfi_lowcore_64 {
u32 access_regs_save_area[16]; /* 0x1340 */
u64 cregs_save_area[16]; /* 0x1380 */
u8 pad_0x1400[0x2000-0x1400]; /* 0x1400 */
} __attribute__((packed));
} __packed;
static inline u64 dfi_lc_size(enum dfi_arch arch)
{

View File

@@ -26,14 +26,14 @@ struct vol_parm {
u8 blk_size;
u8 end_sec;
u8 num_heads;
} __attribute__ ((packed));
} __packed;
struct vol_parm_table {
u64 timestamp;
u16 vol_cnt;
struct vol_parm vol_parm[MAX_VOLUMES];
u8 ssid[MAX_VOLUMES];
} __attribute__ ((packed));
} __packed;
/*
* Device signature

View File

@@ -10,6 +10,9 @@
*/
#include <elf.h>
#include "lib/zt_common.h"
#include "zgetdump.h"
#ifdef __s390x__
@@ -38,7 +41,7 @@ struct os_info {
u64 init_fn_size;
u32 init_fn_csum;
u8 reserved[4004];
} __attribute__ ((packed));
} __packed;
/*
* File local static data

View File

@@ -12,7 +12,9 @@
#include <linux/fs.h>
#include <stdio.h>
#include "lib/zt_common.h"
#include "lib/util_part.h"
#include "zgetdump.h"
/*
@@ -28,7 +30,7 @@ struct scsi_dump_sb {
uint64_t csum_off;
uint64_t csum_size;
uint64_t csum;
} __attribute((packed));
} __packed;
/*
* File local static data
@@ -46,7 +48,7 @@ struct scsi_blockptr {
uint16_t size;
uint16_t blockct;
uint8_t reserved[4];
} __attribute__((__packed__));
} __packed;
enum component_entry_type {
component_execute = 0x01,
@@ -61,7 +63,7 @@ struct component_entry {
uint64_t load_address;
uint64_t load_psw;
} address;
} __attribute__((__packed__));
} __packed;
enum component_header_type {
component_header_ipl = 0x00,
@@ -72,7 +74,7 @@ struct component_header {
uint8_t magic[4];
uint8_t type;
uint8_t reserved[27];
} __attribute__((__packed__));
} __packed;
struct boot_info {
char magic[4];
@@ -81,7 +83,7 @@ struct boot_info {
uint8_t dev_type;
uint8_t flags;
uint64_t sb_off;
} __attribute__ ((packed));
} __packed;
struct scsi_mbr {
char magic[4];
@@ -90,7 +92,7 @@ struct scsi_mbr {
struct scsi_blockptr blockptr;
uint8_t reserved2[0x50];
struct boot_info boot_info;
} __attribute__((__packed__));
} __packed;
#define BOOT_INFO_VERSION 1
#define BOOT_INFO_MAGIC "zIPL"

View File

@@ -62,7 +62,7 @@ struct scsi_dump_sb {
uint64_t csum_off;
uint64_t csum_size;
uint64_t csum;
} __attribute((packed));
} __packed;
/*
* Layout of SCSI disk block pointer
@@ -72,7 +72,7 @@ struct linear_blockptr {
uint16_t size;
uint16_t blockct;
uint8_t reserved[4];
} __attribute((packed));
} __packed;
/* From boot.h in zipl */
struct boot_info {
@@ -82,7 +82,7 @@ struct boot_info {
uint8_t dev_type;
uint8_t flags;
uint64_t sb_off;
} __attribute__ ((packed));
} __packed;
/* From install.c in zipl */
struct scsi_mbr {
@@ -92,7 +92,7 @@ struct scsi_mbr {
struct linear_blockptr lin;
uint8_t reserverd[0x50];
struct boot_info boot_info;
} __attribute__ ((packed));
} __packed;
/* From boot.h in zipl */
#define BOOT_INFO_VERSION 1

View File

@@ -745,10 +745,11 @@ function check_size_requirements() {
trap emergency_shutdown SIGHUP SIGTERM SIGINT SIGQUIT;
check_blktrace;
parse_params $@;
check_blktrace;
determine_host_adapters;
check_cpuplugd;

View File

@@ -8,6 +8,7 @@ all:
install: all
$(MAKE) -C src install
$(MAKE) -C man install
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 doc/zipl.conf.minimal $(DESTDIR)$(TOOLS_LIBDIR)/zipl.conf
clean:
$(MAKE) -C src clean

View File

@@ -1,8 +1,8 @@
# Common definitions
include ../../common.mak
CFLAGS_BOOT = $(NO_PIE_CFLAGS) -Os -g -I../include -D__ASSEMBLY__ \
-DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
ALL_CFLAGS = $(NO_PIE_CFLAGS) -Os -g -I $(rootdir)/zipl/include \
-I $(rootdir)/include -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
-fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \
-fno-delete-null-pointer-checks \
-fexec-charset=IBM1047 -m64 -mpacked-stack \
@@ -21,10 +21,10 @@ all: data.o data.h tape0.bin stage3.bin
%: %.S
%.o: %.S
$(CC) $(CFLAGS_BOOT) -c -o $@ $<
$(CC) $(ALL_CFLAGS) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS_BOOT) -c -o $@ $<
$(CC) $(ALL_CFLAGS) -c -o $@ $<
eckd2dump_sv.exec: \
head.o stage2dump.o cio.o eckd2dump.o eckd2dump_sv.o \

View File

@@ -9,6 +9,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "lib/zt_common.h"
#include "eckd2dump.h"
#include "error.h"
#include "stage2dump.h"
@@ -19,8 +21,7 @@
/*
* Magic number at start of dump record
*/
uint64_t magic __attribute__((section(".stage2.head")))
= 0x584d554c54363401ULL; /* XMULT64, version 1 */
uint64_t __section(.stage2.head) magic = 0x584d554c54363401ULL; /* XMULT64, version 1 */
/*
* Parameter format for ECKD MV dumper (13 bytes):
@@ -59,8 +60,7 @@ struct mvdump_parm_table {
(MAX_DUMP_VOLUMES * (sizeof(struct mvdump_param) + 1))];
} __packed;
static struct mvdump_parm_table mvdump_table
__attribute__((section(".eckd2dump_mv.tail")));
static struct mvdump_parm_table __section(.eckd2dump_mv.tail) mvdump_table;
static int volnr_current;

View File

@@ -9,6 +9,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "lib/zt_common.h"
#include "eckd2dump.h"
#include "error.h"
#include "stage2dump.h"
@@ -16,8 +18,7 @@
/*
* Magic number at start of dump record
*/
uint64_t magic __attribute__((section(".stage2.head"))) =
0x5845434b44363401ULL; /* "XECKD64", version 1 */
uint64_t __section(.stage2.head) magic = 0x5845434b44363401ULL; /* "XECKD64", version 1 */
/*
* ECKD parameter block passed by zipl

View File

@@ -9,6 +9,7 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "lib/zt_common.h"
#include "error.h"
#include "fba.h"
#include "stage2dump.h"
@@ -20,8 +21,7 @@
/*
* Magic number at start of dump record
*/
uint64_t magic __attribute__((section(".stage2.head")))
= 0x5844464241363401ULL; /* XDFBA64, version 1 */
uint64_t __section(.stage2.head) magic = 0x5844464241363401ULL; /* XDFBA64, version 1 */
/*
* FBA dump device partition specification

View File

@@ -11,6 +11,8 @@
#include <stdarg.h>
#include "lib/zt_common.h"
#include "error.h"
#include "libc.h"
#include "sclp.h"
@@ -343,7 +345,7 @@ void pgm_check_handler_fn(void)
libc_stop(psw_old->addr);
}
__attribute__ ((noinline)) void load_wait_psw(uint64_t psw_mask, struct psw_t *psw)
void __noinline load_wait_psw(uint64_t psw_mask, struct psw_t *psw)
{
struct psw_t wait_psw = { .mask = psw_mask, .addr = 0 };
struct psw_t old_psw, *wait_psw_ptr = &wait_psw;
@@ -383,7 +385,7 @@ void initialize(void)
/*
* Load disabled wait PSW with reason code in address field
*/
void libc_stop(unsigned long reason)
void __noreturn libc_stop(unsigned long reason)
{
struct psw_t psw;

View File

@@ -11,6 +11,8 @@
#ifndef LIBC_H
#define LIBC_H
#include <stdint.h>
#define NULL ((void *) 0)
#define EPERM 1 /* Operation not permitted */
@@ -41,11 +43,6 @@
#define MIB (1024ULL * 1024)
typedef unsigned long long uint64_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
void printf(const char *, ...);
void sprintf(char *, const char *, ...);
void *memcpy(void *, const void *, unsigned long);
@@ -60,7 +57,7 @@ char *strcpy(char *, const char *);
unsigned long get_zeroed_page(void);
void free_page(unsigned long);
void initialize(void);
void libc_stop(unsigned long) __attribute__((noreturn));
void libc_stop(unsigned long);
void start(void);
void pgm_check_handler(void);
void pgm_check_handler_fn(void);

View File

@@ -27,7 +27,6 @@ static void menu_prompt(int timeout)
static int menu_read(void)
{
char *temp_area = (char *)get_zeroed_page();
uint16_t *configs = __stage2_params.config;
int timeout, rc, i, count = 0;
char *endptr;
int value;
@@ -60,7 +59,7 @@ static int menu_read(void)
value = ebcstrtoul((char *)temp_area, &endptr, 10);
if ((endptr != temp_area) && (value < BOOT_MENU_ENTRIES - 1) &&
(configs[value] != 0)) {
(__stage2_params.config[value] != 0)) {
/* valid config found - finish */
break;
} else {
@@ -80,14 +79,13 @@ out_free_page:
static int menu_list(void)
{
uint16_t *configs = __stage2_params.config;
char *name;
int i;
for (i = 0; i < BOOT_MENU_ENTRIES; i++) {
if (configs[i] == 0)
if (__stage2_params.config[i] == 0)
continue;
name = configs[i] + ((void *)&__stage2_params);
name = __stage2_params.config[i] + ((void *)&__stage2_params);
printf("%s\n", name);
if (i == 0)
printf("\n");
@@ -136,7 +134,6 @@ static int menu_param(unsigned long *value)
int menu(void)
{
uint16_t *configs = __stage2_params.config;
unsigned long value = 0;
char *cmd_line_extra;
char endstring[15];
@@ -178,11 +175,11 @@ int menu(void)
boot:
/* sanity - config entry not valid */
if (configs[value] == 0)
if (__stage2_params.config[value] == 0)
panic(EINTERNAL, "%s", msg_econfig);
printf("Booting %s\n",
(char *)(configs[value] +
(char *)(__stage2_params.config[value] +
(void *)&__stage2_params + TEXT_OFFSET));
/* append 'BOOT_IMAGE=<num>' to parmline */

View File

@@ -11,7 +11,7 @@
#ifndef S390_H
#define S390_H
#include "../../include/lib/zt_common.h"
#include "lib/zt_common.h"
#include "libc.h"
#define __pa32(x) ((uint32_t)(unsigned long)(x))
@@ -452,7 +452,7 @@ static inline int test_facility(unsigned long nr)
return __test_facility(nr, &S390_lowcore.stfle_fac_list);
}
static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size)
static inline unsigned long __stfle_asm(uint64_t *stfle_fac_list, int size)
{
register unsigned long reg0 asm("0") = size - 1;
@@ -469,7 +469,7 @@ static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size)
* @stfle_fac_list: array where facility list can be stored
* @size: size of passed in array in double words
*/
static inline void stfle(u64 *stfle_fac_list, int size)
static inline void stfle(uint64_t *stfle_fac_list, int size)
{
unsigned long nr;

View File

@@ -53,19 +53,21 @@ struct gds_subvector {
uint8_t key;
} __packed;
/* Structure must not have any padding */
struct sccb_header {
uint16_t length;
uint8_t function_code;
uint8_t control_mask[3];
uint16_t response_code;
} __packed;
};
/* Structure must not have any padding */
struct evbuf_header {
uint16_t length;
uint8_t type;
uint8_t flags;
uint16_t _reserved;
} __packed;
};
struct mto {
uint16_t length;

View File

@@ -104,7 +104,6 @@ int sclp_hsa_get_size(unsigned long *hsa_size)
sccb = (void *)get_zeroed_page();
sccb->header.length = sizeof(*sccb);
sccb->header.length = sizeof(*sccb);
sccb->evbuf.header.length = sizeof(struct sdias_evbuf);
sccb->evbuf.header.type = EVTYP_SDIAS;
sccb->evbuf.event_qual = EQ_SIZE;

View File

@@ -17,9 +17,6 @@
#define SDIAS_EVSTATE_ALL_STORED 0x00
#define SDIAS_EVSTATE_PART_STORED 0x10
#define SDIAS_EVSTATE_ALL_STORED 0x00
#define SDIAS_EVSTATE_PART_STORED 0x10
struct sdias_evbuf {
struct evbuf_header header;
uint8_t event_qual;
@@ -40,10 +37,11 @@ struct sdias_evbuf {
uint16_t dbs;
} __packed;
/* Structure must not have any padding */
struct sdias_sccb {
struct sccb_header header;
struct sdias_evbuf evbuf;
} __packed;
};
int sclp_hsa_copy(void *, unsigned long, unsigned long);

View File

@@ -9,6 +9,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "lib/zt_common.h"
#include "error.h"
#include "libc.h"
#include "menu.h"
@@ -141,4 +143,4 @@ void panic_notify(unsigned long UNUSED(reason))
{
}
uint64_t stage2_head __attribute__((section(".stage2.head")));
uint64_t __section(.stage2.head) stage2_head;

View File

@@ -11,6 +11,8 @@
#include <stdarg.h>
#include "lib/zt_common.h"
#include "error.h"
#include "sclp.h"
#include "stage2dump.h"
@@ -34,8 +36,7 @@ struct ipib_info {
/*
* Tail parameters
*/
struct stage2dump_parm_tail parm_tail
__attribute__ ((section(".stage2dump.tail"))) = {
struct stage2dump_parm_tail parm_tail = {
.mem_upper_limit = 0xffffffffffffffffULL,
};

View File

@@ -28,8 +28,7 @@ struct stage2dump_parm_tail {
uint64_t mem_upper_limit;
} __packed;
extern struct stage2dump_parm_tail parm_tail
__attribute__ ((section(".stage2dump.tail")));
extern struct stage2dump_parm_tail __section(.stage2dump.tail) parm_tail;
/*
* S390 dump format defines

View File

@@ -13,6 +13,7 @@
#include "s390.h"
#include "stage3.h"
#include "error.h"
#include "zipl.h"
#define for_each_rb_entry(entry, rb) \
for (entry = rb->entries; \
@@ -175,8 +176,7 @@ static void ebcdic_to_ascii(unsigned char *target, unsigned char *source,
target[i] = ebc[source[i]];
}
static void
start_kernel(void)
static inline void __noreturn start_kernel(void)
{
struct psw_t *psw = &S390_lowcore.program_new_psw;
unsigned long addr, code;
@@ -199,6 +199,7 @@ start_kernel(void)
: [addr] "=&d" (addr),
[code] "+&d" (code)
: [psw] "a" (psw) );
while (1);
}
unsigned int
@@ -272,7 +273,7 @@ void start(void)
* verified component. If it is not IPL is aborted.
*/
if (secure_boot_enabled()) {
if (_image_addr != DEFAULT_IMAGE_ADDR ||
if (_image_addr != IMAGE_LOAD_ADDRESS ||
_load_psw != DEFAULT_PSW_LOAD)
panic(ESECUREBOOT, "%s", msg_sipl_inval);
@@ -283,8 +284,8 @@ void start(void)
* cut the kernel header
*/
memmove((void *)_image_addr,
(void *)_image_addr + KERNEL_HEADER_SIZE,
_image_len - KERNEL_HEADER_SIZE);
(void *)_image_addr + IMAGE_LOAD_ADDRESS,
_image_len - IMAGE_LOAD_ADDRESS);
/* store subchannel ID into low core and into new kernel space */
subchannel_id = S390_lowcore.subchannel_id;

View File

@@ -15,12 +15,12 @@
#include "libc.h"
#include "s390.h"
#define IPL_DEVICE 0x10404
#define INITRD_START 0x10408
#define INITRD_SIZE 0x10410
#define OLDMEM_BASE 0x10418
#define OLDMEM_SIZE 0x10420
#define COMMAND_LINE 0x10480
#define IPL_DEVICE 0x10404UL
#define INITRD_START 0x10408UL
#define INITRD_SIZE 0x10410UL
#define OLDMEM_BASE 0x10418UL
#define OLDMEM_SIZE 0x10420UL
#define COMMAND_LINE 0x10480UL
#define COMMAND_LINE_SIZE 896
#define COMMAND_LINE_EXTRA 0xE000
@@ -29,12 +29,10 @@
#define IPL_FLAG_SECURE 0x40
#define DEFAULT_IMAGE_ADDR 0x10000
#define DEFAULT_PSW_LOAD 0x0008000080010000L
#define PSW_ADDR_MASK 0x000000007FFFFFFFL
#define KERNEL_HEADER_SIZE 65536
#define DEFAULT_PSW_LOAD 0x0008000080010000UL
#define PSW_ADDR_MASK 0x000000007FFFFFFFUL
#define UNSPECIFIED_ADDRESS -1ULL
#define UNSPECIFIED_ADDRESS -1UL
/* IPL Parameter List header */
@@ -124,11 +122,12 @@ struct ipl_rl_hdr {
} __packed;
/* IPL Report Block header */
/* Structure must not have any padding */
struct ipl_rb_hdr {
uint32_t len;
uint8_t rbt;
uint8_t reserved1[11];
} __packed;
};
/* IPL Report Block types */
enum ipl_rbt {
@@ -162,12 +161,13 @@ struct ipl_rb_component_entry {
#define IPL_RB_COMPONENT_FLAG_SIGNED 0x80
#define IPL_RB_COMPONENT_FLAG_VERIFIED 0x40
/* Structure must not have any padding */
struct ipl_rb_components {
uint32_t len;
uint8_t rbt;
uint8_t reserved1[11];
struct ipl_rb_component_entry entries[];
} __packed;
};
extern unsigned long long _parm_addr; /* address of parmline */
extern unsigned long long _initrd_addr; /* address of initrd */

View File

@@ -9,6 +9,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "lib/zt_common.h"
#include "cio.h"
#include "error.h"
#include "libc.h"
@@ -33,7 +35,7 @@ struct tape_head {
uint64_t ccw2;
} __packed;
struct tape_head tape_head __attribute__((section(".stage2.head"))) = {
struct tape_head __section(.stage2.head) tape_head = {
.psw = 0x0008000080002018ULL, /* Start code at 0x2018 */
.ccw1 = 0x0700000060000001ULL, /* Rewind ccw */
.ccw2 = 0x0200200020003000ULL, /* CCW to load dump tool to 0x2000 */

View File

@@ -0,0 +1,10 @@
# This is an example of a minimal zipl.conf file that can be used when the
# sections are defined in BootLoaderSpec fragments files.
#
# See the zipl and zipl.conf man page for more details.
[defaultboot]
defaultauto
prompt=1
timeout=5
secure=auto
target=/boot

View File

@@ -14,6 +14,8 @@
#include <sys/types.h>
#include "lib/zt_common.h"
#include "disk.h"
#include "job.h"
#include "zipl.h"
@@ -51,7 +53,7 @@ struct scsi_dump_sb {
uint64_t csum_offset;
uint64_t csum_size;
uint64_t csum;
} __attribute((packed));
} __packed;
#define SCSI_DUMP_SB_MAGIC 0x5a46435044554d50ULL; /* ZFCPDUMP */
/* To avoid a csum entry of 0 a seed is used */
@@ -63,7 +65,7 @@ struct scsi_dump_sb {
struct scsi_dump_param {
uint64_t block;
uint64_t reserved;
} __attribute((packed));
} __packed;
/* ECKD dump parameter */
struct eckd_dump_param {
@@ -73,14 +75,14 @@ struct eckd_dump_param {
uint8_t num_heads;
uint8_t bpt;
char reserved[4];
} __attribute((packed, may_alias));
} __packed __may_alias;
/* FBA dump parameter */
struct fba_dump_param {
uint64_t start_blk;
uint64_t blockct;
} __attribute((packed));
} __packed;
struct boot_info_bp_dump {
union {
@@ -89,7 +91,7 @@ struct boot_info_bp_dump {
struct scsi_dump_param scsi;
} param;
uint8_t unused[16];
} __attribute__ ((packed));
} __packed;
/*
* Layout of block pointer for linear devices
@@ -101,7 +103,7 @@ struct linear_blockptr {
uint16_t size;
uint16_t blockct;
uint8_t reserved[4];
} __attribute((packed));
} __packed;
/*
* Layout of block pointer for cylinder/head/sector devices
@@ -115,7 +117,7 @@ struct eckd_blockptr {
uint16_t size;
uint8_t blockct;
uint8_t reserved[8];
} __attribute((packed));
} __packed;
struct boot_info_bp_ipl {
union {
@@ -123,7 +125,7 @@ struct boot_info_bp_ipl {
struct linear_blockptr lin;
} bm_ptr;
uint8_t unused[16];
} __attribute__ ((packed));
} __packed;
struct boot_info {
char magic[4];
@@ -135,7 +137,7 @@ struct boot_info {
struct boot_info_bp_dump dump;
struct boot_info_bp_ipl ipl;
} bp;
} __attribute__ ((packed));
} __packed;
struct boot_ccw0 {
uint8_t cmd;
@@ -144,21 +146,21 @@ struct boot_ccw0 {
uint8_t flags;
uint8_t pad;
uint16_t count;
} __attribute__ ((packed));
} __packed;
/* Boot data structures for FBA disks */
struct boot_fba_locread {
struct boot_ccw0 locate;
struct boot_ccw0 read;
} __attribute__ ((packed));
} __packed;
struct boot_fba_locdata {
uint8_t command;
uint8_t dummy;
uint16_t blockct;
uint32_t blocknr;
} __attribute__ ((packed));
} __packed;
struct boot_fba_stage0 {
uint64_t psw;
@@ -169,13 +171,13 @@ struct boot_fba_stage0 {
struct boot_fba_locdata locdata[2];
uint64_t reserved[4];
struct boot_info boot_info;
} __attribute__ ((packed));
} __packed;
struct boot_fba_stage1b {
struct boot_fba_locread locread[STAGE2_BLK_CNT_MAX];
struct boot_fba_locdata locdata[STAGE2_BLK_CNT_MAX];
uint8_t unused[448];
} __attribute__ ((packed));
} __packed;
/* Boot data structures for ECKD disks */
@@ -184,14 +186,14 @@ struct boot_eckd_ccw1 {
uint8_t flags;
uint16_t count;
uint32_t address;
} __attribute__ ((packed));
} __packed;
struct boot_eckd_ssrt {
struct boot_ccw0 seek;
struct boot_ccw0 search;
struct boot_ccw0 tic;
struct boot_ccw0 read;
} __attribute__ ((packed));
} __packed;
struct boot_eckd_seekarg {
uint16_t pad;
@@ -199,32 +201,32 @@ struct boot_eckd_seekarg {
uint16_t head;
uint8_t sec;
uint8_t pad2;
} __attribute__ ((packed));
} __packed;
struct boot_eckd_cdl_stage0 {
uint64_t psw;
struct boot_ccw0 read;
struct boot_ccw0 tic;
} __attribute__ ((packed));
} __packed;
struct boot_eckd_ldl_stage0 {
uint64_t psw;
struct boot_ccw0 read_r0;
struct boot_ccw0 read_r1;
} __attribute__ ((packed));
} __packed;
struct boot_eckd_stage1 {
struct boot_eckd_ssrt ssrt[2];
struct boot_ccw0 tic1b;
struct boot_eckd_seekarg seek[2];
struct boot_info boot_info;
} __attribute__ ((packed));
} __packed;
struct boot_eckd_stage1b {
struct boot_eckd_ssrt ssrt[STAGE2_BLK_CNT_MAX];
struct boot_eckd_seekarg seek[STAGE2_BLK_CNT_MAX];
uint8_t unused[64];
} __attribute__ ((packed));
} __packed;
/* Stage 2 boot menu parameter structure */
@@ -236,7 +238,7 @@ struct boot_stage2_params {
uint16_t banner;
uint16_t config[BOOT_MENU_ENTRIES + 1];
uint64_t config_kdump;
} __attribute__ ((packed));
} __packed;
/* Stage 3 bootloader parameter structure */
@@ -251,7 +253,7 @@ struct boot_stage3_params {
uint16_t reserved[3];
uint64_t image_len;
uint64_t image_addr;
} __attribute__ ((packed));
} __packed;
#define STAGE3_FLAG_SCSI 0x0001
#define STAGE3_FLAG_KDUMP 0x0002
@@ -275,7 +277,7 @@ struct mvdump_param {
uint8_t blocksize;
uint8_t bpt;
uint8_t num_heads;
} __attribute__ ((packed));
} __packed;
struct mvdump_parm_table {
uint64_t timestamp;
@@ -284,7 +286,7 @@ struct mvdump_parm_table {
uint8_t ssid[MAX_DUMP_VOLUMES];
unsigned char reserved[512 - sizeof(uint64_t) - sizeof(uint16_t) -
(MAX_DUMP_VOLUMES * (sizeof(struct mvdump_param) + 1))];
} __attribute__ ((packed));
} __packed;
void boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type,
void *param);
@@ -310,8 +312,8 @@ int boot_init_fba_stage1b(struct boot_fba_stage1b *stage1b,
int boot_get_eckd_stage2(void** data, size_t* size, struct job_data* job);
int boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr,
address_t initrd_addr, size_t initrd_len,
address_t load_addr, int extra_parm, uint16_t flags,
size_t image_len);
address_t entry, int extra_parm, uint16_t flags,
address_t image_addr, size_t image_len);
int boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr,
address_t initrd_addr, address_t image_addr);
int boot_get_tape_dump(void** data, size_t* size, uint64_t mem);

View File

@@ -12,6 +12,8 @@
#ifndef BOOTMAP_H
#define BOOTMAP_H
#include "lib/zt_common.h"
#include "disk.h"
#include "job.h"
#include "zipl.h"
@@ -23,7 +25,7 @@ struct signature_header {
uint8_t format;
uint8_t reserved[3];
uint32_t length;
} __attribute((packed));
} __packed;
typedef union {
uint64_t load_address;

View File

@@ -126,6 +126,7 @@ char* scan_keyword_name(enum scan_keyword_id id);
int scan_check_defaultboot(struct scan_token* scan);
struct scan_token* scan_build_automenu(struct scan_token* scan);
int scan_check(struct scan_token* scan);
int scan_check_bls(struct scan_token *scan);
int scan_find_section(struct scan_token* scan, char* name, enum scan_id type,
int offset);
int scan_check_section_data(char* keyword[], int* line, char* name,

View File

@@ -19,27 +19,29 @@
#define ZIPL_MAGIC_SIZE 4
#define DISK_LAYOUT_ID 0x00000001
#define ZIPL_STAGE2_LOAD_ADDRESS 0x2000
#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa000LL
#define DEFAULT_IMAGE_ADDRESS 0x10000LL
#define KDUMP_IMAGE_ADDRESS 0x10010LL
#define DEFAULT_STAGE3_ADDRESS 0xa000LL
#define DEFAULT_STAGE3_PARAMS_ADDRESS 0x9000LL
#define MINIMUM_ADDRESS 0x10000LL
#define ADDRESS_LIMIT 0x80000000LL
#define STAGE3_ENTRY 0xa000UL
#define IMAGE_ENTRY 0x10000UL
#define IMAGE_ENTRY_KDUMP 0x10010UL
#define STAGE2_LOAD_ADDRESS 0x2000UL
#define STAGE3_LOAD_ADDRESS 0xa000UL
#define IMAGE_LOAD_ADDRESS IMAGE_ENTRY
#define ADDRESS_LIMIT 0x80000000UL
#define ADDRESS_LIMIT_KDUMP 0x2000000UL /* HSA size: 32 MiB */
#define UNSPECIFIED_ADDRESS -1ULL
#define MAXIMUM_PARMLINE_SIZE 0x380
#define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000
#define UNSPECIFIED_ADDRESS -1UL
#define MAXIMUM_PARMLINE_SIZE 0x380UL
#define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000UL
#define STAGE3_HEAP_SIZE 0x4000
#define STAGE3_HEAP_ADDRESS 0x2000
#define STAGE3_STACK_SIZE 0x1000
#define STAGE3_STACK_ADDRESS 0xF000
#define STAGE3_HEAP_SIZE 0x4000UL
#define STAGE3_HEAP_ADDRESS 0x2000UL
#define STAGE3_STACK_SIZE 0x1000UL
#define STAGE3_STACK_ADDRESS 0xF000UL
#define STAGE3_PARAMS_ADDRESS 0x9000UL
#define PSW_ADDRESS_MASK 0x000000007fffffffLL
#define PSW_LOAD 0x0008000080000000LL
#define PSW_DISABLED_WAIT 0x000a000000000000LL
#define PSW_ADDRESS_MASK 0x000000007fffffffUL
#define PSW_LOAD 0x0008000080000000UL
#define PSW_DISABLED_WAIT 0x000a000000000000UL
#define BOOTMAP_FILENAME "bootmap"
#define BOOTMAP_TEMPLATE_FILENAME "bootmap_temp.XXXXXX"
@@ -47,7 +49,9 @@
#define DEFAULTBOOT_SECTION "defaultboot"
#define ZIPL_CONF_VAR "ZIPLCONF"
#define ZIPL_RUNTIME_CONF "/run/zipl/zipl.conf"
#define ZIPL_DEFAULT_CONF TOOLS_SYSCONFDIR "/zipl.conf"
#define ZIPL_MINIMAL_CONF TOOLS_LIBDIR "/zipl.conf"
#define ZIPL_DEFAULT_BLSDIR "/boot/loader/entries"
#define ZIPL_STAGE3_PATH TOOLS_LIBDIR "/stage3.bin"
#define ZIPL_SIPL_PATH "/sys/firmware/ipl/has_secure"

View File

@@ -6,7 +6,13 @@ all:
install:
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man5
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 -c zipl.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 -c zipl.conf.5 $(DESTDIR)$(MANDIR)/man5
sed -e 's@%SYSCONFDIR%@$(SYSCONFDIR)@' \
-e 's@%TOOLS_LIBDIR%@$(TOOLS_LIBDIR)@' zipl.8.in \
> $(DESTDIR)$(MANDIR)/man8/zipl.8
sed -e 's@%SYSCONFDIR%@$(SYSCONFDIR)@' \
-e 's@%TOOLS_LIBDIR%@$(TOOLS_LIBDIR)@' zipl.conf.5.in \
> $(DESTDIR)$(MANDIR)/man5/zipl.conf.5
chmod 644 $(DESTDIR)$(MANDIR)/man8/zipl.8 \
$(DESTDIR)$(MANDIR)/man5/zipl.conf.5
clean:

View File

@@ -120,7 +120,7 @@ Print version information, then exit.
.TP
.BR "\-c <CONFIG FILE>" " or " "\-\-config=<CONFIG FILE>"
Use the specified <CONFIG FILE>. If none is supplied, the environment
variable ZIPLCONF is evaluated if set, otherwise /etc/zipl.conf is used.
variable ZIPLCONF is evaluated if set, otherwise %SYSCONFDIR%/zipl.conf is used.
.TP
.BR "\-b <BLS DIRECTORY>" " or " "\-\-blsdir=<BLS DIRECTORY>"

View File

@@ -17,8 +17,13 @@ boot loader tool
.BR zipl (8)).
.br
By default this configuration file is located at /etc/zipl.conf. A different
location may be specified either using the '\-\-config' option of
By default
.B zipl
checks for
.I zipl.conf
at /run/zipl/zipl.conf, %SYSCONFDIR%/zipl.conf, %TOOLS_LIBDIR%/zipl.conf in that
order - whichever is found first will be used. Users can specifically choose a
location using the '\-\-config' option of
.B zipl
or by setting the ZIPLCONF shell environment variable.
.br
@@ -138,7 +143,13 @@ initrd /initramfs-4.15.9
options root=/dev/dasda1 console=ttyS0
.PP
The location of the linux and initrd has to be specified relative to the boot partition. The BLS config files are only used to specify the IPL sections, a zipl.conf configuration files is still needed for global parameters.
The location of the linux and initrd has to be specified relative to the boot
partition. The BLS config files are only used to specify the IPL sections, a
zipl.conf configuration file is still needed for global parameters. For this
purpose, a minimal zipl.conf configuration file is shipped at
%TOOLS_LIBDIR%/zipl.conf which would help when used with BLS config files, by
not requiring users to create the traditional configuration file at
%SYSCONFDIR%/zipl.conf.
.B Boot menu

View File

@@ -45,10 +45,10 @@ clean:
.boot.o.d boot.o: ../boot/data.h
../boot/data.h:
make -C ../boot data.h
$(MAKE) -C ../boot data.h
../boot/data.o:
make -C ../boot data.o
$(MAKE) -C ../boot data.o
../boot/stage3.bin:
make -C ../boot stage3.bin
$(MAKE) -C ../boot stage3.bin

View File

@@ -79,14 +79,14 @@ boot_check_data(void)
int
boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr,
address_t initrd_addr, size_t initrd_len,
address_t image_addr, int extra_parm, uint16_t flags,
size_t image_len)
address_t entry, int extra_parm, uint16_t flags,
address_t image_addr, size_t image_len)
{
struct boot_stage3_params params;
void* data;
if (image_addr != (image_addr & PSW_ADDRESS_MASK)) {
error_reason("Kernel image load address to high (31 bit "
if (entry != (entry & PSW_ADDRESS_MASK)) {
error_reason("Kernel image entry point to high (31 bit "
"addressing mode)");
return -1;
}
@@ -99,7 +99,7 @@ boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr,
params.parm_addr = (uint64_t) parm_addr;
params.initrd_addr = (uint64_t) initrd_addr;
params.initrd_len = (uint64_t) initrd_len;
params.load_psw = (uint64_t)(image_addr | PSW_LOAD);
params.load_psw = (uint64_t)(entry | PSW_LOAD);
params.extra_parm = (uint64_t) extra_parm;
params.flags = flags;
params.image_len = (uint64_t) image_len;
@@ -195,7 +195,7 @@ boot_init_fba_stage1b(struct boot_fba_stage1b *stage1b,
stage1b->locdata[i].blocknr =
(uint32_t) stage2_list[i].linear.block;
stage1b->locread[i].read.address_lo =
ZIPL_STAGE2_LOAD_ADDRESS + i * FBA_BLK_SIZE;
STAGE2_LOAD_ADDRESS + i * FBA_BLK_SIZE;
}
/* Terminate CCW chain */
stage1b->locread[i - 1].read.flags &= ~CCW_FLAG_CC;
@@ -220,7 +220,7 @@ boot_init_eckd_stage1b(struct boot_eckd_stage1b *stage1b,
stage1b->seek[i].head = stage2_list[i].chs.head |
((stage2_list[i].chs.cyl >> 12) & 0xfff0);
stage1b->seek[i].sec = stage2_list[i].chs.sec;
stage1b->ssrt[i].read.address_lo = ZIPL_STAGE2_LOAD_ADDRESS +
stage1b->ssrt[i].read.address_lo = STAGE2_LOAD_ADDRESS +
i * stage2_list[i].chs.size;
stage1b->ssrt[i].read.flags = CCW_FLAG_CC | CCW_FLAG_SLI;
}

View File

@@ -18,6 +18,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include "lib/zt_common.h"
#include "lib/util_part.h"
#include "lib/util_path.h"
@@ -223,7 +224,7 @@ struct component_entry {
uint8_t data[23];
uint8_t type;
component_data compdat;
} __attribute((packed));
} __packed;
typedef enum {
component_execute = 0x01,
@@ -263,7 +264,7 @@ struct component_header {
uint8_t magic[4];
uint8_t type;
uint8_t reserved[27];
} __attribute((packed));
} __packed;
typedef enum {
component_header_ipl = 0x00,
@@ -626,7 +627,7 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
}
/* Add stage 3 loader to bootmap */
rc = add_component_file(fd, ZIPL_STAGE3_PATH, DEFAULT_STAGE3_ADDRESS,
rc = add_component_file(fd, ZIPL_STAGE3_PATH, STAGE3_LOAD_ADDRESS,
signature_size, VOID_ADD(table, offset), 1,
info, target, &comp_loc[comp_nr]);
if (rc) {
@@ -643,17 +644,17 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
rc = boot_get_stage3_parms(&stage3_params, &stage3_params_size,
ipl->parm_addr, ipl->ramdisk_addr,
ramdisk_size,
ipl->is_kdump ? ipl->image_addr + 0x10 :
ipl->image_addr,
ipl->is_kdump ? IMAGE_ENTRY_KDUMP :
IMAGE_ENTRY,
(info->type == disk_type_scsi) ? 0 : 1,
flags, image_size);
flags, ipl->image_addr, image_size);
if (rc) {
free(table);
return rc;
}
rc = add_component_buffer(fd, stage3_params, stage3_params_size,
(component_data) (uint64_t)
DEFAULT_STAGE3_PARAMS_ADDRESS,
STAGE3_PARAMS_ADDRESS,
VOID_ADD(table, offset), info,
&comp_loc[comp_nr], component_load);
free(stage3_params);
@@ -791,7 +792,7 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
create_component_entry(VOID_ADD(table, offset), NULL,
component_execute,
(component_data) (uint64_t)
(ZIPL_STAGE3_ENTRY_ADDRESS | PSW_LOAD),
(STAGE3_ENTRY | PSW_LOAD),
info);
/* Write component table */
rc = disk_write_block_aligned(fd, table, info->phy_block_size,
@@ -1174,7 +1175,7 @@ bootmap_create(struct job_data *job, disk_blockptr_t *program_table,
ulong unused_size;
/* Use approximated stage 3 size as starting point */
size = MINIMUM_ADDRESS;
size = IMAGE_LOAD_ADDRESS;
/* Ramdisk */
if (job->data.dump.ramdisk != NULL) {
@@ -1186,7 +1187,7 @@ bootmap_create(struct job_data *job, disk_blockptr_t *program_table,
/* Kernel */
if (stat(job->data.dump.image, &st))
goto out_misc_free_temp_dev;
size += DIV_ROUND_UP(st.st_size - 0x10000,
size += DIV_ROUND_UP(st.st_size - IMAGE_LOAD_ADDRESS,
info->phy_block_size);
/* Parmfile */
size += DIV_ROUND_UP(DUMP_PARAM_MAX_LEN, info->phy_block_size);

View File

@@ -23,6 +23,7 @@
#include <syslog.h>
#include <unistd.h>
#include "lib/zt_common.h"
#include "lib/util_sys.h"
#include "boot.h"
@@ -89,7 +90,7 @@ update_scsi_mbr(void* bootblock, disk_blockptr_t* table,
uint8_t program_table_pointer[16];
uint8_t reserved2[0x50];
struct boot_info boot_info;
} __attribute__ ((packed))* mbr;
} __packed* mbr;
struct scsi_dump_param param;
void* buffer;

View File

@@ -23,6 +23,7 @@
#include "job.h"
#include "misc.h"
#include "scan.h"
#include "zipl.h"
/* Command line options */
static struct option options[] = {
@@ -59,6 +60,14 @@ static struct option options[] = {
/* Command line option abbreviations */
static const char option_string[] = "-c:b:t:i:r:p:P:d:D:M:s:S:m:hHnVvaT:fk:";
/* Locations of zipl.conf configuration file */
static const char *zipl_conf[] = {
ZIPL_RUNTIME_CONF,
ZIPL_DEFAULT_CONF,
ZIPL_MINIMAL_CONF,
NULL
};
struct command_line {
char* data[SCAN_KEYWORD_NUM];
char* config;
@@ -647,12 +656,12 @@ check_component_address_data(struct component_loc *cl, int num, char *name,
address_limit);
return -1;
}
if (*cl[i].addrp < MINIMUM_ADDRESS) {
if (*cl[i].addrp < IMAGE_LOAD_ADDRESS) {
if (name != NULL)
error_text("Section '%s'", name);
error_reason("Component '%s' falls below available "
"address space (limit is 0x%08x)",
cl[i].name, MINIMUM_ADDRESS);
cl[i].name, IMAGE_LOAD_ADDRESS);
return -1;
}
}
@@ -690,12 +699,12 @@ finalize_component_address_data(struct component_loc *cl, int num,
for (j = -1; j < i; j++) {
if (j < 0) {
/* Try address before first component */
addr = MINIMUM_ADDRESS;
addr = IMAGE_LOAD_ADDRESS;
} else {
/* Try address after component j */
addr = *cl[j].addrp + cl[j].size;
if (addr < MINIMUM_ADDRESS)
addr = MINIMUM_ADDRESS;
if (addr < IMAGE_LOAD_ADDRESS)
addr = IMAGE_LOAD_ADDRESS;
}
addr = ALIGN(addr, cl[i].align);
if (addr + cl[i].size > address_limit) {
@@ -889,7 +898,7 @@ check_job_dump_images(struct job_dump_data* dump, char* name)
dump->image = misc_strdup(ZFCPDUMP_IMAGE);
if (dump->image == NULL)
return -1;
dump->image_addr = DEFAULT_IMAGE_ADDRESS;
dump->image_addr = IMAGE_LOAD_ADDRESS;
/* Ramdisk is no longer required with new initramfs dump system */
if (misc_check_readable_file(ZFCPDUMP_INITRD))
@@ -1339,7 +1348,7 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
return -1;
if (extract_address(job->data.ipl.image,
&job->data.ipl.image_addr)) {
job->data.ipl.image_addr = DEFAULT_IMAGE_ADDRESS;
job->data.ipl.image_addr = IMAGE_LOAD_ADDRESS;
}
/* Fill in parmline */
rc = get_parmline(data[(int) scan_keyword_parmfile],
@@ -1394,7 +1403,7 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
return -1;
if (extract_address(job->data.ipl_tape.image,
&job->data.ipl_tape.image_addr)) {
job->data.ipl_tape.image_addr = DEFAULT_IMAGE_ADDRESS;
job->data.ipl_tape.image_addr = IMAGE_LOAD_ADDRESS;
}
/* Fill in parmline */
rc = get_parmline(data[(int) scan_keyword_parmfile],
@@ -1780,10 +1789,10 @@ get_job_from_config_file(struct command_line* cmdline, struct job_data* job)
{
struct scan_token* scan;
struct scan_token* new_scan;
char* filename;
const char *filename = NULL;
char *blsdir;
char* source;
int rc, scan_size;
int i, rc, scan_size;
/* Read configuration file */
if (cmdline->config != NULL) {
@@ -1797,7 +1806,16 @@ get_job_from_config_file(struct command_line* cmdline, struct job_data* job)
ZIPL_CONF_VAR ")";
} else {
/* Use default config file */
filename = ZIPL_DEFAULT_CONF;
for (i = 0; zipl_conf[i]; i++) {
if (misc_check_readable_file(zipl_conf[i]) == 0) {
filename = zipl_conf[i];
break;
}
}
if (filename == NULL) {
error_text("No zipl configuration was readable");
return -1;
}
source = "";
}
printf("Using config file '%s'%s\n", filename, source);
@@ -1840,6 +1858,12 @@ get_job_from_config_file(struct command_line* cmdline, struct job_data* job)
scan_free(scan);
return rc;
}
rc = scan_check_bls(scan);
if (rc) {
error_text("BLS parsing '%s'", blsdir);
scan_free(scan);
return rc;
}
/* Get job from config file data */
if (cmdline->menu != NULL)
rc = get_menu_job(scan, cmdline->menu, job);

View File

@@ -755,8 +755,14 @@ scan_bls(const char* blsdir, struct scan_token** token, int scan_size)
remaining = scan_size - count;
if (remaining < n) {
size = scan_size - remaining + n;
/* The array of scanned tokens is allocated when the zipl config file is
* parsed. Its size is a multiple of INITIAL_ARRAY_LENGTH so it may have
* enough space to scan all the tokens that are defined in the BLS files.
* Calculate if is enough assuming that a BLS fragment can contain up to
* 4 tokens: a section heading and 3 keywords (image, ramdisk, parameter).
*/
if (remaining < n * 4) {
size = scan_size - remaining + (n * 4);
buffer = (struct scan_token *)misc_malloc(size * sizeof(struct scan_token));
if (!buffer)
goto err;
@@ -1558,6 +1564,64 @@ scan_check(struct scan_token* scan)
return 0;
}
/*
* Check if kernel and initrd image paths provided by BLS files are readable.
* If not, add value of 'scan_keyword_target' into search path and silently
* update scan list.
*/
int
scan_check_bls(struct scan_token *scan)
{
int i, rc;
char *target_value = NULL;
char *img_value = NULL;
char *buffer = NULL;
/*
* In the BLS case, each BLS section heading inherits a keyword
* assignment target= from zipl.conf, and they are all the same.
*
*/
for (i = 0 ; scan[i].id != scan_id_empty; i++) {
if (scan[i].id == scan_id_keyword_assignment &&
scan[i].content.keyword.keyword == scan_keyword_target) {
target_value = scan[i].content.keyword.value;
break;
}
}
if (!target_value)
return -1;
for (i = 0 ; scan[i].id != scan_id_empty; i++) {
if (scan[i].id != scan_id_keyword_assignment)
continue;
if (scan[i].content.keyword.keyword == scan_keyword_image ||
scan[i].content.keyword.keyword == scan_keyword_ramdisk) {
rc = misc_check_readable_file(
scan[i].content.keyword.value);
if (rc) {
misc_asprintf(&img_value, "%s%s",
target_value,
scan[i].content.keyword.value);
rc = misc_check_readable_file(img_value);
if (rc) {
error_text(
"Image file '%s' is not accessible",
scan[i].content.keyword.value);
return rc;
}
buffer = (char *)
misc_malloc(strlen(img_value) + 1);
if (buffer == NULL)
return -1;
memcpy(buffer, img_value, strlen(img_value));
buffer[strlen(img_value)] = 0;
free(scan[i].content.keyword.value);
scan[i].content.keyword.value = buffer;
}
}
}
return 0;
}
static int
scan_get_defaultboot_type(char* keyword[], int line[], int section_line,

View File

@@ -68,6 +68,8 @@ static const char* usage_text[] = {
"-P, --parameters PARMLINE Use specified kernel PARMLINE",
"-T, --tape TAPEDEV Install bootloader on tape device TAPEDEV",
"-s, --segment SEGMENT,ADDR Install a segment from file SEGMENT",
"-k, --kdump=auto Install a kdump kernel that can be used as a",
" stand-alone dump tool",
"-d, --dumpto DUMPDEV[,SIZE] Install a system dump record on tape device",
" or disk partition DUMPDEV",
"-M, --mvdump DEVLIST[,SIZE] Install a multi-volume dump record on each",
@@ -78,7 +80,12 @@ static const char* usage_text[] = {
"-n, --noninteractive Answer all confirmation questions with 'yes'",
"-V, --verbose Provide more verbose output",
"-a, --add-files Add all referenced files to bootmap file",
" --dry-run Simulate run but don't modify IPL records"
" --dry-run Simulate run but don't modify IPL records",
"-S, --secure SWITCH Control the zIPL secure boot support.",
" auto (default):",
" Write signatures if available and supported",
" 1: Write signatures regardless of support",
" 0: Do not write signatures"
};

View File

@@ -64,18 +64,20 @@ zkey-cryptsetup-skip-jsonc:
all: $(BUILD_TARGETS)
zkey.o: zkey.c pkey.h misc.h
zkey.o: zkey.c pkey.h cca.h misc.h
pkey.o: pkey.c pkey.h
cca.o: cca.c cca.h pkey.h utils.h
utils.o: utils.h
properties.o: check-dep-zkey properties.c properties.h
keystore.o: keystore.c keystore.h properties.h
zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h misc.h
keystore.o: keystore.c keystore.h properties.h pkey.h cca.h utils.h
zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h cca.h misc.h
zkey: LDLIBS = -ldl -lcrypto
zkey: zkey.o pkey.o properties.o keystore.o $(libs)
zkey: zkey.o pkey.o cca.o properties.o keystore.o utils.o $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c
zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(libs)
zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o utils.o $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
install-common:

981
zkey/cca.c Normal file
View File

@@ -0,0 +1,981 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* Copyright IBM Corp. 2019
*
* 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 <dlfcn.h>
#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_panic.h"
#include "cca.h"
#include "pkey.h"
#include "utils.h"
#define pr_verbose(verbose, fmt...) do { \
if (verbose) \
warnx(fmt); \
} while (0)
/*
* Definitions for the CCA library
*/
#define CCA_LIBRARY_NAME "libcsulcca.so"
#define CCA_WEB_PAGE "http://www.ibm.com/security/cryptocards"
#define CCA_DOMAIN_ENVAR "CSU_DEFAULT_DOMAIN"
#define CCA_ADAPTER_ENVAR "CSU_DEFAULT_ADAPTER"
/**
* Prints CCA return and reason code information for certain known CCA
* error situations.
*
* @param return_code the CCA return code
* @param reason_code the CCA reason code
*/
static void print_CCA_error(int return_code, int reason_code)
{
switch (return_code) {
case 8:
switch (reason_code) {
case 48:
warnx("The secure key has a CCA master key "
"verification pattern that is not valid");
break;
case 90:
warnx("The operation has been rejected due to access "
"control checking");
break;
case 2143:
warnx("The operation has been rejected due to key "
"export restrictions of the secure key");
break;
}
break;
case 12:
switch (reason_code) {
case 764:
warnx("The CCA master key is not loaded and "
"therefore a secure key cannot be enciphered");
break;
}
break;
}
}
/**
* Returns the version, release and modification number of the used CCA library.
*
* @param[in] cca the CCA library structure
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error
*/
static int get_cca_version(struct cca_lib *cca, bool verbose)
{
unsigned char exit_data[4] = { 0, };
unsigned char version_data[20];
long return_code, reason_code;
long version_data_length;
long exit_data_len = 0;
char date[20];
util_assert(cca != NULL, "Internal error: cca is NULL");
memset(version_data, 0, sizeof(version_data));
version_data_length = sizeof(version_data);
cca->dll_CSUACFV(&return_code, &reason_code,
&exit_data_len, exit_data,
&version_data_length, version_data);
pr_verbose(verbose, "CSUACFV (Cryptographic Facility Version) "
"returned: return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
version_data[sizeof(version_data) - 1] = '\0';
pr_verbose(verbose, "CCA Version string: %s", version_data);
if (sscanf((char *)version_data, "%u.%u.%uz%s", &cca->version.ver,
&cca->version.rel, &cca->version.mod, date) != 4) {
warnx("CCA library version is invalid: %s", version_data);
return -EINVAL;
}
return 0;
}
/**
* Loads the CCA library and provides the entry point of the CSNBKTC function.
*
* @param[out] cca on return this contains the address of the CCA
* library and certain CCA symbols. dlclose() should
* be used to free the library when no longer needed.
* @param verbose if true, verbose messages are printed
*
* @returns 0 on success, -ELIBACC in case of library load errors
*/
int load_cca_library(struct cca_lib *cca, bool verbose)
{
util_assert(cca != NULL, "Internal error: caa is NULL");
/* Load the CCA library */
cca->lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW);
if (cca->lib_csulcca == NULL) {
pr_verbose(verbose, "%s", dlerror());
warnx("The command requires the IBM CCA Host Libraries and "
"Tools.\nFor the supported environments and downloads, "
"see:\n%s", CCA_WEB_PAGE);
return -ELIBACC;
}
/* Get the Cryptographic Facility Version function */
cca->dll_CSUACFV = (t_CSUACFV)dlsym(cca->lib_csulcca, "CSUACFV");
/* Get the Key Token Change function */
cca->dll_CSNBKTC = (t_CSNBKTC)dlsym(cca->lib_csulcca, "CSNBKTC");
/* Get the Key Token Change 2 function */
cca->dll_CSNBKTC2 = (t_CSNBKTC2)dlsym(cca->lib_csulcca, "CSNBKTC2");
/* Get the Cryptographic Facility Query function */
cca->dll_CSUACFQ = (t_CSUACFQ)dlsym(cca->lib_csulcca, "CSUACFQ");
/* Get the Cryptographic Resource Allocate function */
cca->dll_CSUACRA = (t_CSUACRA)dlsym(cca->lib_csulcca, "CSUACRA");
/* Cryptographic Resource Deallocate function */
cca->dll_CSUACRD = (t_CSUACRD)dlsym(cca->lib_csulcca, "CSUACRD");
/* Get the Key Translate 2 function */
cca->dll_CSNBKTR2 = (t_CSNBKTR2)dlsym(cca->lib_csulcca, "CSNBKTR2");
/* Get the Restrict Key Attribute function */
cca->dll_CSNBRKA = (t_CSNBRKA)dlsym(cca->lib_csulcca, "CSNBRKA");
if (cca->dll_CSUACFV == NULL ||
cca->dll_CSNBKTC == NULL ||
cca->dll_CSNBKTC2 == NULL ||
cca->dll_CSUACFQ == NULL ||
cca->dll_CSUACRA == NULL ||
cca->dll_CSUACRD == NULL ||
cca->dll_CSNBKTR2 == NULL ||
cca->dll_CSNBRKA == NULL) {
pr_verbose(verbose, "%s", dlerror());
warnx("The command requires the IBM CCA Host Libraries and "
"Tools.\nFor the supported environments and downloads, "
"see:\n%s", CCA_WEB_PAGE);
dlclose(cca->lib_csulcca);
cca->lib_csulcca = NULL;
return -ELIBACC;
}
pr_verbose(verbose, "CCA library '%s' has been loaded successfully",
CCA_LIBRARY_NAME);
return get_cca_version(cca, verbose);
}
/**
* Re-enciphers a secure key.
*
* @param[in] cca the CCA libraray structure
* @param[in] secure_key a buffer containing the secure key
* @param[in] secure_key_size the size of the secure key
* @param[in] method the re-enciphering method. METHOD_OLD_TO_CURRENT
* or METHOD_CURRENT_TO_NEW.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, -EIO in case of an error
*/
int key_token_change(struct cca_lib *cca,
u8 *secure_key, unsigned int secure_key_size,
char *method, bool verbose)
{
struct aescipherkeytoken *cipherkey =
(struct aescipherkeytoken *)secure_key;
long exit_data_len = 0, rule_array_count;
unsigned char rule_array[2 * 8] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
long key_token_length;
util_assert(cca != NULL, "Internal error: cca is NULL");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
util_assert(secure_key_size > 0,
"Internal error: secure_key_size is 0");
util_assert(method != NULL, "Internal error: method is NULL");
memcpy(rule_array, method, 8);
memcpy(rule_array + 8, "AES ", 8);
rule_array_count = 2;
if (is_cca_aes_data_key(secure_key, secure_key_size)) {
cca->dll_CSNBKTC(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
secure_key);
pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' "
"returned: return_code: %ld, reason_code: %ld",
method, return_code, reason_code);
} else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
key_token_length = cipherkey->length;
cca->dll_CSNBKTC2(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&key_token_length,
(unsigned char *)cipherkey);
pr_verbose(verbose, "CSNBKTC2 (Key Token Change2) with '%s' "
"returned: return_code: %ld, reason_code: %ld",
method, return_code, reason_code);
pr_verbose(verbose, "key_token_length: %lu", key_token_length);
} else {
warnx("Invalid key type specified");
return -EINVAL;
}
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
if (is_xts_key(secure_key, secure_key_size)) {
if (is_cca_aes_data_key(secure_key, secure_key_size)) {
cca->dll_CSNBKTC(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
secure_key + AESDATA_KEY_SIZE);
pr_verbose(verbose, "CSNBKTC (Key Token Change) with "
"'%s' returned: return_code: %ld, "
"reason_code: %ld", method, return_code,
reason_code);
} else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
cipherkey = (struct aescipherkeytoken *)(secure_key +
AESCIPHER_KEY_SIZE);
key_token_length = cipherkey->length;
cca->dll_CSNBKTC2(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&key_token_length,
(unsigned char *)cipherkey);
pr_verbose(verbose, "CSNBKTC2 (Key Token Change2) with "
"'%s' returned: return_code: %ld, "
"reason_code: %ld", method, return_code,
reason_code);
pr_verbose(verbose, "key_token_length: %lu",
key_token_length);
} else {
warnx("Invalid key type specified");
return -EINVAL;
}
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
}
return 0;
}
/**
* Queries the number of adapters known by the CCA host library
*
* @param[in] cca the CCA library structure
* @param[out] adapters the number of adapters
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error.
*/
static int get_number_of_cca_adapters(struct cca_lib *cca,
unsigned int *adapters, bool verbose)
{
long exit_data_len = 0, rule_array_count, verb_data_length = 0;
unsigned char rule_array[16 * 8] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
util_assert(cca != NULL, "Internal error: cca is NULL");
util_assert(adapters != NULL, "Internal error: adapters is NULL");
memset(rule_array, 0, sizeof(rule_array));
memcpy(rule_array, "STATCRD2", 8);
rule_array_count = 1;
cca->dll_CSUACFQ(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&verb_data_length, NULL);
pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
"return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
rule_array[8] = '\0';
if (sscanf((char *)rule_array, "%u", adapters) != 1) {
pr_verbose(verbose, "Unparsable output: %s", rule_array);
return -EIO;
}
pr_verbose(verbose, "Number of CCA adapters: %u", *adapters);
return 0;
}
/**
* Allocate a specific CCA adapter.
*
* @param[in] cca the CCA library structure
* @param[in] adapter the adapter number, starting at 1. If 0 is
* specified, then the AUTOSELECT option is
* enabled.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error. -ENODEV is
* returned if the adapter is not available.
*/
static int allocate_cca_adapter(struct cca_lib *cca, unsigned int adapter,
bool verbose)
{
long exit_data_len = 0, rule_array_count;
unsigned char rule_array[8] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
char res_name[9];
long res_name_len;
util_assert(cca != NULL, "Internal error: cca is NULL");
if (adapter > 0)
memcpy(rule_array, "DEVICE ", 8);
else
memcpy(rule_array, "DEV-ANY ", 8);
rule_array_count = 1;
sprintf(res_name, "CRP%02d", adapter);
res_name_len = strlen(res_name);
cca->dll_CSUACRA(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&res_name_len, (unsigned char *)res_name);
pr_verbose(verbose, "CSUACRA (Cryptographic Resource Allocate) "
"returned: return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -ENODEV;
}
pr_verbose(verbose, "Adapter %u (%s) allocated", adapter, res_name);
return 0;
}
/**
* Deallocate a specific CCA adapter.
*
* @param[in] cca the CCA library structure
* @param[in] adapter the adapter number, starting at 1. If 0 is
* specified, then the AUTOSELECT option is
* disabled.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error. -ENODEV is
* returned if the adapter is not available.
*/
static int deallocate_cca_adapter(struct cca_lib *cca, unsigned int adapter,
bool verbose)
{
long exit_data_len = 0, rule_array_count;
unsigned char rule_array[8] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
char res_name[9];
long res_name_len;
util_assert(cca != NULL, "Internal error: cca is NULL");
if (adapter > 0)
memcpy(rule_array, "DEVICE ", 8);
else
memcpy(rule_array, "DEV-ANY ", 8);
rule_array_count = 1;
sprintf(res_name, "CRP%02d", adapter);
res_name_len = strlen(res_name);
cca->dll_CSUACRD(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&res_name_len, (unsigned char *)res_name);
pr_verbose(verbose, "CSUACRD (Cryptographic Resource Deallocate) "
"returned: return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -ENODEV;
}
pr_verbose(verbose, "Adapter %u (%s) deallocated", adapter, res_name);
return 0;
}
/**
* Queries the serial number of the current CCA adapter
*
* @param[in] cca the CCA library structure
* @param[out] serialnr the buffer where the serial number is returned
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error.
*/
static int get_cca_adapter_serialnr(struct cca_lib *cca, char serialnr[9],
bool verbose)
{
long exit_data_len = 0, rule_array_count, verb_data_length = 0;
unsigned char rule_array[16 * 8] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
util_assert(cca != NULL, "Internal error: cca is NULL");
memset(rule_array, 0, sizeof(rule_array));
memcpy(rule_array, "STATCRD2", 8);
rule_array_count = 1;
cca->dll_CSUACFQ(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&verb_data_length, NULL);
pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
"return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
memcpy(serialnr, rule_array+14*8, 8);
serialnr[8] = '\0';
pr_verbose(verbose, "Serial number of CCA adapter: %s", serialnr);
return 0;
}
/**
* Queries the firmware version of the current CCA adapter
*
* @param[in] cca the CCA library structure
* @param[out] version the struct where the version is returned
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error.
*/
static int get_cca_adapter_version(struct cca_lib *cca,
struct cca_version *version,
bool verbose)
{
long exit_data_len = 0, rule_array_count, verb_data_length = 0;
unsigned char rule_array[6 * 8] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
char version_data[9];
util_assert(cca != NULL, "Internal error: cca is NULL");
memset(rule_array, 0, sizeof(rule_array));
memcpy(rule_array, "STATCCA ", 8);
rule_array_count = 1;
cca->dll_CSUACFQ(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&verb_data_length, NULL);
pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
"return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
memcpy(version_data, rule_array+3*8, 8);
version_data[8] = '\0';
pr_verbose(verbose, "CCA firmware version string: %s", version_data);
if (sscanf((char *)version_data, "%u.%u.%uz", &version->ver,
&version->rel, &version->mod) != 3) {
warnx("CCA formware version is invalid: %s", version_data);
return -EINVAL;
}
return 0;
}
/**
* Selects the specified APQN to be used for the CCA host library.
*
* @param[in] cca the CCA library structure
* @param[in] card the card number
* @param[in] domain the domain number
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error. -ENOTSUP is
* returned when the serialnr sysfs attribute is not available,
* because the zcrypt kernel module is on an older level. -ENODEV is
* returned if the APQN is not available.
*/
int select_cca_adapter(struct cca_lib *cca, int card, int domain, bool verbose)
{
unsigned int adapters, adapter;
char adapter_serialnr[9];
char apqn_serialnr[9];
char temp[10];
int rc, found = 0;
util_assert(cca != NULL, "Internal error: cca is NULL");
pr_verbose(verbose, "Select %02x.%04x for the CCA host library", card,
domain);
rc = sysfs_get_serialnr(card, apqn_serialnr, verbose);
if (rc != 0) {
pr_verbose(verbose, "Failed to get the serial number: %s",
strerror(-rc));
return rc;
}
sprintf(temp, "%u", domain);
if (setenv(CCA_DOMAIN_ENVAR, temp, 1) != 0) {
rc = -errno;
pr_verbose(verbose, "Failed to set the %s environment variable:"
" %s", CCA_DOMAIN_ENVAR, strerror(-rc));
return rc;
}
unsetenv(CCA_ADAPTER_ENVAR);
/*
* Unload and reload the CCA host library so that it recognizes the
* changed CSU_DEFAULT_DOMAIN environment variable value.
*/
if (cca->lib_csulcca != NULL)
dlclose(cca->lib_csulcca);
memset(cca, 0, sizeof(struct cca_lib));
rc = load_cca_library(cca, verbose);
if (rc != 0)
return rc;
rc = get_number_of_cca_adapters(cca, &adapters, verbose);
if (rc != 0)
return rc;
/* Disable the AUTOSELECT option */
rc = deallocate_cca_adapter(cca, 0, verbose);
if (rc != 0)
return rc;
for (adapter = 1; adapter <= adapters; adapter++) {
rc = allocate_cca_adapter(cca, adapter, verbose);
if (rc != 0)
return rc;
rc = get_cca_adapter_serialnr(cca, adapter_serialnr, verbose);
if (rc == 0) {
if (memcmp(apqn_serialnr, adapter_serialnr, 8) == 0) {
found = 1;
break;
}
}
rc = deallocate_cca_adapter(cca, adapter, verbose);
if (rc != 0)
return rc;
}
if (!found)
return -ENODEV;
pr_verbose(verbose, "Selected adapter %u (CRP%02d)", adapter, adapter);
return 0;
}
struct find_mkvp_info {
u64 mkvp;
unsigned int flags;
bool found;
int card;
int domain;
bool verbose;
};
static int find_mkvp(int card, int domain, void *handler_data)
{
struct find_mkvp_info *info = (struct find_mkvp_info *)handler_data;
struct mk_info mk_info;
bool found = false;
int rc;
rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
if (rc == -ENODEV)
return 0;
if (rc != 0)
return rc;
if (info->flags & FLAG_SEL_CCA_MATCH_CUR_MKVP)
if (mk_info.cur_mk.mk_state == MK_STATE_VALID &&
mk_info.cur_mk.mkvp == info->mkvp)
found = true;
if (info->flags & FLAG_SEL_CCA_MATCH_OLD_MKVP)
if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
mk_info.old_mk.mkvp == info->mkvp)
found = true;
if (info->flags & FLAG_SEL_CCA_NEW_MUST_BE_SET)
if (mk_info.new_mk.mk_state != MK_STATE_FULL)
found = false;
if (found) {
info->card = card;
info->domain = domain;
info->found = true;
pr_verbose(info->verbose, "%02x.%04x has the desired mkvp%s",
card, domain,
info->flags & FLAG_SEL_CCA_NEW_MUST_BE_SET ?
" and NEW MK set" : "");
return 1;
}
return 0;
}
/**
* Selects an APQN to be used for the CCA host library that has the specified
* master key verification pattern
*
* @param[in] cca the CCA library structure
* @param[in] mkvp the master key verification pattern to search for
* @param[in] apqns a comma separated list of APQNs. If NULL is specified,
* or an empty string, then all online CCA APQNs are
* checked.
* @param[in] flags Flags that control the MKVM matching and NEW register
* checking. Multiple flags can be combined.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error. -ENOTSUP is
* returned when the serialnr sysfs attribute is not available,
* because the zcrypt kernel module is on an older level. -ENODEV is
* returned if no APQN is available with the desired mkvp.
*/
int select_cca_adapter_by_mkvp(struct cca_lib *cca, u64 mkvp, const char *apqns,
unsigned int flags, bool verbose)
{
struct find_mkvp_info info;
int rc;
util_assert(cca != NULL, "Internal error: cca is NULL");
pr_verbose(verbose, "Select mkvp %016llx in APQNs %s for the CCA host "
"library", mkvp, apqns == 0 ? "ANY" : apqns);
info.mkvp = mkvp;
info.flags = flags;
info.found = false;
info.card = 0;
info.domain = 0;
info.verbose = verbose;
rc = handle_apqns(apqns, find_mkvp, &info, verbose);
if (rc < 0)
return rc;
if (!info.found)
return -ENODEV;
rc = select_cca_adapter(cca, info.card, info.domain, verbose);
return rc;
}
void print_msg_for_cca_envvars(const char *key_name)
{
char *msg;
util_asprintf(&msg, "WARNING: You must set environment variables "
"%s and %s to the desired card and domain that is "
"set up with the AES master key used by this %s. "
"%s specifies the domain as decimal number. %s "
"specifies the adapter number as 'CRPnn', where "
"'nn' is the adapter number. See the CCA "
"documentation for more details.\n",
CCA_DOMAIN_ENVAR, CCA_ADAPTER_ENVAR, key_name,
CCA_DOMAIN_ENVAR, CCA_ADAPTER_ENVAR);
util_print_indented(msg, 0);
free(msg);
}
/*
* Convert a secure key of type CCA-AESDATA into a secure key of type
* CCA-AESCIPHER.
*
* @param[in] cca the CCA library structure
* @param[in] input_key the secure key to convert
* @param[in] input_key_size the size of the secure key to convert
* @param[in] output_key buffer for the converted secure key
* @param[in/out] output_key_size on input: size of the output buffer.
* on exit: size of the converted secure key
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error.
*/
int convert_aes_data_to_cipher_key(struct cca_lib *cca,
u8 *input_key, unsigned int input_key_size,
u8 *output_key,
unsigned int *output_key_size,
bool verbose)
{
long input_token_size, output_token_size, zero = 0;
long exit_data_len = 0, rule_array_count = 0;
unsigned char *input_token, *output_token;
unsigned char rule_array[8 * 2] = { 0, };
unsigned char null_token[64] = { 0, };
long null_token_len = sizeof(null_token);
unsigned char exit_data[4] = { 0, };
struct aescipherkeytoken *cipherkey;
long return_code, reason_code;
struct cca_version version;
unsigned char buffer[800];
int rc;
util_assert(cca != NULL, "Internal error: cca is NULL");
util_assert(input_key != NULL, "Internal error: input_key is NULL");
util_assert(output_key != NULL, "Internal error: output_key is NULL");
util_assert(output_key_size != NULL,
"Internal error: output_key_size is NULL");
if (is_cca_aes_cipher_key(input_key, input_key_size)) {
warnx("Invalid key-type specified");
return -EINVAL;
}
if (*output_key_size < (is_xts_key(input_key, input_key_size) ?
2 * AESCIPHER_KEY_SIZE : AESCIPHER_KEY_SIZE))
return -EINVAL;
/*
* We need a CCA firmware version 6.3.27 or later to support
* conversion of secure keys that are exportable to CPACF protected keys
*/
rc = get_cca_adapter_version(cca, &version, verbose);
if (rc != 0)
return rc;
if (version.ver < 6 ||
(version.ver == 6 && version.rel < 3) ||
(version.ver == 6 && version.rel < 3 && version.mod < 27)) {
util_print_indented("The used CCA firmware version does not "
"support converting a secure key that can "
"be used with the PAES cipher. The "
"required CCA firmware version is 6.3.27 "
"or later. For the supported environments "
"and updates, see: " CCA_WEB_PAGE, 0);
return -ENOTSUP;
}
input_token = input_key;
input_token_size = AESDATA_KEY_SIZE;
output_token = buffer;
output_token_size = sizeof(buffer);
memset(buffer, 0, sizeof(buffer));
memcpy(rule_array, "AES ", 8);
memcpy(rule_array + 8, "REFORMAT", 8);
rule_array_count = 2;
cca->dll_CSNBKTR2(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&input_token_size, input_token,
&null_token_len, null_token,
&zero, NULL,
&output_token_size, output_token);
pr_verbose(verbose, "CSNBKTR2 (Key Translate2) "
"returned: return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
pr_verbose(verbose, "output_token_size: %lu", output_token_size);
if (output_token_size > (long)AESCIPHER_KEY_SIZE) {
pr_verbose(verbose, "Output key token too large");
return -EINVAL;
}
/*
* Check if the converted key allows export to CPACF protected key.
* If not, then the CCA host library or firmware code level is too low.
*/
cipherkey = (struct aescipherkeytoken *)buffer;
if ((cipherkey->kmf1 & 0x0800) == 0) {
util_print_indented("The used CCA firmware version does not "
"support converting a secure key that can "
"be used with the PAES cipher. The "
"required CCA firmware version is 6.3.27 "
"or later. For the supported environments "
"and updates, see: " CCA_WEB_PAGE, 0);
return -ENOTSUP;
}
memset(output_key, 0, *output_key_size);
memcpy(output_key, buffer, output_token_size);
*output_key_size = AESCIPHER_KEY_SIZE;
if (is_xts_key(input_key, input_key_size)) {
input_token = input_key + AESDATA_KEY_SIZE;
input_token_size = AESDATA_KEY_SIZE;
output_token = buffer;
output_token_size = sizeof(buffer);
memset(buffer, 0, sizeof(buffer));
cca->dll_CSNBKTR2(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&input_token_size, input_token,
&null_token_len, null_token,
&zero, NULL,
&output_token_size, output_token);
pr_verbose(verbose, "CSNBKTR2 (Key Translate2) "
"returned: return_code: %ld, reason_code: %ld",
return_code, reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
pr_verbose(verbose, "output_token_size: %lu",
output_token_size);
if (output_token_size > (long)AESCIPHER_KEY_SIZE) {
pr_verbose(verbose, "Output key token too large");
return -EINVAL;
}
memcpy(output_key + AESCIPHER_KEY_SIZE, buffer,
output_token_size);
*output_key_size += AESCIPHER_KEY_SIZE;
}
return 0;
}
/*
* Restrict the exportability of an AES CIPHER key. It restricts export by means
* of NOEX-AES, NOEX-DES, NOEX-RSA, NOEX-SYM, NOEXUASY, NOEXAASY, NOEX-RAW
* keywords.
* When this function is called with an AES DATA key, it does nothing and
* returns 0. AES DATA keys can not be export restricted.
*
* @param[in] cca the CCA library structure
* @param[in] secure_key the secure key to restrict
* @param[in] secure_key_size the size of the secure key to restrict
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error.
*/
int restrict_key_export(struct cca_lib *cca, u8 *secure_key,
unsigned int secure_key_size, bool verbose)
{
struct aescipherkeytoken *cipherkey =
(struct aescipherkeytoken *)secure_key;
long exit_data_len = 0, rule_array_count = 0;
unsigned char rule_array[8 * 8] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
long token_length, zero = 0;
util_assert(cca != NULL, "Internal error: cca is NULL");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
if (!is_cca_aes_cipher_key(secure_key, secure_key_size))
return 0;
memcpy(rule_array, "AES ", 8);
memcpy(rule_array + 8, "NOEX-AES", 8);
memcpy(rule_array + 16, "NOEX-DES", 8);
memcpy(rule_array + 24, "NOEX-RSA", 8);
memcpy(rule_array + 32, "NOEX-SYM", 8);
memcpy(rule_array + 40, "NOEXUASY", 8);
memcpy(rule_array + 48, "NOEXAASY", 8);
memcpy(rule_array + 56, "NOEX-RAW", 8);
rule_array_count = 8;
token_length = cipherkey->length;
cca->dll_CSNBRKA(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&token_length, (unsigned char *)secure_key,
&zero, NULL, &zero, NULL, &zero, NULL);
pr_verbose(verbose, "CSNBRKA (Restrict Key Attribute) "
"returned: return_code: %ld, reason_code: %ld", return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
if (is_xts_key(secure_key, secure_key_size)) {
cipherkey = (struct aescipherkeytoken *)(secure_key +
AESCIPHER_KEY_SIZE);
token_length = cipherkey->length;
cca->dll_CSNBRKA(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
&token_length, (unsigned char *)cipherkey,
&zero, NULL, &zero, NULL, &zero, NULL);
pr_verbose(verbose, "CSNBRKA (Restrict Key Attribute) "
"returned: return_code: %ld, reason_code: %ld",
return_code, reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
}
return 0;
}

146
zkey/cca.h Normal file
View File

@@ -0,0 +1,146 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* This header file defines the interface to the CCA host library.
*
* Copyright IBM Corp. 2019
*
* 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 CCA_H
#define CCA_H
#include "lib/zt_common.h"
#define METHOD_OLD_TO_CURRENT "RTCMK "
#define METHOD_CURRENT_TO_NEW "RTNMK "
typedef void (*t_CSNBKTC)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
unsigned char *key_identifier);
typedef void (*t_CSNBKTC2)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
long *key_identifier_length,
unsigned char *key_identifier);
typedef void (*t_CSUACFV)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *version_data_length,
unsigned char *version_data);
typedef void (*t_CSUACFQ)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
long *verb_data_length,
unsigned char *verb_data);
typedef void (*t_CSUACRA)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
long *ressource_name_length,
unsigned char *ressource_name);
typedef void (*t_CSUACRD)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
long *ressource_name_length,
unsigned char *ressource_name);
typedef void (*t_CSNBKTR2)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
long *input_key_token_length,
unsigned char *input_key_token,
long *input_KEK_key_identifier_length,
unsigned char *input_KEK_key_identifier,
long *output_KEK_key_identifier_length,
unsigned char *output_KEK_key_identifier,
long *output_key_token_length,
unsigned char *output_key_token);
typedef void (*t_CSNBRKA)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
long *key_identifier_length,
unsigned char *key_identifier,
long *ey_encrypting_key_identifier_length,
unsigned char *ey_encrypting_key_identifier,
long *opt_parameter1_length,
unsigned char *opt_parameter1,
long *opt_parameter2_length,
unsigned char *opt_parameter2);
struct cca_version {
unsigned int ver;
unsigned int rel;
unsigned int mod;
};
struct cca_lib {
void *lib_csulcca;
t_CSNBKTC dll_CSNBKTC;
t_CSNBKTC2 dll_CSNBKTC2;
t_CSUACFV dll_CSUACFV;
t_CSUACFQ dll_CSUACFQ;
t_CSUACRA dll_CSUACRA;
t_CSUACRD dll_CSUACRD;
t_CSNBKTR2 dll_CSNBKTR2;
t_CSNBRKA dll_CSNBRKA;
struct cca_version version;
};
int load_cca_library(struct cca_lib *cca, bool verbose);
int key_token_change(struct cca_lib *cca,
u8 *secure_key, unsigned int secure_key_size,
char *method, bool verbose);
int select_cca_adapter(struct cca_lib *cca, int card, int domain, bool verbose);
#define FLAG_SEL_CCA_MATCH_CUR_MKVP 0x01
#define FLAG_SEL_CCA_MATCH_OLD_MKVP 0x02
#define FLAG_SEL_CCA_NEW_MUST_BE_SET 0x80
int select_cca_adapter_by_mkvp(struct cca_lib *cca, u64 mkvp, const char *apqns,
unsigned int flags, bool verbose);
void print_msg_for_cca_envvars(const char *key_name);
int convert_aes_data_to_cipher_key(struct cca_lib *cca,
u8 *input_key, unsigned int input_key_size,
u8 *output_key,
unsigned int *output_key_size,
bool verbose);
int restrict_key_export(struct cca_lib *cca, u8 *secure_key,
unsigned int secure_key_size, bool verbose);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@
#include <stdbool.h>
#include "cca.h"
#include "pkey.h"
struct keystore {
@@ -31,12 +32,13 @@ 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,
int pkey_fd);
const char *key_type, int pkey_fd);
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);
const char *import_file, const char *volume_type,
struct cca_lib *cca);
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
@@ -54,7 +56,7 @@ int keystore_reencipher_key(struct keystore *keystore, const char *name_filter,
const char *apqn_filter,
bool from_old, bool to_new, bool inplace,
bool staged, bool complete, int pkey_fd,
t_CSNBKTC dll_CSNBKTC);
struct cca_lib *cca);
int keystore_copy_key(struct keystore *keystore, const char *name,
const char *newname, const char *volumes);
@@ -67,7 +69,7 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
int keystore_list_keys(struct keystore *keystore, const char *name_filter,
const char *volume_filter, const char *apqn_filter,
const char *volume_type);
const char *volume_type, const char *key_type);
int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter,
bool execute, const char *volume_type,
@@ -79,6 +81,10 @@ int keystore_crypttab(struct keystore *keystore, const char *volume_filter,
const char *volume_type, const char *keyfile,
size_t keyfile_offset, size_t keyfile_size, size_t tries);
int keystore_convert_key(struct keystore *keystore, const char *name,
const char *key_type, bool noapqncheck, bool quiet,
int pkey_fd, struct cca_lib *cca);
void keystore_free(struct keystore *keystore);

File diff suppressed because it is too large Load Diff

View File

@@ -18,10 +18,23 @@
/*
* Definitions for the /dev/pkey kernel module interface
*/
struct secaeskeytoken {
u8 type; /* 0x01 for internal key token */
struct tokenheader {
u8 type;
u8 res0[3];
u8 version; /* should be 0x04 */
u8 version;
u8 res1[3];
} __packed;
#define TOKEN_TYPE_NON_CCA 0x00
#define TOKEN_TYPE_CCA_INTERNAL 0x01
#define TOKEN_VERSION_AESDATA 0x04
#define TOKEN_VERSION_AESCIPHER 0x05
struct aesdatakeytoken {
u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */
u8 res0[3];
u8 version; /* should be TOKEN_VERSION_AESDATA (0x04) */
u8 res1[1];
u8 flag; /* key flags */
u8 res2[1];
@@ -33,22 +46,60 @@ struct secaeskeytoken {
u8 tvv[4]; /* token validation value */
} __packed;
#define SECURE_KEY_SIZE sizeof(struct secaeskeytoken)
struct aescipherkeytoken {
u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */
u8 res0;
u16 length; /* length of token */
u8 version; /* should be TOKEN_VERSION_CIPHER (0x05) */
u8 res1[3];
u8 kms; /* key material state, should be 0x03 */
u8 kvptype; /* key verification pattern type */
u8 kvp[16]; /* key verification pattern */
u8 kwm; /* key wrapping method, should be 0x02 */
u8 kwh; /* key wrapping hash algorithm */
u8 pfv; /* payload format version, should be 0x00*/
u8 res2;
u8 adv; /* associated data section version */
u8 res3;
u16 adl; /* associated data length */
u8 kll; /* length of optional key label */
u8 eadl; /* extended associated data length */
u8 uadl; /* user associated data length */
u8 res4;
u16 pl; /* payload bit length */
u8 res5;
u8 at; /* algorithm type, should be 0x02 (AES) */
u16 kt; /* key type, should be 0x001 (CIPHER) */
u8 kufc; /* key usage field count */
u16 kuf1; /* key usage field 1 */
u16 kuf2; /* key usage field 2 */
u8 kmfc; /* key management field count */
u16 kmf1; /* key management field 1 */
u16 kmf2; /* key management field 2 */
u16 kmf3; /* key management field 3 */
u8 varpart[80]; /* variable part */
} __packed;
#define AESDATA_KEY_SIZE sizeof(struct aesdatakeytoken)
#define AESCIPHER_KEY_SIZE sizeof(struct aescipherkeytoken)
#define MAX_SECURE_KEY_SIZE MAX(AESDATA_KEY_SIZE, AESCIPHER_KEY_SIZE)
#define MIN_SECURE_KEY_SIZE MIN(AESDATA_KEY_SIZE, AESCIPHER_KEY_SIZE)
struct pkey_seckey {
u8 seckey[SECURE_KEY_SIZE]; /* the secure key blob */
u8 seckey[AESDATA_KEY_SIZE]; /* the secure key blob */
};
struct pkey_clrkey {
u8 clrkey[32]; /* 16, 24, or 32 byte clear key value */
};
#define PKEY_IOCTL_MAGIC 'p'
#define AUTOSELECT 0xFFFF
#define PKEYDEVICE "/dev/pkey"
#define PKEY_KEYTYPE_AES_128 1
#define PKEY_KEYTYPE_AES_192 2
#define PKEY_KEYTYPE_AES_256 3
#define PKEY_IOCTL_MAGIC 'p'
#define AUTOSELECT 0xFFFF
#define PKEYDEVICE "/dev/pkey"
#define PKEY_KEYTYPE_AES_128 1
#define PKEY_KEYTYPE_AES_192 2
#define PKEY_KEYTYPE_AES_256 3
struct pkey_genseck {
u16 cardnr; /* in: card to use or FFFF for any */
@@ -82,34 +133,114 @@ struct pkey_verifykey {
#define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
#define METHOD_OLD_TO_CURRENT "RTCMK "
#define METHOD_CURRENT_TO_NEW "RTNMK "
enum pkey_key_type {
PKEY_TYPE_CCA_DATA = (u32) 1,
PKEY_TYPE_CCA_CIPHER = (u32) 2,
};
typedef void (*t_CSNBKTC)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
unsigned char *key_identifier);
enum pkey_key_size {
PKEY_SIZE_AES_128 = (u32) 128,
PKEY_SIZE_AES_192 = (u32) 192,
PKEY_SIZE_AES_256 = (u32) 256,
PKEY_SIZE_UNKNOWN = (u32) 0xFFFFFFFF,
};
#define PKEY_FLAGS_MATCH_CUR_MKVP 0x00000002
#define PKEY_FLAGS_MATCH_ALT_MKVP 0x00000004
#define PKEY_KEYGEN_XPRT_SYM 0x00008000
#define PKEY_KEYGEN_XPRT_UASY 0x00004000
#define PKEY_KEYGEN_XPRT_AASY 0x00002000
#define PKEY_KEYGEN_XPRT_RAW 0x00001000
#define PKEY_KEYGEN_XPRT_CPAC 0x00000800
#define PKEY_KEYGEN_XPRT_DES 0x00000080
#define PKEY_KEYGEN_XPRT_AES 0x00000040
#define PKEY_KEYGEN_XPRT_RSA 0x00000008
struct pkey_apqn {
u16 card;
u16 domain;
};
struct pkey_genseck2 {
struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */
u32 apqn_entries; /* in: # of apqn target list entries */
enum pkey_key_type type; /* in: key type to generate */
enum pkey_key_size size; /* in: key size to generate */
u32 keygenflags; /* in: key generation flags */
u8 *key; /* in: pointer to key blob buffer */
u32 keylen; /* in: available key blob buffer size */
/* out: actual key blob size */
};
#define PKEY_GENSECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x11, struct pkey_genseck2)
struct pkey_clr2seck2 {
struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */
u32 apqn_entries; /* in: # of apqn target list entries */
enum pkey_key_type type; /* in: key type to generate */
enum pkey_key_size size; /* in: key size to generate */
u32 keygenflags; /* in: key generation flags */
struct pkey_clrkey clrkey; /* in: the clear key value */
u8 *key; /* in: pointer to key blob buffer */
u32 keylen; /* in: available key blob buffer size */
/* out: actual key blob size */
};
#define PKEY_CLR2SECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x12, struct pkey_clr2seck2)
struct pkey_verifykey2 {
u8 *key; /* in: pointer to key blob */
u32 keylen; /* in: key blob size */
u16 cardnr; /* in/out: card number */
u16 domain; /* in/out: domain number */
enum pkey_key_type type; /* out: the key type */
enum pkey_key_size size; /* out: the key size */
u32 flags; /* out: additional key info flags */
};
#define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2)
struct pkey_apqns4key {
u8 *key; /* in: pointer to key blob */
u32 keylen; /* in: key blob size */
u32 flags; /* in: match controlling flags */
struct pkey_apqn *apqns; /* in/out: ptr to list of apqn targets*/
u32 apqn_entries; /* in: max # of apqn entries in list */
/* out: # apqns stored into the list */
};
#define PKEY_APQNS4K _IOWR(PKEY_IOCTL_MAGIC, 0x1B, struct pkey_apqns4key)
struct pkey_apqns4keytype {
enum pkey_key_type type; /* in: key type */
u8 cur_mkvp[32]; /* in: current mkvp */
u8 alt_mkvp[32]; /* in: alternate mkvp */
u32 flags; /* in: match controlling flags */
struct pkey_apqn *apqns; /* in/out: ptr to list of apqn targets*/
u32 apqn_entries; /* in: max # of apqn entries in list */
/* out: # apqns stored into the list */
};
#define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype)
#define KEY_TYPE_CCA_AESDATA "CCA-AESDATA"
#define KEY_TYPE_CCA_AESCIPHER "CCA-AESCIPHER"
#define PAES_BLOCK_SIZE 16
#define ENC_ZERO_LEN (2 * PAES_BLOCK_SIZE)
#define VERIFICATION_PATTERN_LEN (2 * ENC_ZERO_LEN + 1)
int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose);
int open_pkey_device(bool verbose);
int generate_secure_key_random(int pkey_fd, const char *keyfile,
size_t keybits, bool xts, u16 card, u16 domain,
bool verbose);
size_t keybits, bool xts, const char *key_type,
const char **apqns, bool verbose);
int generate_secure_key_clear(int pkey_fd, const char *keyfile,
size_t keybits, bool xts,
const char *clearkeyfile,
u16 card, u16 domain,
bool verbose);
const char *clearkeyfile, const char *key_type,
const char **apqns, bool verbose);
u8 *read_secure_key(const char *keyfile, size_t *secure_key_size,
bool verbose);
@@ -120,13 +251,20 @@ int write_secure_key(const char *keyfile, const u8 *secure_key,
int validate_secure_key(int pkey_fd,
u8 *secure_key, size_t secure_key_size,
size_t *clear_key_bitsize, int *is_old_mk,
bool verbose);
const char **apqns, bool verbose);
int key_token_change(t_CSNBKTC dll_CSNBKTC,
u8 *secure_key, unsigned int secure_key_size,
char *method, bool verbose);
int generate_key_verification_pattern(const char *key, size_t key_size,
int generate_key_verification_pattern(const u8 *key, size_t key_size,
char *vp, size_t vp_len, bool verbose);
int get_master_key_verification_pattern(const u8 *key, size_t key_size,
u64 *mkvp, bool verbose);
bool is_cca_aes_data_key(const u8 *key, size_t key_size);
bool is_cca_aes_cipher_key(const u8 *key, size_t key_size);
bool is_xts_key(const u8 *key, size_t key_size);
int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize);
const char *get_key_type(const u8 *key, size_t key_size);
int get_min_card_level_for_keytype(const char *key_type);
int check_aes_cipher_key(const u8 *key, size_t key_size);
#endif

819
zkey/utils.c Normal file
View File

@@ -0,0 +1,819 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* Copyright IBM Corp. 2019
*
* 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 <dirent.h>
#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_path.h"
#include "lib/util_file.h"
#include "lib/util_scandir.h"
#include "lib/util_libc.h"
#include "lib/util_rec.h"
#include "lib/util_base.h"
#include "utils.h"
#include "properties.h"
#define pr_verbose(verbose, fmt...) do { \
if (verbose) \
warnx(fmt); \
} while (0)
/**
* Checks if the specified card is of type CCA and is online
*
* @param[in] card card number
*
* @returns 1 if its a CCA card and is online, 0 if offline and -1 if its
* not a CCA card.
*/
int sysfs_is_card_online(int card)
{
long int online;
char *dev_path;
char type[20];
int rc = 1;
dev_path = util_path_sysfs("bus/ap/devices/card%02x", card);
if (!util_path_is_dir(dev_path)) {
rc = 0;
goto out;
}
if (util_file_read_l(&online, 10, "%s/online", dev_path) != 0) {
rc = 0;
goto out;
}
if (online == 0) {
rc = 0;
goto out;
}
if (util_file_read_line(type, sizeof(type), "%s/type", dev_path) != 0) {
rc = 0;
goto out;
}
if (strncmp(type, "CEX", 3) != 0 || strlen(type) < 5) {
rc = 0;
goto out;
}
if (type[4] != 'C') {
rc = -1;
goto out;
}
out:
free(dev_path);
return rc;
}
/**
* Checks if the specified APQN is of type CCA and is online
*
* @param[in] card card number
* @param[in] domain the domain
*
* @returns 1 if its a CCA card and is online, 0 if offline and -1 if its
* not a CCA card.
*/
int sysfs_is_apqn_online(int card, int domain)
{
long int online;
char *dev_path;
int rc = 1;
rc = sysfs_is_card_online(card);
if (rc != 1)
return rc;
dev_path = util_path_sysfs("bus/ap/devices/card%02x/%02x.%04x", card,
card, domain);
if (!util_path_is_dir(dev_path)) {
rc = 0;
goto out;
}
if (util_file_read_l(&online, 10, "%s/online", dev_path) != 0) {
rc = 0;
goto out;
}
if (online == 0) {
rc = 0;
goto out;
}
out:
free(dev_path);
return rc;
}
/**
* Returns the level of the card. For a CEX3C 3 is returned, for a CEX4C 4,
* and so on.
*
* @param[in] card card number
*
* @returns The card level, or -1 of the level can not be determined.
*/
int sysfs_get_card_level(int card)
{
char *dev_path;
char type[20];
int rc;
dev_path = util_path_sysfs("bus/ap/devices/card%02x", card);
if (!util_path_is_dir(dev_path)) {
rc = -1;
goto out;
}
if (util_file_read_line(type, sizeof(type), "%s/type", dev_path) != 0) {
rc = -1;
goto out;
}
if (strncmp(type, "CEX", 3) != 0 || strlen(type) < 5) {
rc = -1;
goto out;
}
if (type[4] != 'C') {
rc = -1;
goto out;
}
if (type[3] < '1' || type[3] > '9') {
rc = -1;
goto out;
}
rc = type[3] - '0';
out:
free(dev_path);
return rc;
}
/**
* Gets the 8 character ASCII serial number string of an card from the sysfs.
*
* @param[in] card card number
* @param[out] serialnr Result buffer
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 if the serial number was returned. -ENODEV if the APQN is not
* available, or is not a CCA card. -ENOTSUP if the serialnr sysfs
* attribute is not available, because the zcrypt kernel module is
* on an older level.
*/
int sysfs_get_serialnr(int card, char serialnr[9], bool verbose)
{
char *dev_path;
int rc = 0;
if (serialnr == NULL)
return -EINVAL;
if (sysfs_is_card_online(card) != 1)
return -ENODEV;
dev_path = util_path_sysfs("bus/ap/devices/card%02x", card);
if (!util_path_is_dir(dev_path)) {
rc = -ENODEV;
goto out;
}
if (util_file_read_line(serialnr, 9, "%s/serialnr", dev_path) != 0) {
rc = -ENOTSUP;
goto out;
}
if (strlen(serialnr) == 0) {
rc = -ENODEV;
goto out;
}
pr_verbose(verbose, "Serial number of %02x: %s", card, serialnr);
out:
if (rc != 0)
pr_verbose(verbose, "Failed to get serial number for "
"%02x: %s", card, strerror(-rc));
free(dev_path);
return rc;
}
static int parse_mk_info(char *line, struct mk_info *mk_info)
{
struct mk_info_reg *mk_reg;
char *save;
char *tok;
tok = strtok_r(line, " ", &save);
if (tok == NULL)
return -EIO;
if (strcasecmp(tok, "AES") != 0)
return 0;
tok = strtok_r(NULL, " ", &save);
if (tok == NULL)
return -EIO;
if (strcasecmp(tok, "NEW:") == 0)
mk_reg = &mk_info->new_mk;
else if (strcasecmp(tok, "CUR:") == 0)
mk_reg = &mk_info->cur_mk;
else if (strcasecmp(tok, "OLD:") == 0)
mk_reg = &mk_info->old_mk;
else
return -EIO;
tok = strtok_r(NULL, " ", &save);
if (tok == NULL)
return -EIO;
if (strcasecmp(tok, "empty") == 0)
mk_reg->mk_state = MK_STATE_EMPTY;
else if (strcasecmp(tok, "partial") == 0)
mk_reg->mk_state = MK_STATE_PARTIAL;
else if (strcasecmp(tok, "full") == 0)
mk_reg->mk_state = MK_STATE_FULL;
else if (strcasecmp(tok, "valid") == 0)
mk_reg->mk_state = MK_STATE_VALID;
else if (strcasecmp(tok, "invalid") == 0)
mk_reg->mk_state = MK_STATE_INVALID;
else
mk_reg->mk_state = MK_STATE_UNKNOWN;
tok = strtok_r(NULL, " ", &save);
if (tok == NULL)
return -EIO;
if (sscanf(tok, "%llx", &mk_reg->mkvp) != 1)
return -EIO;
return 0;
}
/**
* Gets the master key states and verification patterns of an APQN from the
* sysfs.
*
* @param[in] card card number
* @param[in] domain the domain
* @param[out] mk_info structure is filled on return with master key infos
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 if the master key info was returned. -ENODEV if the APQN is not
* available, or is not a CCA card. -ENOTSUP if the mkvps sysfs
* attribute is not available, because the zcrypt kernel module is
* on an older level.
*/
int sysfs_get_mkvps(int card, int domain, struct mk_info *mk_info, bool verbose)
{
char *dev_path;
char *p, *end;
char buf[100];
int rc = 0;
FILE *fp;
if (mk_info == NULL)
return -EINVAL;
memset(mk_info, 0, sizeof(struct mk_info));
mk_info->new_mk.mk_state = MK_STATE_UNKNOWN;
mk_info->cur_mk.mk_state = MK_STATE_UNKNOWN;
mk_info->old_mk.mk_state = MK_STATE_UNKNOWN;
if (sysfs_is_apqn_online(card, domain) != 1)
return -ENODEV;
dev_path = util_path_sysfs("bus/ap/devices/card%02x/%02x.%04x/mkvps",
card, card, domain);
if (!util_path_is_reg_file(dev_path)) {
rc = -ENOTSUP;
goto out;
}
fp = fopen(dev_path, "r");
if (fp == NULL) {
rc = -ENOTSUP;
goto out;
}
/*
* Expected contents:
* AES NEW: <new_mk_state> <new_mk_mkvp>
* AES CUR: <cur_mk_state> <cur_mk_mkvp>
* AES OLD: <old_mk_state> <old_mk_mkvp>
* with
* <new_mk_state>: 'empty' or 'partial' or 'full'
* <cur_mk_state>, <old_mk_state>: 'valid' or 'invalid'
* <new_mk_mkvp>, <cur_mk_mkvp>, <old_mk_mkvp:
* 8 byte hex string with leading 0x
*/
while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
end = memchr(buf, '\n', sizeof(buf));
if (end)
*end = 0;
else
buf[sizeof(buf) - 1] = 0;
pr_verbose(verbose, "mkvp for %02x.%04x: %s", card, domain,
buf);
rc = parse_mk_info(buf, mk_info);
if (rc != 0)
break;
}
fclose(fp);
if (mk_info->new_mk.mk_state == MK_STATE_UNKNOWN &&
mk_info->cur_mk.mk_state == MK_STATE_UNKNOWN &&
mk_info->old_mk.mk_state == MK_STATE_UNKNOWN)
rc = -EIO;
out:
if (rc != 0)
pr_verbose(verbose, "Failed to get mkvps for %02x.%04x: %s",
card, domain, strerror(-rc));
free(dev_path);
return rc;
}
static int scan_for_domains(int card, apqn_handler_t handler,
void *handler_data, bool verbose)
{
struct dirent **namelist;
char fname[290];
int i, n, domain, rc = 0;
sprintf(fname, "/sys/devices/ap/card%02x/", card);
n = util_scandir(&namelist, alphasort, fname,
"[0-9a-fA-F]+\\.[0-9a-fA-F]+");
if (n < 0)
return -EIO;
for (i = 0; i < n; i++) {
if (sscanf(namelist[i]->d_name, "%x.%x", &card, &domain) != 2)
continue;
pr_verbose(verbose, "Found %02x.%04x", card, domain);
if (sysfs_is_apqn_online(card, domain) != 1) {
pr_verbose(verbose, "APQN %02x.%04x is offline or not "
"CCA", card, domain);
continue;
}
rc = handler(card, domain, handler_data);
if (rc != 0)
break;
}
util_scandir_free(namelist, n);
return rc;
}
static int scan_for_apqns(apqn_handler_t handler, void *handler_data,
bool verbose)
{
struct dirent **namelist;
int i, n, card, rc = 0;
if (handler == NULL)
return -EINVAL;
n = util_scandir(&namelist, alphasort, "/sys/devices/ap/",
"card[0-9a-fA-F]+");
if (n < 0)
return -EIO;
for (i = 0; i < n; i++) {
if (sscanf(namelist[i]->d_name, "card%x", &card) != 1)
continue;
pr_verbose(verbose, "Found card %02x", card);
if (sysfs_is_card_online(card) != 1) {
pr_verbose(verbose, "Card %02x is offline or not CCA",
card);
continue;
}
rc = scan_for_domains(card, handler, handler_data, verbose);
if (rc != 0)
break;
}
util_scandir_free(namelist, n);
return rc;
}
/**
* Calls the handler for all APQNs specified in the apqns parameter, or of this
* is NULL, for all online CCA APQNs found in sysfs. In case sysfs is inspected,
* the cards and domains are processed in alphabetical order.
*
* @param[in] apqns a comma separated list of APQNs. If NULL is specified,
* or an empty string, then all online CCA APQNs are
* handled.
* @param[in] handler a handler function that is called for each APQN
* @param[in] handler_data private data that is passed to the handler
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error
*/
int handle_apqns(const char *apqns, apqn_handler_t handler, void *handler_data,
bool verbose)
{
int card, domain;
char *copy, *tok;
char *save;
int rc = 0;
if (apqns == NULL || (apqns != NULL && strlen(apqns) == 0)) {
rc = scan_for_apqns(handler, handler_data, verbose);
} else {
copy = util_strdup(apqns);
tok = strtok_r(copy, ",", &save);
while (tok != NULL) {
if (sscanf(tok, "%x.%x", &card, &domain) != 2) {
warnx("the APQN '%s' is not valid",
tok);
rc = -EINVAL;
break;
}
pr_verbose(verbose, "Specified: %02x.%04x", card,
domain);
rc = handler(card, domain, handler_data);
if (rc != 0)
break;
tok = strtok_r(NULL, ",", &save);
}
free(copy);
}
return rc;
}
struct print_apqn_info {
struct util_rec *rec;
bool verbose;
};
static int print_apqn_mk_info(int card, int domain, void *handler_data)
{
struct print_apqn_info *info = (struct print_apqn_info *)handler_data;
struct mk_info mk_info;
int rc, level;
rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
if (rc == -ENOTSUP)
return rc;
level = sysfs_get_card_level(card);
util_rec_set(info->rec, "APQN", "%02x.%04x", card, domain);
if (rc == 0) {
if (mk_info.new_mk.mk_state == MK_STATE_FULL)
util_rec_set(info->rec, "NEW", "%016llx",
mk_info.new_mk.mkvp);
else if (mk_info.new_mk.mk_state == MK_STATE_PARTIAL)
util_rec_set(info->rec, "NEW", "partially loaded");
else
util_rec_set(info->rec, "NEW", "-");
if (mk_info.cur_mk.mk_state == MK_STATE_VALID)
util_rec_set(info->rec, "CUR", "%016llx",
mk_info.cur_mk.mkvp);
else
util_rec_set(info->rec, "CUR", "-");
if (mk_info.old_mk.mk_state == MK_STATE_VALID)
util_rec_set(info->rec, "OLD", "%016llx",
mk_info.old_mk.mkvp);
else
util_rec_set(info->rec, "OLD", "-");
} else {
util_rec_set(info->rec, "NEW", "?");
util_rec_set(info->rec, "CUR", "?");
util_rec_set(info->rec, "OLD", "?");
}
if (level > 0)
util_rec_set(info->rec, "TYPE", "CEX%dC", level);
else
util_rec_set(info->rec, "TYPE", "?");
util_rec_print(info->rec);
return 0;
}
/**
* Prints master key information for all specified APQNs
*
* @param[in] apqns a comma separated list of APQNs. If NULL is specified,
* or an empty string, then all online CCA APQNs are
* printed.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error. -ENOTSUP is
* returned when the mkvps sysfs attribute is not available, because
* the zcrypt kernel module is on an older level.
*/
int print_mk_info(const char *apqns, bool verbose)
{
struct print_apqn_info info;
int rc;
info.verbose = verbose;
info.rec = util_rec_new_wide("-");
util_rec_def(info.rec, "APQN", UTIL_REC_ALIGN_LEFT, 11, "CARD.DOMAIN");
util_rec_def(info.rec, "NEW", UTIL_REC_ALIGN_LEFT, 16, "NEW MK");
util_rec_def(info.rec, "CUR", UTIL_REC_ALIGN_LEFT, 16, "CURRENT MK");
util_rec_def(info.rec, "OLD", UTIL_REC_ALIGN_LEFT, 16, "OLD MK");
util_rec_def(info.rec, "TYPE", UTIL_REC_ALIGN_LEFT, 6, "TYPE");
util_rec_print_hdr(info.rec);
rc = handle_apqns(apqns, print_apqn_mk_info, &info, verbose);
util_rec_free(info.rec);
return rc;
}
struct cross_check_info {
u64 mkvp;
u64 new_mkvp;
bool key_mkvp;
int min_level;
u32 num_cur_match;
u32 num_old_match;
u32 num_new_match;
bool mismatch;
bool print_mks;
int num_checked;
bool verbose;
};
static int cross_check_mk_info(int card, int domain, void *handler_data)
{
struct cross_check_info *info = (struct cross_check_info *)handler_data;
struct mk_info mk_info;
char temp[200];
int rc, level;
rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
if (rc == -ENODEV) {
info->print_mks = 1;
printf("WARNING: APQN %02x.%04x: Not available or not of "
"type CCA\n", card, domain);
return 0;
}
if (rc != 0)
return rc;
info->num_checked++;
if (info->min_level >= 0) {
level = sysfs_get_card_level(card);
if (level < info->min_level) {
info->print_mks = 1;
info->mismatch = 1;
sprintf(temp, "WARNING: APQN %02x.%04x: The card level "
"is less than CEX%dC.", card, domain,
info->min_level);
util_print_indented(temp, 0);
}
}
if (mk_info.new_mk.mk_state == MK_STATE_PARTIAL) {
info->print_mks = 1;
sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
"register is only partially loaded.", card, domain);
util_print_indented(temp, 0);
}
if (info->new_mkvp == 0 &&
mk_info.new_mk.mk_state == MK_STATE_FULL)
info->new_mkvp = mk_info.new_mk.mkvp;
if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
mk_info.new_mk.mkvp != info->new_mkvp) {
info->print_mks = 1;
sprintf(temp, "WARNING: APQN %02x.%04x: The NEW master key "
"register contains a different master key than "
"the NEW register of other APQNs.", card,
domain);
util_print_indented(temp, 0);
}
if (mk_info.cur_mk.mk_state != MK_STATE_VALID) {
info->print_mks = 1;
info->mismatch = 1;
printf("WARNING: APQN %02x.%04x: No master key is set.\n", card,
domain);
return 0;
}
if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
mk_info.old_mk.mkvp == mk_info.cur_mk.mkvp) {
info->print_mks = 1;
sprintf(temp, "INFO: APQN %02x.%04x: The OLD master key "
"register contains the same master key as the CURRENT "
"master key register.", card, domain);
util_print_indented(temp, 0);
}
if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
mk_info.new_mk.mkvp == mk_info.cur_mk.mkvp) {
info->print_mks = 1;
sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
"register contains the same master key as the CURRENT "
"master key register.", card, domain);
util_print_indented(temp, 0);
}
if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
mk_info.old_mk.mk_state == MK_STATE_VALID &&
mk_info.new_mk.mkvp == mk_info.old_mk.mkvp) {
info->print_mks = 1;
sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
"register contains the same master key as the OLD "
"master key register.", card, domain);
util_print_indented(temp, 0);
}
if (info->mkvp == 0)
info->mkvp = mk_info.cur_mk.mkvp;
if (info->key_mkvp) {
if (mk_info.cur_mk.mk_state == MK_STATE_VALID &&
mk_info.cur_mk.mkvp == info->mkvp)
info->num_cur_match++;
if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
mk_info.old_mk.mkvp == info->mkvp)
info->num_old_match++;
if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
mk_info.new_mk.mkvp == info->mkvp)
info->num_new_match++;
}
if (mk_info.cur_mk.mkvp != info->mkvp) {
if (info->key_mkvp) {
if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
mk_info.old_mk.mkvp == info->mkvp) {
info->print_mks = 1;
sprintf(temp, "INFO: APQN %02x.%04x: The master"
" key has been changed to a new "
"master key, but the secure key has "
"not yet been re-enciphered.", card,
domain);
util_print_indented(temp, 0);
} else if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
mk_info.new_mk.mkvp == info->mkvp) {
info->print_mks = 1;
sprintf(temp, "INFO: APQN %02x.%04x: The master"
" key has been changed but is not "
"yet been set (made active).", card,
domain);
util_print_indented(temp, 0);
} else {
info->print_mks = 1;
info->mismatch = 1;
sprintf(temp, "WARNING: APQN %02x.%04x: The "
"CURRENT master key register contains "
"a master key that is different from "
"the one used by the secure key.", card,
domain);
util_print_indented(temp, 0);
}
} else {
info->print_mks = 1;
info->mismatch = 1;
}
}
return 0;
}
/**
* Cross checks the master key information for all specified APQNs. It checks
* if all specified APQNs have the same current master key, and if it matches
* the master key specified by the mkvp parameter (optional). If not, it prints
* out an information message about the APQNs that have a different master key.
*
* @param[in] apqns a comma separated list of APQNs. If NULL is specified,
* or an empty string, then all online CCA APQNs are
* checked.
* @param[in] mkvp The master key verification pattern of a secure key.
* If this is all zero, then the master keys are not
* matched against it.
* @param[in] min_level The minimum card level required. If min_level is -1 then
* the card level is not checked.
* @param[in] print_mks if true, then a the full master key info of all
* specified APQns is printed, in case of a mismatch.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error. -ENODEV is
* returned if at least one APQN has a mismatching master key.
* -ENOTSUP is returned when the mkvps sysfs attribute is not
* available, because the zcrypt kernel module is on an older level.
*/
int cross_check_apqns(const char *apqns, u64 mkvp, int min_level,
bool print_mks, bool verbose)
{
struct cross_check_info info;
char temp[200];
int rc;
memset(&info, 0, sizeof(info));
info.key_mkvp = mkvp != 0;
info.mkvp = mkvp;
info.min_level = min_level;
info.verbose = verbose;
pr_verbose(verbose, "Cross checking APQNs with mkvp 0x%016llx and "
"min-level %d: %s", mkvp, min_level,
apqns != NULL ? apqns : "ANY");
rc = handle_apqns(apqns, cross_check_mk_info, &info, verbose);
if (rc != 0)
return rc;
if (info.mismatch) {
if (info.key_mkvp)
printf("WARNING: Not all APQNs have the correct master "
"key (%016llx).\n", mkvp);
else
printf("WARNING: Not all APQNs have the same master "
"key.\n");
rc = -ENODEV;
}
if (info.num_checked == 0) {
printf("WARNING: None of the APQNs is available or of "
"type CCA\n");
rc = -ENODEV;
}
if (info.num_old_match > 0 && info.num_new_match > 0) {
sprintf(temp, "WARNING: On %u APQNs the OLD master key "
"register contains the master key use by the secure "
"key, and on %u APQNs the NEW master key register "
"contains the master key use by the secure key.",
info.num_old_match, info.num_new_match);
util_print_indented(temp, 0);
info.print_mks = 1;
rc = -ENODEV;
}
if (print_mks && info.print_mks) {
printf("\n");
print_mk_info(apqns, verbose);
printf("\n");
}
return rc;
}
/*
* Prompts for yes or no. Returns true if 'y' or 'yes' was entered.
*
* @param[in] verbose if true, verbose messages are printed
*
* @returns true if 'y' or 'yes' was entered (case insensitive). Returns false
* otherwise.
*/
bool prompt_for_yes(bool verbose)
{
char str[20];
if (fgets(str, sizeof(str), stdin) == NULL)
return false;
if (str[strlen(str) - 1] == '\n')
str[strlen(str) - 1] = '\0';
pr_verbose(verbose, "Prompt reply: '%s'", str);
if (strcasecmp(str, "y") == 0 || strcasecmp(str, "yes") == 0)
return true;
return false;
}

58
zkey/utils.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* This header file defines the interface to the CCA host library.
*
* Copyright IBM Corp. 2019
*
* 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 UTILS_H
#define UTILS_H
#include "lib/zt_common.h"
int sysfs_is_card_online(int card);
int sysfs_is_apqn_online(int card, int domain);
int sysfs_get_card_level(int card);
int sysfs_get_serialnr(int card, char serialnr[9], bool verbose);
#define MK_STATE_EMPTY 0
#define MK_STATE_PARTIAL 1
#define MK_STATE_FULL 2
#define MK_STATE_VALID 3
#define MK_STATE_INVALID 4
#define MK_STATE_UNKNOWN -1
struct mk_info_reg {
int mk_state;
u64 mkvp;
};
struct mk_info {
struct mk_info_reg new_mk;
struct mk_info_reg cur_mk;
struct mk_info_reg old_mk;
};
int sysfs_get_mkvps(int card, int domain, struct mk_info *mk_info,
bool verbose);
typedef int(*apqn_handler_t) (int card, int domain, void *handler_data);
int handle_apqns(const char *apqns, apqn_handler_t handler, void *handler_data,
bool verbose);
int print_mk_info(const char *apqns, bool verbose);
int cross_check_apqns(const char *apqns, u64 mkvp, int min_level,
bool print_mks, bool verbose);
bool prompt_for_yes(bool verbose);
#endif

View File

@@ -91,6 +91,8 @@ behave in the same way as with \fBcryptsetup\fP.
.B zkey\-cryptsetup
.BR reencipher | re
.I device
.RB [ \-\-to\-new | \-N ]
.RB [ \-\-from\-old | \-O ]
.RB [ \-\-staged | \-s ]
.RB [ \-\-in\-place | \-i ]
.RB [ \-\-complete | \-c ]
@@ -128,17 +130,36 @@ register can still be used until the master key is changed again.
The \fBNEW\fP register contains the new master key to be set.
The master key in the \fBNEW\fP register cannot be used until it is made
the current master key. You can pro-actively re-encipher a secure key with the
\fBNEW\fP master key before this key is made the \fBCURRENT\fP key.
\fBNEW\fP master key before this key is made the \fBCURRENT\fP key. Use the
.B \-\-to-new
option to do this.
.RE
.PP
\fBzkey\-cryptsetup\fP automatically detects whether the secure volume key
is currently enciphered with the master key in the \fBOLD\fP register or with
the master key in the \fBCURRENT\fP register. If currently enciphered with the
master key in the \fBOLD\fP register, it is re-enciphered with the master key
in the \fBCURRENT\fP register. If it is currently enciphered with the master
key in the \fBCURRENT\fP register, it is re-enciphered with the master key in
the \fBNEW\fP register. If for this case the \fBNEW\fP register does not
contain a valid master key, then the re-encipher operation fails.
Use the
.B \-\-from\-old
option to re-encipher a secure volume key that is currently enciphered with
the master key in the \fBOLD\fP register with the master key in the
\fBCURRENT\fP register.
.PP
.PP
If both the
.B \-\-from-old
and
.B \-\-to-new
options are specified, a secure volume key that is currently enciphered
with the master key in the \fBOLD\fP register is re-enciphered with the
master key in the \fBNEW\fP register.
.RE
.PP
If both options are omitted, \fBzkey-cryptsetup\fP automatically detects whether
the secure volume key is currently enciphered with the master key in the
\fBOLD\fP register or with the master key in the \fBCURRENT\fP register.
If currently enciphered with the master key in the \fBOLD\fP register,
it is re-enciphered with the master key in the \fBCURRENT\fP register.
If it is currently enciphered with the master key in the \fBCURRENT\fP
register, it is re-enciphered with the master key in the \fBNEW\fP register.
If for this case the \fBNEW\fP register does not contain a valid master key,
then the re-encipher operation fails.
.PP
Re-enciphering a secure volume key of a volume encrypted with
\fBLUKS2\fP and the \fBpaes\fP cipher can be performed \fBin-place\fP, or in
@@ -326,6 +347,16 @@ relevance.
.
.SS "Options for the reencipher command"
.TP
.BR \-N ", " \-\-to\-new
Re-enciphers a secure volume key in the LUKS2 header that is currently
enciphered with the master key in the CURRENT register with the master key in
the NEW register.
.TP
.BR \-O ", " \-\-from\-old
Re-enciphers a secure volume key in the LUKS2 header that is currently
enciphered with the master key in the OLD register with the master key in the
CURRENT register.
.TP
.BR \-i ", " \-\-in-place
Forces an in-place re-enciphering of a secure volume key in the LUKS2
header. This option immediately replaces the secure volume key in the LUKS2

View File

@@ -34,6 +34,7 @@
#include "misc.h"
#include "pkey.h"
#include "cca.h"
/* Detect if cryptsetup 2.1 or later is available */
#ifdef CRYPT_LOG_DEBUG_JSON
@@ -94,6 +95,8 @@ static struct zkey_cryptsetup_globals {
long long keyfile_offset;
long long keyfile_size;
long long tries;
bool tonew;
bool fromold;
bool complete;
bool inplace;
bool staged;
@@ -101,8 +104,7 @@ static struct zkey_cryptsetup_globals {
bool batch_mode;
bool debug;
bool verbose;
void *lib_csulcca;
t_CSNBKTC dll_CSNBKTC;
struct cca_lib cca;
int pkey_fd;
struct crypt_device *cd;
} g = {
@@ -162,6 +164,22 @@ static struct util_opt opt_vec[] = {
.desc = "OPTIONS",
.command = COMMAND_REENCIPHER,
},
{
.option = {"to-new", 0, NULL, 'N'},
.desc = "Re-enciphers a secure volume key in the LUKS2 header "
"that is currently enciphered with the master key in "
"the CURRENT register with the master key in the NEW "
"register",
.command = COMMAND_REENCIPHER,
},
{
.option = {"from-old", 0, NULL, 'O'},
.desc = "Re-enciphers a secure volume key in the LUKS2 header "
"that is currently enciphered with the master key in "
"the OLD register with the master key in the CURRENT "
"register",
.command = COMMAND_REENCIPHER,
},
{
.option = {"staged", 0, NULL, 's'},
.desc = "Forces that the re-enciphering of a secure volume "
@@ -1311,22 +1329,25 @@ static int activate_unbound_keyslot(int token, int keyslot, const char *key,
return rc;
}
static int check_keysize_and_cipher_mode(size_t keysize)
static int check_keysize_and_cipher_mode(const u8 *key, size_t keysize)
{
if (keysize == 0) {
if (keysize < MIN_SECURE_KEY_SIZE ||
keysize > 2 * MAX_SECURE_KEY_SIZE) {
warnx("Invalid volume key size");
return -EINVAL;
}
if (strncmp(crypt_get_cipher_mode(g.cd), "xts", 3) == 0) {
if (keysize != 2 * SECURE_KEY_SIZE) {
if (keysize < 2 * MIN_SECURE_KEY_SIZE ||
(key != NULL && !is_xts_key(key, keysize))) {
warnx("The volume key size %lu is not valid for the "
"cipher mode '%s'", keysize,
crypt_get_cipher_mode(g.cd));
return -EINVAL;
}
} else {
if (keysize != SECURE_KEY_SIZE) {
if (keysize > MAX_SECURE_KEY_SIZE ||
(key != NULL && is_xts_key(key, keysize))) {
warnx("The volume key size %lu is not valid for the "
"cipher mode '%s'", keysize,
crypt_get_cipher_mode(g.cd));
@@ -1359,7 +1380,7 @@ static int open_keyslot(int keyslot, char **key, size_t *keysize,
vkeysize = crypt_get_volume_key_size(g.cd);
pr_verbose("Volume key size: %lu", vkeysize);
rc = check_keysize_and_cipher_mode(vkeysize);
rc = check_keysize_and_cipher_mode(NULL, vkeysize);
if (rc != 0)
return rc;
@@ -1471,7 +1492,7 @@ static int validate_keyslot(int keyslot, char **key, size_t *keysize,
keyslot = rc;
rc = validate_secure_key(g.pkey_fd, (u8 *)vkey, vkeysize, clear_keysize,
&is_old, g.verbose);
&is_old, NULL, g.verbose);
if (rc != 0) {
if (invalid_msg != NULL)
warnx("%s", invalid_msg);
@@ -1514,10 +1535,12 @@ static int reencipher_prepare(int token)
char *password = NULL;
size_t password_len;
char *key = NULL;
int selected = 1;
size_t keysize;
int is_old_mk;
char *prompt;
char *msg;
u64 mkvp;
int rc;
if (token >= 0) {
@@ -1551,7 +1574,7 @@ static int reencipher_prepare(int token)
if (rc != 0)
goto out;
rc = generate_key_verification_pattern(key, keysize,
rc = generate_key_verification_pattern((u8 *)key, keysize,
reenc_tok.verification_pattern,
sizeof(reenc_tok.verification_pattern),
g.verbose);
@@ -1570,25 +1593,97 @@ static int reencipher_prepare(int token)
if (rc < 0)
goto out;
util_asprintf(&msg, "The secure volume key of device '%s' is "
"enciphered with the %s CCA master key and is being "
"re-enciphered with the %s CCA master key.",
g.pos_arg, is_old_mk ? "OLD" : "CURRENT",
is_old_mk ? "CURRENT" : "NEW");
util_print_indented(msg, 0);
free(msg);
if (!g.fromold && !g.tonew) {
/* Autodetect reencipher mode */
if (is_old_mk) {
g.fromold = 1;
util_asprintf(&msg, "The secure volume key of device "
"'%s' is enciphered with the OLD CCA "
"master key and is being re-enciphered "
"with the CURRENT CCA master key.",
g.pos_arg);
util_print_indented(msg, 0);
free(msg);
} else {
g.tonew = 1;
util_asprintf(&msg, "The secure volume key of device "
"'%s' is enciphered with the CURRENT CCA "
"master key and is being re-enciphered "
"with the NEW CCA master key.",
g.pos_arg);
util_print_indented(msg, 0);
free(msg);
}
}
rc = key_token_change(g.dll_CSNBKTC, (u8 *)key, keysize,
is_old_mk ? METHOD_OLD_TO_CURRENT :
METHOD_CURRENT_TO_NEW,
g.verbose);
rc = get_master_key_verification_pattern((u8 *)key, keysize, &mkvp,
g.verbose);
if (rc != 0) {
warnx("Failed to re-encipher the secure volume key of device "
"'%s'", g.pos_arg);
rc = -EINVAL;
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
goto out;
}
if (g.fromold) {
rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
FLAG_SEL_CCA_MATCH_OLD_MKVP,
g.verbose);
if (rc == -ENOTSUP) {
rc = 0;
selected = 0;
}
if (rc != 0) {
util_print_indented("No APQN found that is suitable "
"for re-enciphering the secure AES "
"volume key from the OLD to the "
"CURRENT CCA master key.", 0);
goto out;
}
rc = key_token_change(&g.cca, (u8 *)key, keysize,
METHOD_OLD_TO_CURRENT, g.verbose);
if (rc != 0) {
warnx("Failed to re-encipher the secure volume key of "
"device '%s'\n", g.pos_arg);
if (!selected)
print_msg_for_cca_envvars(
"secure AES volume key");
rc = -EINVAL;
goto out;
}
}
if (g.tonew) {
rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
FLAG_SEL_CCA_MATCH_CUR_MKVP |
FLAG_SEL_CCA_NEW_MUST_BE_SET,
g.verbose);
if (rc == -ENOTSUP) {
rc = 0;
selected = 0;
}
if (rc != 0) {
util_print_indented("No APQN found that is suitable "
"for re-enciphering the secure AES "
"volume key from the CURRENT to "
"the NEW CCA master key.", 0);
goto out;
}
rc = key_token_change(&g.cca, (u8 *)key, keysize,
METHOD_CURRENT_TO_NEW,
g.verbose);
if (rc != 0) {
warnx("Failed to re-encipher the secure volume key of "
"device '%s'\n", g.pos_arg);
if (!selected)
print_msg_for_cca_envvars(
"secure AES volume key");
rc = -EINVAL;
goto out;
}
}
rc = crypt_keyslot_add_by_key(g.cd, CRYPT_ANY_SLOT, key, keysize,
password, password_len,
CRYPT_VOLUME_KEY_NO_SEGMENT);
@@ -1651,10 +1746,12 @@ static int reencipher_complete(int token)
char *password = NULL;
size_t password_len;
char *key = NULL;
int selected = 1;
size_t keysize;
int is_old_mk;
char *prompt;
char *msg;
u64 mkvp;
int rc;
rc = get_reencipher_token(g.cd, token, &tok, true);
@@ -1700,11 +1797,38 @@ static int reencipher_complete(int token)
goto out;
}
rc = key_token_change(g.dll_CSNBKTC, (u8 *)key, keysize,
rc = get_master_key_verification_pattern((u8 *)key, keysize,
&mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification "
"pattern: %s",
strerror(-rc));
goto out;
}
rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
FLAG_SEL_CCA_MATCH_OLD_MKVP,
g.verbose);
if (rc == -ENOTSUP) {
rc = 0;
selected = 0;
}
if (rc != 0) {
util_print_indented("No APQN found that is suitable "
"for re-enciphering the secure AES "
"volume key from the OLD to the "
"CURRENT CCA master key.", 0);
goto out;
}
rc = key_token_change(&g.cca, (u8 *)key, keysize,
METHOD_OLD_TO_CURRENT, g.verbose);
if (rc != 0) {
warnx("Failed to re-encipher the secure volume key for "
"device '%s'", g.pos_arg);
"device '%s'\n", g.pos_arg);
if (!selected)
print_msg_for_cca_envvars(
"secure AES volume key");
rc = -EINVAL;
goto out;
}
@@ -1730,8 +1854,8 @@ static int reencipher_complete(int token)
}
rc = generate_key_verification_pattern(key, keysize, vp, sizeof(vp),
g.verbose);
rc = generate_key_verification_pattern((u8 *)key, keysize, vp,
sizeof(vp), g.verbose);
if (rc != 0) {
warnx("Failed to generate the verification pattern: %s",
strerror(-rc));
@@ -1834,6 +1958,7 @@ static int command_validate(void)
char *prompt;
char *msg;
int token;
u64 mkvp;
int rc;
util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg);
@@ -1847,7 +1972,7 @@ static int command_validate(void)
goto out;
rc = validate_secure_key(g.pkey_fd, (u8 *)key, keysize, &clear_keysize,
&is_old_mk, g.verbose);
&is_old_mk, NULL, g.verbose);
is_valid = (rc == 0);
token = find_token(g.cd, PAES_REENC_TOKEN_NAME);
@@ -1864,18 +1989,29 @@ static int command_validate(void)
vp_tok_avail = 1;
}
rc = get_master_key_verification_pattern((u8 *)key, keysize,
&mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
goto out;
}
printf("Validation of secure volume key of device '%s':\n", g.pos_arg);
printf(" Status: %s\n", is_valid ? "Valid" : "Invalid");
printf(" Secure key size: %lu bytes\n", keysize);
printf(" XTS type key: %s\n",
keysize > SECURE_KEY_SIZE ? "Yes" : "No");
is_xts_key((u8 *)key, keysize) ? "Yes" : "No");
printf(" Key type: %s\n",
get_key_type((u8 *)key, keysize));
if (is_valid) {
printf(" Clear key size: %lu bits\n", clear_keysize);
printf(" Enciphered with: %s CCA master key\n",
is_old_mk ? "OLD" : "CURRENT");
printf(" Enciphered with: %s CCA master key (MKVP: "
"%016llx)\n", is_old_mk ? "OLD" : "CURRENT", mkvp);
} else {
printf(" Clear key size: (unknown)\n");
printf(" Enciphered with: (unknown)\n");
printf(" Enciphered with: (unknown, MKVP: %016llx)\n",
mkvp);
}
if (vp_tok_avail)
print_verification_pattern(vp_tok.verification_pattern);
@@ -1943,7 +2079,7 @@ static int command_setvp(void)
token = find_token(g.cd, PAES_VP_TOKEN_NAME);
rc = generate_key_verification_pattern(key, keysize,
rc = generate_key_verification_pattern((const u8 *)key, keysize,
vp_tok.verification_pattern,
sizeof(vp_tok.verification_pattern),
g.verbose);
@@ -1998,12 +2134,12 @@ static int command_setkey(void)
if (newkey == NULL)
return EXIT_FAILURE;
rc = check_keysize_and_cipher_mode(newkey_size);
rc = check_keysize_and_cipher_mode(newkey, newkey_size);
if (rc != 0)
goto out;
rc = validate_secure_key(g.pkey_fd, newkey, newkey_size, NULL,
&is_old_mk, g.verbose);
&is_old_mk, NULL, g.verbose);
if (rc != 0) {
warnx("The secure key in file '%s' is not valid",
g.master_key_file);
@@ -2033,21 +2169,14 @@ static int command_setkey(void)
if (rc < 0)
goto out;
if (keysize != newkey_size) {
warnx("The secure key in file '%s' has an invalid size",
g.master_key_file);
rc = -EINVAL;
goto out;
}
if (memcmp(newkey, key, keysize) == 0) {
if (keysize == newkey_size && memcmp(newkey, key, keysize) == 0) {
warnx("The secure key in file '%s' is equal to the current "
"volume key, setkey is ignored", g.master_key_file);
rc = 0;
goto out;
}
rc = generate_key_verification_pattern((char *)newkey, newkey_size, vp,
rc = generate_key_verification_pattern(newkey, newkey_size, vp,
sizeof(vp), g.verbose);
if (rc != 0) {
warnx("Failed to generate the verification pattern: %s",
@@ -2206,6 +2335,12 @@ int main(int argc, char *argv[])
if (c == -1)
break;
switch (c) {
case 'N':
g.tonew = 1;
break;
case 'O':
g.fromold = 1;
break;
case 'c':
g.complete = 1;
break;
@@ -2288,8 +2423,7 @@ int main(int argc, char *argv[])
}
if (command->need_cca_library) {
rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC,
g.verbose);
rc = load_cca_library(&g.cca, g.verbose);
if (rc != 0) {
rc = EXIT_FAILURE;
goto out;
@@ -2331,8 +2465,8 @@ int main(int argc, char *argv[])
rc = command->function();
out:
if (g.lib_csulcca)
dlclose(g.lib_csulcca);
if (g.cca.lib_csulcca)
dlclose(g.cca.lib_csulcca);
if (g.pkey_fd >= 0)
close(g.pkey_fd);
if (g.cd)

View File

@@ -62,7 +62,8 @@ in size.
The \fBzkey\fP tool can operate in two modes. When argument
.I secure\-key\-file
is specified then it operates on the secure key contained in the specified file.
This applies to commands \fBgenerate\fP, \fBvalidate\fP, and \fBreencipher\fP.
This applies to commands \fBgenerate\fP, \fBvalidate\fP, \fBreencipher\fP, and
\fBconvert\fP.
When the
.B \-\-name
option is specified then it operates on a secure key contained in the secure
@@ -79,6 +80,8 @@ key repository.
.RB [ \-\-xts | \-x ]
.RB [ \-\-clearkey | \-c
.IR clear\-key\-file ]
.RB [ \-\-key-type | \-K
.IR type ]
.RB [ \-\-verbose | \-V ]
.
.PP
@@ -102,6 +105,8 @@ key repository.
.RB [ \-\-xts | \-x ]
.RB [ \-\-clearkey | \-c
.IR clear\-key\-file ]
.RB [ \-\-key-type | \-K
.IR type ]
.RB [ \-\-verbose | \-V ]
.PP
Use the
@@ -129,6 +134,15 @@ additional information can be associated with a secure key using the
, or the
.B \-\-sector-size
options.
.PP
You can generate different types of secure keys: \fBCCA-AESDATA\fP keys, and
\fBCCA-AESCIPHER\fP keys. Specify the type of the secure key using the
.B \-\-key\-type
option. The default key type is CCA-AESDATA.
.PP
.B Note:
Secure keys of type \fBCCA-AESCIPHER\fP require an IBM cryptographic
adapter in CCA coprocessor mode of version 6 or later, e.g. a CEX6C.
.
.SS "Validating secure AES keys"
.
@@ -336,6 +350,12 @@ additional information can be associated with a secure key using the
, or the
.B \-\-sector-size
options.
.PP
.B Note:
The \fBimport\fP command requires the CCA host library (libcsulcca.so)
to be installed when secure keys of type \fBCCA-AESCIPHER\fP are imported.
For the supported environments and downloads, see:
\fIhttp://www.ibm.com/security/cryptocards\fP
.
.SS "Export AES secure keys from the secure key repository"
.
@@ -368,6 +388,8 @@ The exported secure key also remains in the secure key repository.
.IR card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-volume-type | \-t
.IR type ]
.RB [ \-\-key-type | \-K
.IR type ]
.RB [ \-\-verbose | \-V ]
.
.PP
@@ -382,7 +404,7 @@ listed that are associated with the specified volume and device-mapper name.
.PP
The
.B list
command displays the attributes of the secure keys, such as key sizes,
command displays the attributes of the secure keys, such as key sizes, key type,
whether it is a secure key that can be used for the XTS cipher mode, the textual
description, associated cryptographic adapters (APQNs) and volumes, the
sector size, the key verification pattern, and timestamps for key creation, last
@@ -659,6 +681,72 @@ questions, you can specify the
option. These options are passed to the generated command(s) and behave in the
same way as with \fBcryptsetup\fP.
.
.SS "Convert existing AES secure keys from one key type to another type"
.
.B zkey
.BR convert | con
.I secure\-key\-file
.RB \-\-key-type | \-K
.IR type
.RB [ \-\-no\-apqn\-check ]
.RB [ \-\-force | \-F ]
.RB [ \-\-verbose | \-V ]
.
.PP
.B zkey
.BR convert | con
.B \-\-name | \-N
.IR key-name
.RB \-\-key-type | \-K
.IR type
.RB [ \-\-no\-apqn\-check ]
.RB [ \-\-force | \-F ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B convert
command to convert an existing secure key from one key type to another type.
You can convert secure keys of type CCA-AESDATA to type CCA-AESCIPHER only.
.B Note:
Secure keys converted to type \fBCCA-AESCIPHER\fP require an IBM cryptographic
adapter in CCA coprocessor mode of version 6 or later, e.g. a CEX6C.
The secure key can either be contained in a file in the file system, or in a
secure key repository. To convert a secure key contained in a file, specify
the file name with option \fIsecure\-key\-file\fP. To convert a secure key
contained in the secure key repository, specify the name of the key
that is to be converted using the
.B \-\-name
option. You cannot use wildcards. The convert command prompts for
a confirmation, unless you specify the
.B \-\-force
option.
.PP
.B Note:
Converting a secure key is irreversible!
When converting a secure key that is associated with one or multiple volumes,
a message informs you about the associated volumes. When the secure key is
converted, this might have an effect on these volumes.
.P
For volumes with volume type \fBplain\fP, you must adapt the crypttab entries
and change the key size parameter to \fBsize=<new-key-size-in-bits>\fP or run
command \fBzkey crypttab --volumes <device>\fP for each associated volume to
re-generate the crypttab entries.
.P
Associated volumes of type \fLUKS2\fP still contain the secure AES volume key of
the original type. To change the secure AES volume key in the LUKS2 header,
run command \fBzkey-cryptsetup setkey <device> --master-key-file
<converted-key>\fP for each associated volume.
.
.P
.B Note:
The \fBconvert\fP command requires the CCA host library (libcsulcca.so)
to be installed. The required CCA IBM cryptographic adapter firmware version
is 6.3.27 or later. For the supported environments and downloads, see:
\fIhttp://www.ibm.com/security/cryptocards\fP
.
.
.
.
@@ -728,6 +816,13 @@ 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 \-K ", " \-\-key-type\~\fItype\fP
Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP
and \fBCCA-AESCIPHER\fP. If this option is omitted, then a secure key of type
CCA-AESDATA is generated. Secure keys of type \fBCCA-AESCIPHER\fP require an
IBM cryptographic adapter in CCA coprocessor mode of version 6 or later, e.g.
a CEX6C.
.
.
.
@@ -907,6 +1002,11 @@ 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 \-K ", " \-\-key-type\~\fItype\fP
Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP
and \fBCCA-AESCIPHER\fP. Only keys with the specified key type are listed.
This option is only used for secure keys contained in the secure key repository.
.
.
.
@@ -1170,6 +1270,30 @@ cryptsetup command(s).
.
.
.
.SS "Options for the convert command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You cannot
use wildcards.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-K ", " \-\-key-type\~\fItype\fP
Specifies the key type to which the secure key shall be converted to.
Possible values are \fBCCA-AESCIPHER\fP. Secure keys of type \fBCCA-AESCIPHER\fP
require an IBM cryptographic adapter in CCA coprocessor mode of version 6 or
later, e.g. a CEX6C.
.TP
.BR \-\-no\-apqn\-check
Do not check if the associated APQNs are available and capable of converting
the secure key to type CCA-AESCIPHER.
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 convertion of a secure key. Use this option
to convert a secure key without prompting for a confirmation.
.
.
.
.SS "General options"
.TP
.BR \-V ", " \-\-verbose

View File

@@ -27,9 +27,11 @@
#include "lib/util_prg.h"
#include "lib/zt_common.h"
#include "cca.h"
#include "keystore.h"
#include "misc.h"
#include "pkey.h"
#include "utils.h"
/*
* Program configuration
@@ -71,6 +73,7 @@ static struct zkey_globals {
long int sector_size;
char *volume_type;
char *newname;
char *key_type;
bool run;
bool batch_mode;
char *keyfile;
@@ -80,8 +83,7 @@ static struct zkey_globals {
bool force;
bool open;
bool format;
void *lib_csulcca;
t_CSNBKTC dll_CSNBKTC;
struct cca_lib cca;
int pkey_fd;
struct keystore *keystore;
} g = {
@@ -104,6 +106,7 @@ static struct zkey_globals {
#define COMMAND_COPY "copy "
#define COMMAND_CRYPTTAB "crypttab"
#define COMMAND_CRYPTSETUP "cryptsetup"
#define COMMAND_CONVERT "convert"
#define ZKEY_COMMAND_MAX_LEN 10
@@ -161,7 +164,7 @@ static struct util_opt opt_vec[] = {
.desc = "Name of the secure AES key in the repository. If "
"option --name/-N is specified, then the generated "
"secure AES key is stored in the repository. Parameter "
"SECURE-KEY-FILE is not used when option --name/-M is "
"SECURE-KEY-FILE is not used when option --name/-N is "
"specified",
.command = COMMAND_GENERATE,
},
@@ -215,6 +218,15 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_GENERATE,
},
#endif
{
.option = { "key-type", required_argument, NULL, 'K'},
.argument = "type",
.desc = "The type of the key. Possible values are '"
KEY_TYPE_CCA_AESDATA"' and '"KEY_TYPE_CCA_AESCIPHER"'. "
"When this option is omitted, the default is '"
KEY_TYPE_CCA_AESDATA"'",
.command = COMMAND_GENERATE,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -431,6 +443,15 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_LIST,
},
#endif
{
.option = { "key-type", required_argument, NULL, 'K'},
.argument = "type",
.desc = "The type of the key. Possible values are '"
KEY_TYPE_CCA_AESDATA"' and '"KEY_TYPE_CCA_AESCIPHER"'. "
"Use this option to list all keys with the specified "
"key type.",
.command = COMMAND_LIST,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -744,6 +765,38 @@ static struct util_opt opt_vec[] = {
.flags = UTIL_OPT_FLAG_NOSHORT,
},
#endif
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
.desc = "OPTIONS",
.command = COMMAND_CONVERT,
},
{
.option = { "name", required_argument, NULL, 'N'},
.argument = "NAME",
.desc = "Name of the secure AES key in the repository that is "
"to be converted",
.command = COMMAND_CONVERT,
},
{
.option = { "key-type", required_argument, NULL, 'K'},
.argument = "type",
.desc = "The type of the key to convert the secure key to. "
"Possible values are '"KEY_TYPE_CCA_AESCIPHER"'. ",
.command = COMMAND_CONVERT,
},
{
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
.desc = "Do not check if the associated APQN(s) are available",
.command = COMMAND_CONVERT,
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = {"force", 0, NULL, 'F'},
.desc = "Do not prompt for a confirmation when converting a "
"key",
.command = COMMAND_CONVERT,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -792,6 +845,7 @@ static int command_rename(void);
static int command_copy(void);
static int command_crypttab(void);
static int command_cryptsetup(void);
static int command_convert(void);
static struct zkey_command zkey_commands[] = {
{
@@ -926,6 +980,21 @@ static struct zkey_command zkey_commands[] = {
.has_options = 1,
.need_keystore = 1,
},
{
.command = COMMAND_CONVERT,
.abbrev_len = 3,
.function = command_convert,
.need_cca_library = 1,
.need_pkey_device = 1,
.short_desc = "Convert a secure AES key",
.long_desc = "Convert an existing secure AES key that is "
"either contained in SECURE-KEY-FILE or is stored "
"in the repository from one key type to another "
"type.",
.has_options = 1,
.pos_arg = "[SECURE-KEY-FILE]",
.pos_arg_optional = 1,
},
{ .command = NULL }
};
@@ -1008,9 +1077,8 @@ static int command_generate_clear(void)
rc = generate_secure_key_clear(g.pkey_fd, g.pos_arg,
g.keybits, g.xts,
g.clearkeyfile,
AUTOSELECT, AUTOSELECT,
g.verbose);
g.clearkeyfile, g.key_type,
NULL, g.verbose);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1025,9 +1093,8 @@ static int command_generate_random(void)
int rc;
rc = generate_secure_key_random(g.pkey_fd, g.pos_arg,
g.keybits, g.xts,
AUTOSELECT, AUTOSELECT,
g.verbose);
g.keybits, g.xts, g.key_type,
NULL, g.verbose);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1047,7 +1114,7 @@ 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.pkey_fd);
g.volume_type, g.key_type, g.pkey_fd);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1060,6 +1127,8 @@ static int command_generate_repository(void)
*/
static int command_generate(void)
{
int rc;
if (g.pos_arg != NULL && g.name != NULL) {
warnx(" Option '--name|-N' is not valid for generating a key "
"outside of the repository");
@@ -1072,6 +1141,8 @@ static int command_generate(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.key_type == NULL)
g.key_type = KEY_TYPE_CCA_AESDATA;
if (g.name != NULL)
return command_generate_repository();
if (g.pos_arg != NULL) {
@@ -1100,6 +1171,16 @@ static int command_generate(void)
return EXIT_FAILURE;
}
rc = cross_check_apqns(NULL, 0,
get_min_card_level_for_keytype(g.key_type),
true, g.verbose);
if (rc == -EINVAL)
return EXIT_FAILURE;
if (rc != 0 && rc != -ENOTSUP) {
warnx("Your master key setup is improper");
return EXIT_FAILURE;
}
return g.clearkeyfile ? command_generate_clear()
: command_generate_random();
}
@@ -1117,7 +1198,9 @@ static int command_reencipher_file(void)
{
size_t secure_key_size;
int rc, is_old_mk;
int selected = 1;
u8 *secure_key;
u64 mkvp;
if (g.name != NULL) {
warnx("Option '--name|-N' is not valid for "
@@ -1156,13 +1239,22 @@ static int command_reencipher_file(void)
return EXIT_FAILURE;
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL,
&is_old_mk, g.verbose);
&is_old_mk, NULL, g.verbose);
if (rc != 0) {
warnx("The secure key in file '%s' is not valid", g.pos_arg);
rc = EXIT_FAILURE;
goto out;
}
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
&mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
rc = EXIT_FAILURE;
goto out;
}
if (!g.fromold && !g.tonew) {
/* Autodetect reencipher option */
if (is_old_mk) {
@@ -1194,13 +1286,28 @@ static int command_reencipher_file(void)
pr_verbose("Secure key will be re-enciphered from OLD to the "
"CURRENT CCA master key");
rc = key_token_change(g.dll_CSNBKTC,
secure_key, secure_key_size,
rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
FLAG_SEL_CCA_MATCH_OLD_MKVP,
g.verbose);
if (rc == -ENOTSUP) {
rc = 0;
selected = 0;
}
if (rc != 0) {
warnx("No APQN found that is suitable for "
"re-enciphering the secure AES volume key");
rc = EXIT_FAILURE;
goto out;
}
rc = key_token_change(&g.cca, secure_key, secure_key_size,
METHOD_OLD_TO_CURRENT,
g.verbose);
if (rc != 0) {
warnx("Re-encipher from OLD to CURRENT CCA "
"master key has failed");
"master key has failed\n");
if (!selected)
print_msg_for_cca_envvars("secure AES key");
rc = EXIT_FAILURE;
goto out;
}
@@ -1209,12 +1316,30 @@ static int command_reencipher_file(void)
pr_verbose("Secure key will be re-enciphered from CURRENT "
"to the NEW CCA master key");
rc = key_token_change(g.dll_CSNBKTC,
secure_key, secure_key_size,
rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
FLAG_SEL_CCA_MATCH_CUR_MKVP |
FLAG_SEL_CCA_NEW_MUST_BE_SET,
g.verbose);
if (rc == -ENOTSUP) {
rc = 0;
selected = 0;
}
if (rc != 0) {
util_print_indented("No APQN found that is suitable "
"for re-enciphering this secure "
"AES key and has the NEW master "
"key loaded", 0);
rc = EXIT_FAILURE;
goto out;
}
rc = key_token_change(&g.cca, secure_key, secure_key_size,
METHOD_CURRENT_TO_NEW, g.verbose);
if (rc != 0) {
warnx("Re-encipher from CURRENT to NEW CCA "
"master key has failed");
"master key has failed\n");
if (!selected)
print_msg_for_cca_envvars("secure AES key");
rc = EXIT_FAILURE;
goto out;
}
@@ -1270,7 +1395,7 @@ static int command_reencipher_repository(void)
rc = keystore_reencipher_key(g.keystore, g.name, g.apqns, g.fromold,
g.tonew, g.inplace, g.staged, g.complete,
g.pkey_fd, g.dll_CSNBKTC);
g.pkey_fd, &g.cca);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1302,6 +1427,7 @@ static int command_validate_file(void)
size_t clear_key_size;
u8 *secure_key;
int is_old_mk;
u64 mkvp;
int rc;
if (g.name != NULL) {
@@ -1329,14 +1455,14 @@ static int command_validate_file(void)
return EXIT_FAILURE;
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size,
&clear_key_size, &is_old_mk, g.verbose);
&clear_key_size, &is_old_mk, NULL, g.verbose);
if (rc != 0) {
warnx("The secure key in file '%s' is not valid", g.pos_arg);
rc = EXIT_FAILURE;
goto out;
}
rc = generate_key_verification_pattern((char *)secure_key,
rc = generate_key_verification_pattern(secure_key,
secure_key_size, vp, sizeof(vp),
g.verbose);
if (rc != 0) {
@@ -1348,19 +1474,42 @@ static int command_validate_file(void)
goto out;
}
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
&mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
rc = EXIT_FAILURE;
goto out;
}
printf("Validation of secure key in file '%s':\n", g.pos_arg);
printf(" Status: Valid\n");
printf(" Secure key size: %lu bytes\n", secure_key_size);
printf(" Key type: %s\n",
get_key_type(secure_key, secure_key_size));
printf(" Clear key size: %lu bits\n", clear_key_size);
printf(" XTS type key: %s\n",
secure_key_size > SECURE_KEY_SIZE ? "Yes" : "No");
printf(" Enciphered with: %s CCA master key\n",
is_old_mk ? "OLD" : "CURRENT");
is_xts_key(secure_key, secure_key_size) ? "Yes" : "No");
printf(" Enciphered with: %s CCA master key (MKVP: %016llx)\n",
is_old_mk ? "OLD" : "CURRENT", mkvp);
printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,
vp);
printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
&vp[VERIFICATION_PATTERN_LEN / 2]);
rc = cross_check_apqns(NULL, mkvp,
get_min_card_level_for_keytype(
get_key_type(secure_key, secure_key_size)),
true, g.verbose);
if (rc == -EINVAL)
return EXIT_FAILURE;
if (rc != 0 && rc != -ENOTSUP) {
warnx("Your master key setup is improper");
rc = EXIT_FAILURE;
goto out;
}
out:
free(secure_key);
return rc;
@@ -1422,7 +1571,7 @@ static int command_import(void)
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.pos_arg, g.volume_type, &g.cca);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1456,7 +1605,7 @@ static int command_list(void)
int rc;
rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns,
g.volume_type);
g.volume_type, g.key_type);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -1591,6 +1740,206 @@ static int command_cryptsetup(void)
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
* Command handler for 'convert'.
*
* Converts secure keys from one key type to another
*/
static int command_convert_file(void)
{
u8 output_key[2 * MAX_SECURE_KEY_SIZE];
unsigned int output_key_size;
size_t secure_key_size;
int rc, is_old_mk;
int selected = 1;
u8 *secure_key;
int min_level;
u64 mkvp;
if (g.name != NULL) {
warnx("Option '--name|-N' is not valid for "
"re-enciphering a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.noapqncheck) {
warnx("Option '--no-apqn-check' is not valid for "
"converting a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
min_level = get_min_card_level_for_keytype(g.key_type);
if (min_level < 0) {
warnx("Invalid key-type specified: %s", g.key_type);
return EXIT_FAILURE;
}
rc = cross_check_apqns(NULL, 0, min_level, true, g.verbose);
if (rc == -EINVAL)
return EXIT_FAILURE;
if (rc != 0 && rc != -ENOTSUP) {
warnx("Your master key setup is improper");
return EXIT_FAILURE;
}
/* Read the secure key to be re-enciphered */
secure_key = read_secure_key(g.pos_arg, &secure_key_size, g.verbose);
if (secure_key == NULL)
return EXIT_FAILURE;
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL,
&is_old_mk, NULL, g.verbose);
if (rc != 0) {
warnx("The secure key in file '%s' is not valid", g.pos_arg);
rc = EXIT_FAILURE;
goto out;
}
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
&mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
rc = EXIT_FAILURE;
goto out;
}
if (strcasecmp(get_key_type(secure_key, secure_key_size),
g.key_type) == 0) {
warnx("The secure key in file '%s' is already of type %s",
g.pos_arg, get_key_type(secure_key, secure_key_size));
rc = EXIT_FAILURE;
goto out;
}
if (is_cca_aes_data_key(secure_key, secure_key_size)) {
if (strcasecmp(g.key_type, KEY_TYPE_CCA_AESCIPHER) != 0) {
warnx("The secure key in file '%s' can not be "
"converted into type %s", g.pos_arg, g.key_type);
rc = EXIT_FAILURE;
goto out;
}
} else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
warnx("The secure key in file '%s' is already of type %s",
g.pos_arg, KEY_TYPE_CCA_AESCIPHER);
rc = EXIT_FAILURE;
goto out;
} else {
warnx("The secure key in file '%s' has an unsupported key type",
g.pos_arg);
rc = EXIT_FAILURE;
goto out;
}
rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
FLAG_SEL_CCA_MATCH_CUR_MKVP,
g.verbose);
if (rc == -ENOTSUP) {
rc = 0;
selected = 0;
}
if (rc != 0) {
warnx("No APQN found that is suitable for "
"converting the secure AES key in file '%s'", g.pos_arg);
rc = EXIT_FAILURE;
goto out;
}
if (!g.force) {
util_print_indented("ATTENTION: Converting a secure key is "
"irreversible, and might have an effect "
"on the volumes encrypted with it!", 0);
printf("%s: Convert key in file '%s' [y/N]? ",
program_invocation_short_name, g.pos_arg);
if (!prompt_for_yes(g.verbose)) {
warnx("Operation aborted");
rc = EXIT_FAILURE;
goto out;
}
}
memset(output_key, 0, sizeof(output_key));
output_key_size = sizeof(output_key);
rc = convert_aes_data_to_cipher_key(&g.cca, secure_key, secure_key_size,
output_key, &output_key_size,
g.verbose);
if (rc != 0) {
warnx("Converting the secure key from %s to %s has failed",
get_key_type(secure_key, secure_key_size), g.key_type);
if (!selected)
print_msg_for_cca_envvars("secure AES key");
rc = EXIT_FAILURE;
goto out;
}
rc = restrict_key_export(&g.cca, output_key, output_key_size,
g.verbose);
if (rc != 0) {
warnx("Export restricting the converted secure key has failed");
if (!selected)
print_msg_for_cca_envvars("secure AES key");
rc = EXIT_FAILURE;
goto out;
}
pr_verbose("Secure key was converted successfully");
/* Write the converted secure key */
rc = write_secure_key(g.outputfile ? g.outputfile : g.pos_arg,
output_key, output_key_size, g.verbose);
if (rc != 0)
rc = EXIT_FAILURE;
out:
free(secure_key);
return rc;
}
/*
* Command handler for 'convert in repository'.
*
* Converts secure keys from one key type to another
*/
static int command_convert_repository(void)
{
int rc;
if (g.name == NULL) {
misc_print_required_parm("--name/-N");
return EXIT_FAILURE;
}
rc = keystore_convert_key(g.keystore, g.name, g.key_type, g.noapqncheck,
g.force, g.pkey_fd, &g.cca);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
* Command handler for 'convert'.
*
* Converts secure keys from one key type to another
*/
static int command_convert(void)
{
if (g.key_type == NULL) {
misc_print_required_parm("--key-type/-K");
return EXIT_FAILURE;
}
if (strcasecmp(g.key_type, KEY_TYPE_CCA_AESCIPHER) != 0) {
warnx("Secure keys can only be converted into key type %s",
KEY_TYPE_CCA_AESCIPHER);
return EXIT_FAILURE;
}
if (g.pos_arg != NULL)
return command_convert_file();
else
return command_convert_repository();
return EXIT_SUCCESS;
}
/**
* Opens the keystore. The keystore directory is either the
* default directory or as specified in an environment variable
@@ -1777,6 +2126,9 @@ int main(int argc, char *argv[])
case 'r':
g.run = 1;
break;
case 'K':
g.key_type = optarg;
break;
case 'F':
g.force = 1;
break;
@@ -1867,8 +2219,7 @@ int main(int argc, char *argv[])
}
if (command->need_cca_library) {
rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC,
g.verbose);
rc = load_cca_library(&g.cca, g.verbose);
if (rc != 0) {
rc = EXIT_FAILURE;
goto out;
@@ -1887,8 +2238,8 @@ int main(int argc, char *argv[])
rc = command->function();
out:
if (g.lib_csulcca)
dlclose(g.lib_csulcca);
if (g.cca.lib_csulcca)
dlclose(g.cca.lib_csulcca);
if (g.pkey_fd >= 0)
close(g.pkey_fd);
if (g.keystore)