Compare commits

...

34 Commits

Author SHA1 Message Date
Jan Höppner
1bb9a9ec5b New release s390-tools-2.16.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 15:46:37 +01:00
Nikita Dubrovskii
4a3957fab5 zipl: fix reading 4k disk's geometry
On 4k SCSI disks zipl stores wrong values to 'scsi_mbr.program_table_pointer',
which makes system unbootable.
This happens in 'zipl/src/disk.c:656':

```
/* Convert file system block to physical */
*physical = mapped * phy_per_fs + subblock;
/* Add partition start */
*physical += info->geo.start;

```

So 'hd_geometry.start' should be adjusted before being used.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1918723
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/107
Signed-off-by: Nikita Dubrovskii <nikita@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Ingo Franzki
e506c94839 zkey-ekmfweb: Fix typos in messages
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Wenjia Zhang
dfd9f52873 hsci: fix packet loss caused by large MTU
For maximum performance the MTU of an HSCI interface was set to the value
of the MTU of its HiperSockets interface. However, the MTU of a
HiperSockets interface can be very large, and when the data packets are
not sent over the HiperSocket but over the corresponding ethernet
interface (which usually has a smaller MTU size) then it can happen that
the large packets are silently dropped. One example would be communication
from an HSCI in one CEC to another HSCI in another CEC via Ethernet.

To solve the problem, the MTU setting in this tool is removed, and the
default MTU value is used. Thus, the minimum value of the MTUs of the both
converged interfaces is used as the MTU of the HSCI interface.

Fixes: 0566a492ae ("s390-tools: add hsci tool")
Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Jan Höppner
14ca7c5080 s390-tools: Change GitHub link to new name
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Steffen Maier
4fc1a92a8d zfcpdbf: deal with crash 7.2.9 change in caller name formatting
Since crash 7.2.9 commit
f1f43bf355
in support of kernel v5.9 commit 0990d836cecb
("s390/debug: debug feature version 3"),
the symbolic caller function name is left aligned instead of right
aligned, so now we alternatively have to remove whitespace between
function name and offset.

Otherwise, zfcpdbf output contains wrong warnings about ambiguous payload
records with wrong values for reqid and area, as well as incorrectly
decoded trace records with wrong content values and potential error
messages on not defined record id, and finally a potential list of
occurrences of unknown tags which should empty:

Loading trace records ...(this might take a while)
Warning: Ambiguous PAYload records. reqid:>>>wrong<<< area:V^D^@fcp_
Warning: Ambiguous PAYload records. reqid:>>>wrong<<< area:W^D^@fsf_
Warning: Ambiguous PAYload records. reqid:>>>wrong<<< area:i^B^@san_

...

Timestamp      : ...
Area           : SAN
Subarea        : 00
Level          : 1
Exception      : -
CPU ID         : 0001
Caller         : <zfcp_dbf_san_in_els
Record ID      : 0
Tag            : 6^B^Cfcie
Request ID     : >>>wrong<<<
Destination ID : >>>wrong<<<
SAN record id=0 not defined.
Timestamp      : ...
Area           : SAN
Subarea        : 00
Level          : 1
Exception      : -
CPU ID         : 0002
Caller         : <zfcp_dbf_san_in_els
Record ID      : 0
Tag            : 6^B^Cfcie
Request ID     : >>>wrong<<<
Destination ID : >>>wrong<<<
SAN record id=0 not defined.

...

occurrences of unknown tags:
...

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:46:54 +01:00
Ingo Franzki
d73d7f91ac zkey-ekmfweb: Fix typos in man page
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Alexander Egorenkov
800df6bef8 zipl/boot: fix heap OOM in stage2 of DASD dumper
For the stage2 of zipl's boot loaders only 3 heap pages are available
[0x6000, 0x6000 + 0x3000]. Therefore, stage2 code needs to be very careful
when and for how long it allocates a heap page.

The heap OOM problem in stage2 was hidden until the commit 252be376
("zipl/boot: fix potential heap overflow in stage2"). Before this commit,
stage2 assumed that heap is 4 pages large which is apparently very wrong
but get_zeroed_page() still allowed allocating an extra 4th page by
overriding the memory segment following the heap area of stage2 (stage3
parameter area).

Try to avoid allocating a heap page and keeping it allocated over a long
period of time in the DASD dumpers. Free a heap page as soon as possible
if not required anymore.

And be extra careful with printf() because it always tries to allocate
a free heap page.

Fixes: 252be376 ("zipl/boot: fix potential heap overflow in stage2")
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Marc Hartmayer
3c661da4ee genprotimg: boot: make boot loader -march=z900 compatible
Replace the `lgfi` opcode with equivalents as z900 has no support for
it.

While at it, fix a comment in `genprotimg/boot/head.S` and remove a
useless label in `genprotimg/boot/stage3b_reloc.S`.

Closes: https://github.com/ibm-s390-tools/s390-tools/issues/86
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Ingo Franzki
bf5ca4367d libekmfweb: Check length of JWK EC public key coordinates
RFC 7517 requires that the x and y coordinates of a ECC JSON Web Key
(JWK) are specified in its full size of a coordinate for the curve used.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Wenjia Zhang
faf26220a7 hsci: fix failed to delete an HSCI connected with VLAN
Deleting an HSCI interface, the connected HiperSockets interface's name
and the connected Ethernet interface's name are extracted from "ip link
show". Currently the extracted names are directly used in "bridge -d link
show dev ifname" for further checking. If "iflink" and "ifindex" of an
interface are not matched, ip commands will print @ifXX appended to the
real interface's name. Thus, it will be failed if the interface's name
with the ending @ifXX is used in "bridge -d link show dev ifname" for
further checking.

To solve the problem, the ending @ifXX must be removed before the
interface name is used further.

Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Wenjia Zhang
522252d18a hsci: fix wrong return code
In the current code, after the function check_pnetids() and the function
verify_precon() are called, $? from each function is used twice
successively. It is used for the first time in the condition of the IF
statement, while for the second time as return code of the current
function. In bash, $? can be used to get the return code, but only for
the first time directly after the previous function is called.
Afterwards, $? will be reset to "0". Thus, the right return code can not
be get, if $? is used second time.

To solve the problem, using $? for the second time should be avoided.

Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Alexander Egorenkov
42889edc0c make: add address sanitizer support
Install libasan first, e.g. on Fedora 32:
  dnf install -y libasan libasan-static.

To compile with address sanitizer, pass ASAN=1 to make.
AdressSanitizer helps to catch various memory bugs for which C/C++ is
infamous.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Alexander Egorenkov
13016ebc5a cmsfs-fuse: ASAN fix dec_to_hex() and hex_to_dec()
This fixes the following compiler errors when ASAN is enabled:

  CC      cmsfs-fuse/cmsfs-fuse.o
cmsfs-fuse.c: Assembler messages:
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Ingo Franzki
c4546daf34 zkey-ekmfweb: Avoid sequence number clash when generating keys
When keys are generated concurrently in EKMF Web from multiple clients,
and the key labels use a sequence number tag, then the assignment logic
of the sequence number may cause a duplicate sequence number to be used,
because another key might have already been generated with the same
sequence number, since the next-to-use sequence number has been retrieved
from EKMF Web. This results in a HTTP response code of 409 and a -EEXIST
return code from ekmf_generate_key().

Instead of getting the last used sequence number from EKMFWeb, tell
EKMFWeb to automatically use the next available sequence number when
generating a key. When the sequence number label tag value is 'next'
then EKMFWeb will automatically assign the next available sequence number
to the label tag and increment the sequence number in an atomic way.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Alexander Egorenkov
1e18429f69 zdump: fix invalid memory access on memory chunk's data
If a memory chunk is added to mem_phys as well as mem_virt
in dfi_mem_chunk_add_vol() then an illegal memory access might occur
when accessing mem_chunk->data e.g. in dfi_elf_mem_chunk_read_fn()
because the data block pointed to by the data field is now being referenced
by two memory chunks, one in mem_phys and one in mem_virt. If it happens
that the memory chunk from mem_virt is freed in mem_unmap() then
the memory chunk in mem_phys still points to the common data block
which has been already freed. This leads to all sort of bad behavior
in dfi_elf_mem_chunk_read_fn() and other places where mem_chunk->data
might be accessed.

Fixes the following bug:
zgetdump: Unexpected end of file for "dump.all.elf"

And this was found by AddressSanitizer:

=================================================================
==81170==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000570 at pc 0x00000101ac10 bp 0x03ffd897e250 sp 0x03ffd897e248
READ of size 8 at 0x602000000570 thread T0
    #0 0x101ac0f in dfi_elf_mem_chunk_read_fn s390-tools/zdump/dfi_elf.c:27
    #1 0x100d8a5 in mem_read s390-tools/zdump/dfi.c:339
    #2 0x100d8a5 in dfi_mem_phys_read s390-tools/zdump/dfi.c:616
    #3 0x100d8a5 in mem_chunk_map_read_fn s390-tools/zdump/dfi.c:353
    #4 0x100fd29 in mem_read s390-tools/zdump/dfi.c:339
    #5 0x100fd29 in dfi_mem_read s390-tools/zdump/dfi.c:608
    #6 0x1018e89 in os_info_get s390-tools/zdump/dfi_vmcoreinfo.c:65
    #7 0x1018e89 in dfi_vmcoreinfo_init s390-tools/zdump/dfi_vmcoreinfo.c:86
    #8 0x10175b3 in dfi_init s390-tools/zdump/dfi.c:1215
    #9 0x1006e71 in do_stdout s390-tools/zdump/zgetdump.c:161
    #10 0x1006e71 in main s390-tools/zdump/zgetdump.c:180
    #11 0x3ffb07abb89 in __libc_start_main (/lib64/libc.so.6+0x2bb89)
    #12 0x1007e8d  (s390-tools/zdump/zgetdump+0x1007e8d)

0x602000000570 is located 0 bytes inside of 8-byte region [0x602000000570,0x602000000578)
freed by thread T0 here:
    #0 0x3ffb0bc961b in free (/lib64/libasan.so.6+0xc961b)
    #1 0x100d2d9 in mem_unmap s390-tools/zdump/dfi.c:1050

previously allocated by thread T0 here:
    #0 0x3ffb0bc9aa9 in calloc (/lib64/libasan.so.6+0xc9aa9)
    #1 0x100a271 in zg_alloc s390-tools/zdump/zg.c:93

SUMMARY: AddressSanitizer: heap-use-after-free s390-tools/zdump/dfi_elf.c:27 in dfi_elf_mem_chunk_read_fn
Shadow bytes around the buggy address:
  0x100c0400000050: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000060: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000070: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000080: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000090: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
=>0x100c04000000a0: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa[fd]fa
  0x100c04000000b0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
  0x100c04000000c0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 04 fa
  0x100c04000000d0: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c04000000e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x100c04000000f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==81170==ABORTING

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Alexander Egorenkov
11e78cada5 zdump: catch attempts to seek past end of file in zg_seek()
Make zg_seek() more robust.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Alexander Egorenkov
0a7df9e030 zdump: improve error handling in pt_load_add()
Verify the given ELF header before adding any memory chunks otherwise
a memory chunk might be added even if the given ELF header is invalid.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Vineeth Vijayan
7dd03eaeec zdev: Add build option to update initial RAM-disk by default
Some Linux distributions always include a copy of all persistent device
configuration data when updating the initial RAM-disk. This makes
chzdev's persistent device configuration changes ineffective because
device configuration directives applied in the RAM-disk take precedence
over those stored in the root filesystem.

This patch introduces a new build-time switch which allows distributions
to specify that whenever there is a persistent device configuration
change, the RAM-disk is updated automatically.

This feature can be enabled by adding 'ZDEV_ALWAYS_UPDATE_INITRD=1' as
a zdev build option. Where, by default ZDEV_ALWAYS_UPDATE_INITRD is 0.

Co-developed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Ingo Franzki
663262c962 zkey: Prevent sporadic error during key verification pattern generation
After a master key change, it can happen that the AF_ALG setkey
operation returns EINVAL, although the key is valid. This is a
temporary situation and the operation will succeed, once the firmware
has completed some internal processing related with the master key
change. Delay 1 second and retry up to 10 times.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Nikita Dubrovskii
bf9482709f fdasd: Use increased retry count for dasd_reread_partition_table
If fdasd is used right after dasdfmt, it may fail with the following
error due to udev still processing events for the device:

```
fdasd error:  IOCTL error: Error while rereading partition table.
```

Call dasd_reread_partition_table() with an increased retry value to
circumvent this issue.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/103
Signed-off-by: Nikita Dubrovskii <nikita@linux.ibm.com>
[hoeppner@linux.ibm.com: Reword commit message]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Dan Horák
cdf0b5d66f hsci: fix help text
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/102
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Vance Morris
4aafd6962a netboot: Bump busybox version in pxelinux.0 build
`stime` was removed in glibc-2.31.
Busybox fixes this in https://git.busybox.net/busybox/patch/?id=d3539be8f27b8cbfdfee460fe08299158f08bcd9

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/100
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/101
Signed-off-by: Vance Morris <vmorris@us.ibm.com>
Reviewed-by: Viktor Mihajlovski mihajlov@de.ibm.com
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
863e1c3fa4 zkey: Remove warning about sector size support with crypttab
Current distributions should now all support the sector size option
in crypttab entries for plain mode dm-crypt volumes.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
7c47ea8e09 zkey: Add support to store LUKS2 dummy passphrase in key repository
Extend zkey to allow to store a (dummy) LUKS2 passphrase together with a
secure key, for use with LUKS2 volumes. That way, when the repository is
backed up, or archived, also the passphrases of the associated LUKS2
volumes are backed up, or archived, and thus can not be forgotten.
This passphrase is then used in generated commands to format and open
the LUKS2 volumes.

Because of the use of secure keys to encrypt the volumes, the LUKS2
passphrase is of no or less relevance for security. It is therefore OK to
store the passphrase in clear text in the key repository, and also use
them in /etc/crypttab. Therefore, the passphrase could actually be a
trivial passphrase, or a dummy passphrase.

Note: Such a dummy passphrase is NOT considered a secret that needs to
be protected. If for a certain usage the passphrase is of relevance for
security, then the zkey dummy passphrase option must not be used to store
the passphrase.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Alexander Egorenkov
c239d99379 genprotimg: do not fail on inline warnings caused by glib
gcc's -Werror switch also enables -Werror=inline which leads to a compilation
failure due to inline warnings caused by GLIB macros. To fix it, disable
the conversion of inline warnings into errors.

In file included from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/lib/glib-2.0/include/glibconfig.h:9,
                 from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib/gtypes.h:32,
                 from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib/galloca.h:32,
                 from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib.h:30,
                 from pv/pv_hdr.c:10:
buildroot/qemu-s390x/build/s390-tools-2.15.1/genprotimg/src/utils/buffer.h: In function ‘pv_hdr_new’:
buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib/gmacros.h:1028:49: error: inlining failed in call to ‘glib_autoptr_clear_Buffer’: call is unlikely and code size would grow [-Werror=inline]
 1028 | #define _GLIB_AUTOPTR_CLEAR_FUNC_NAME(TypeName) glib_autoptr_clear_##TypeName
      |                                                 ^~~~~~~~~~~~~~~~~~~

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Alexander Egorenkov
6c6e3a2b0e zipl/boot: fix potential heap overflow in stage2
Current heap size in stage2 is three pages long [0x6000-0x9000] but
get_zeroed_page() assumes it is one page more which might lead to
a heap overflow which will corrupt data located at 0x9000 (stage3
parameters). Calculate the heap size of a stage at run-time
by using the symbols provided by linker.

Furthermore, validate the given address in free_page() to stop illegal
memory accesses.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Alexander Egorenkov
2dca5d193f zipl/boot: fix memory use after free in stage2
Prevent access to freed memory still pointed to by entry.
entry still points into load_page that has been released with free_page.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
75675ec627 libekmfweb: Make install directory for shared libraries configurable
If LIBDIR is not passed to the make invocation, install shared libraries
to USRLIB64DIR (/usr/lib64/), even though LIBDIR defaults to /lib/. If
LIBDIR is overridden for the make invocation, install shared libraries to
whatever is specified as LIBDIR.

Closes: https://github.com/ibm-s390-tools/s390-tools/issues/98

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
18bf2cce06 zkey/zkey-ekmfweb: Install KMS plugins into configurable location
Install KMS plugins into a configurable location. The default KMS plugin
location is '/usr/lib64/zkey/', but one can set ZKEYKMSPLUGINDIR on the make
invocation to change the plugin location, e.g. to '/usr/libexec/zkey/'.

Closes: https://github.com/ibm-s390-tools/s390-tools/issues/98

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
8781dd3e7b zkey-ekmfweb: Fix selection of key properties to set or remove
When some of the key properties are skipped due to null_values_only
being true or false, then the resulting EKMF tag list might be built
incorrectly.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
6380e77f28 zkey-ekmfweb: Allow NULL as property value to remove a property
To remove a KMS property function kms_set_key_properties() can be
called with the property value set to NULL. Do not assert for non-NULL
property values.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Marc Hartmayer
733b86c02a genprotimg: remove -Winline cflag
`-Winline` can cause problems with the cleanup functions defined by
glib. Therefore let's remove the cflag for now.

DEBUG: /usr/include/glib-2.0/glib/gmacros.h:1031:43: error: inlining failed in call to 'glib_autoptr_cleanup_STACK_OF_X509_CRL.isra.0': call is unlikely and \
code size would grow [-Werror=inline]
DEBUG:  1031 | #define _GLIB_AUTOPTR_FUNC_NAME(TypeName) glib_autoptr_cleanup_##TypeName

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Marc Hartmayer
7827a791c9 genprotimg: add missing return
This should be no problem (if OpenSSL works correctly), because
`crls_download_cb` is only called out of the verification context of
OpenSSL. It's used to look up a CRL and therefore
X509_STORE_CTX_get_current_cert should always return a certificate
since X509_STORE_CTX_get_current_cert returns NULL only if an error
has occurred during the verification (see
https://www.openssl.org/docs/man1.1.0/man3/X509_STORE_CTX_get_current_cert.html).

Fixes: 074de1e14e ("genprotimg: add host-key document verification support")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
49 changed files with 1288 additions and 231 deletions

View File

@@ -9,12 +9,14 @@ List of all individuals having contributed content to s390-tools
- Arnd Bergmann
- Axel Wirbser
- Benjamin Block
- Brian C. Lane
- Carsten Otte
- Christian Borntraeger
- Christian Ehrhardt
- Christof Schmitt
- Claudio Imbrenda
- Clemens von Mann
- Colin Walters
- Dan Horak
- Despina Papadopoulou
- Dimitri John Ledkov
@@ -75,11 +77,13 @@ List of all individuals having contributed content to s390-tools
- Michael Mueller
- Mijo Safradin
- Mikhail Zaslonko
- Nikita Dubrovskii
- Niklas Schnelle
- Peter Oberparleiter
- Peter Tiedemann
- Philipp Kern
- Philipp Rudo
- Prashanth Sundararaman
- Rafael Fonseca
- Raimund Schroeder
- Ralph Wuerthner
@@ -109,7 +113,10 @@ List of all individuals having contributed content to s390-tools
- Tuan Hoang
- Ursula Braun
- Utz Bacher
- Vance Morris
- Vasily Gorbik
- Viktor Mihajlovski
- Vineeth Vijayan
- Volker Sameske
- Wenjia Zhang
- Wolfgang Taphorn

View File

@@ -1,14 +1,35 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.15.x (2020-xx-xx)__
* __v2.16.0 (2021-02-19)__
For Linux kernel version: 5.x
For Linux kernel version: 5.10 / 5.11
Add new tool:
- hsci: New tool to manage HSCI (HiperSockets Converged Interfaces)
Changes of existing tools:
- hsci: New tool to manage HSCI interfaces
- genprotimg: Add host-key document verification support
- genprotimg: boot: Make boot loader -march=z900 compatible
- libekmfweb: Make install directory for shared libraries configurable
- lsdasd: Add FC Endpoint Security information
- make: Add address sanitizer support
- netboot: Add version information to scripts
- netboot: Bump busybox version in pxelinux.0 build
- zdev: Add FC Endpoint Security information for DASD devices
- zdev: Add build option to update initial RAM-disk by default
- zkey-ekmfweb: Avoid sequence number clash when generating keys
- zkey/zkey-ekmfweb: Install KMS plugins into configurable location
- zkey: Add support to store LUKS2 dummy passphrase in key repository
Bug Fixes:
- dasdfmt: Fix segfault when an incorrect option is specified
- genprotimg: Fix several build issues
- genprotimg: Require argument for 'ramdisk' and 'parmfile' options
- zcryptstats: Fix handling of partial results with many domains
- zfcpdbf: Deal with crash 7.2.9 change in caller name formatting
- zipl/boot: Fix memory use after free in stage2
- zipl/boot: Fix potential heap overflow in stage2
- zipl: Fix reading 4k disk's geometry
* __v2.15.1 (2020-10-28)__

View File

@@ -72,7 +72,7 @@ In the examples below we use this fictive identity:
### Setup GitHub and local git
1. Create a fork of this repository by clicking the `Fork` button on the top
right of the [s390-tools](https://github.com/ibm-s390-tools/s390-tools)
right of the [s390-tools](https://github.com/ibm-s390-linux/s390-tools)
main page
2. Clone your forked repository to your local development system
@@ -84,7 +84,7 @@ In the examples below we use this fictive identity:
s390-tools repository on GitHub
```
$ cd s390-tools
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-tools/s390-tools.git
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-linux/s390-tools.git
```
4. Verify your remotes
@@ -92,8 +92,8 @@ In the examples below we use this fictive identity:
~/s390-tools $ git remote -v
origin https://github.com/random-developer/s390-tools.git (fetch)
origin https://github.com/random-developer/s390-tools.git (push)
upstream https://github.com/ibm-s390-tools/s390-tools.git (fetch)
upstream https://github.com/ibm-s390-tools/s390-tools.git (push)
upstream https://github.com/ibm-s390-linux/s390-tools.git (fetch)
upstream https://github.com/ibm-s390-linux/s390-tools.git (push)
```
You now have two remotes: The "origin" remote points to your fork
and the "upstream" remote to the official s390-tools repository.

View File

@@ -284,10 +284,11 @@ build options:
This table lists additional build or install options:
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|----------------|:----------------:|:-------------------------------:|
| dracut | `HAVE_DRACUT` | zdev |
| initramfs-tools| `HAVE_INITRAMFS` | zdev |
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:--------------:|
| dracut | `HAVE_DRACUT` | zdev |
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
The s390-tools build process uses "pkg-config" if available and hard-coded
compiler and linker options otherwise.
@@ -378,6 +379,17 @@ the different tools are provided:
Distributors with different boot or RAM-disk mechanisms should provide
a custom zdev-root-update helper script.
- `ZDEV_ALWAYS_UPDATE_INITRD=1` upon modification of any persistent device
configuration, chzdev updates the initial RAM-disk by default, without any
additional user interaction.
For some distributions, all the configuration attributes must be copied to
the initial RAM-disk. Because the device configuration directives applied
in the initial RAM-disk takes precedence over those stored in the root file-
system. This copying is done usually by explicitly invoking a command. This
build option makes it user-friendly and does this copying without any manual
intervention.
Some functions of zdev require that the following programs are available:
- modprobe (kmod)

View File

@@ -299,7 +299,7 @@ static unsigned long dec_to_hex(unsigned long long num)
{
unsigned long res;
asm volatile("cvb %0,%1" : "=d" (res) : "m" (num));
asm volatile("cvb %0,%1" : "=d" (res) : "Q" (num));
return res & 0xffffffff;
}
@@ -307,7 +307,7 @@ static unsigned int hex_to_dec(unsigned int num)
{
unsigned long long res;
asm volatile("cvd %1,%0" : "=m" (res) : "d" (num));
asm volatile("cvd %1,%0" : "=Q" (res) : "d" (num));
return res & 0xffffffff;
}

View File

@@ -5,8 +5,8 @@ COMMON_INCLUDED = true
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 15
PATCHLEVEL = 1
RELEASE = 16
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
export S390_TOOLS_RELEASE
@@ -106,6 +106,11 @@ endif
DEFAULT_CPPFLAGS = -D_GNU_SOURCE
DEFAULT_LDFLAGS = -rdynamic
ifeq ("${ASAN}","1")
DEFAULT_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
DEFAULT_LDFLAGS += -fsanitize=address
endif
#
# Check for build dependency
#
@@ -174,12 +179,20 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
# for SYSTEMDSYSTEMUNITDIR (e.g. /lib/systemd/system)
SYSTEMDSYSTEMUNITDIR =
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
SOINSTALLDIR = $(USRLIB64DIR)
else
SOINSTALLDIR = $(LIBDIR)
endif
INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
$(SYSCONFDIR) $(SYSCONFDIR)/sysconfig \
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
$(USRLIB64DIR) $(USRINCLUDEDIR)
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
$(SOINSTALLDIR)
OWNER = $(shell id -un)
GROUP = $(shell id -gn)
export INSTALLDIR BINDIR LIBDIR USRLIB64DIR MANDIR OWNER GROUP
@@ -264,6 +277,7 @@ help:
@echo ' G=1 Build with gcov to collect code coverage data'
@echo ' V=1 Generate verbose build output'
@echo ' W=1 Build with higher warning level'
@echo ' ASAN=1 Build with address sanitizer'
@echo ''
@echo 'EXAMPLES'
@echo ' # make clean all D=1 W=1 -j'

View File

@@ -1232,7 +1232,7 @@ static void fdasd_reread_partition_table(fdasd_anchor_t *anc)
if (!anc->silent)
printf("rereading partition table...\n");
if (dasd_reread_partition_table(options.device, 1) != 0) {
if (dasd_reread_partition_table(options.device, 5) != 0) {
fdasd_error(anc, unable_to_ioctl, "Error while rereading "
"partition table.\nPlease reboot!");
}

View File

@@ -1,5 +1,5 @@
/*
* Entry code for stage 3a boot loader
* Entry code for stage 3a and stage 3b boot loader
*
* Copyright IBM Corp. 2020
*
@@ -24,6 +24,8 @@ _start:
sam64
/* Initialize stack */
lgfi %r15, STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
basr %r13, 0
.Lbase: llgf %r15, .Lstack - .Lbase(%r13)
brasl %r14, initialize
.Lstack: .long STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
.previous

View File

@@ -21,6 +21,8 @@ _init:
* kernel command line and the address and size of the
* ramdisk. Simply ignore this by starting at 0x11000.
*/
lgfi %r1, STAGE3A_ENTRY
basr %r13, 0
.Lbase: llgf %r1, .Lstage3a_entry - .Lbase(%r13)
br %r1
.Lstage3a_entry: .long STAGE3A_ENTRY
.previous

View File

@@ -31,12 +31,12 @@ stage3b_reloc_start:
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
sam64
.copy_stage3b:
/* Location of stage3b in memory */
larl %r8, stage3b_start
/* Destination for stage3b */
lgfi %r9, STAGE3B_LOAD_ADDRESS
basr %r13, 0
.Lbase: llgf %r9, .Lstage3b_load_address - .Lbase(%r13)
/* Size of stage3b */
lghi %r11, stage3b_end - stage3b_start
@@ -45,8 +45,10 @@ stage3b_reloc_start:
MEMCPY %r9, %r8, %r11
/* Branch to STAGE3B_ENTRY */
lgfi %r9, STAGE3B_ENTRY
llgf %r9, .Lstage3b_entry - .Lbase(%r13)
br %r9
.Lstage3b_load_address: .long STAGE3B_LOAD_ADDRESS
.Lstage3b_entry: .long STAGE3B_ENTRY
stage3b_start:
.incbin "stage3b.bin"
stage3b_end:

View File

@@ -15,9 +15,9 @@ INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
WARNINGS := -Wall -Wextra -Wshadow \
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline \
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
-Wpointer-arith -Werror \
-Wpointer-arith -Werror -Wno-error=inline \
$(NULL)
$(bin_PROGRAM)_SRCS := $(bin_PROGRAM).c pv/pv_stage3.c pv/pv_image.c \

View File

@@ -1475,7 +1475,7 @@ static STACK_OF_X509_CRL *crls_download_cb(X509_STORE_CTX *ctx, X509_NAME *nm)
g_abort();
cert = X509_STORE_CTX_get_current_cert(ctx);
if (!cert)
g_steal_pointer(&crls);
return g_steal_pointer(&crls);
g_assert(X509_NAME_cmp(X509_get_issuer_name(cert), nm) == 0);
crl = lookup_crl(nm);
if (!crl) {

View File

@@ -22,6 +22,7 @@ Usage: hsci COMMAND [OPTION]
This tool is designed to control and show HSCI (HiperSockets Converged
Interfaces) settings. A HiperSockets interface and an external network
interface are converged into an HSCI interface.
COMMANDS
add HIPERSOCKETS_DEV NET_DEV Adds an HSCI interface
@@ -145,7 +146,7 @@ function verify_precon {
#Check PNETIDs
check_pnetids
if [ $? -ne 0 ]; then
return $?
return 1
fi
return 0
@@ -174,7 +175,7 @@ function add_hsci {
#### Verify preconditions
verify_precon
if [ $? -ne 0 ]; then
return $?
return 1
fi
hsci_postfix="$(readlink /sys/class/net/$hsdev/device/cdev0 | tail -c5)"
@@ -252,16 +253,6 @@ function add_hsci {
return 1
fi
# use hsdev MTU
if [ -e /sys/class/net/$hsdev/mtu ]; then
hs_mtu="$(cat /sys/class/net/$hsdev/mtu)"
ip link set dev $hsci mtu $hs_mtu >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set MTU for $hsci " >&2
clean_up
return 1
fi
fi
ip link set dev $hsci up >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set $hsci up" >&2
@@ -302,10 +293,14 @@ function del_hsci {
bports="$(ip link show | grep "master $hsci" | awk '{print $2}')"
for bport in $bports; do
bport=${bport%:}
if [[ $bport == *@* ]]; then
bport=${bport%@*}
fi
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
hsdev=${bport%:}
hsdev=$bport
else
ndev=${bport%:}
ndev=$bport
fi
done
if [ "$hsdev" == "" ]; then

View File

@@ -77,9 +77,9 @@ libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o
ln -srf libekmfweb.so.$(VERSION) libekmfweb.so
install-libekmfweb.so.$(VERSION): libekmfweb.so.$(VERSION)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION)
ln -srf $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERM)
ln -srf $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION)
ln -srf $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERM)
ln -srf $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so
$(INSTALL) -d -m 770 $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 $(rootdir)include/ekmfweb/ekmfweb.h $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb

View File

@@ -1061,6 +1061,12 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib,
pr_verbose(verbose, "Failed to get and decode x");
goto out;
}
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
pr_verbose(verbose, "x coordinate length is wrong");
rc = -EINVAL;
goto out;
}
len = prime_len;
rc = json_object_get_base64url(jwk, "y", &q[1 + prime_len],
@@ -1069,6 +1075,12 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib,
pr_verbose(verbose, "Failed to get and decode y");
goto out;
}
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
pr_verbose(verbose, "y coordinate length is wrong");
rc = -EINVAL;
goto out;
}
rule_array_count = 1;
memcpy(rule_array, "ECC-PUBL", CCA_KEYWORD_SIZE);

View File

@@ -2254,11 +2254,21 @@ int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey)
rc = json_object_get_base64url(jwk, "x", x, &len);
if (rc != 0)
goto out;
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
rc = -EINVAL;
goto out;
}
len = prime_len;
rc = json_object_get_base64url(jwk, "y", y, &len);
if (rc != 0)
goto out;
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
rc = -EINVAL;
goto out;
}
rc = ecc_pub_key_as_pkey(nid, prime_len, x, y, pkey);
if (rc != 0)

View File

@@ -21,7 +21,7 @@ ifeq ($(KERNEL_IMAGE),)
$(error Could not find a kernel image under /boot)
endif
BUSYBOX=busybox-1.27.1
BUSYBOX=busybox-1.32.0
BBINSTALL=$(BUSYBOX)/_install
all: $(KERNEL_IMAGE) pxelinux.initramfs

View File

@@ -227,6 +227,16 @@ sub get_common
# function name or hexadecimal caller address.
#
$line =~ s/<\s+/</;
#
# Since crash 7.2.9 commit
# https://github.com/crash-utility/crash/commit/f1f43bf355df2564543c39f5d7e13b15c67eb13d
# in support of kernel v5.9 commit 0990d836cecb
# ("s390/debug: debug feature version 3"),
# the symbolic caller function name is left aligned instead of right
# aligned, so now we alternatively have to remove whitespace between
# function name and offset.
#
$line =~ s/<([^+> ]+)[ \t]+/<\1/;
@common = split(/\s+/, $line);
#
# Process symbolic kernel module name, if necessary.
@@ -388,6 +398,17 @@ sub get_foreign_records
# caller address.
#
$line =~ s/<\s+/</;
#
# Since crash 7.2.9 commit
# https://github.com/crash-utility/crash/commit/f1f43bf355df2564543c39f5d7e13b15c67eb13d
# in support of kernel v5.9 commit 0990d836cecb
# ("s390/debug: debug feature version 3"),
# the symbolic caller function name is left aligned
# instead of right aligned, so now we alternatively
# have to remove whitespace between function name and
# offset.
#
$line =~ s/<([^+> ]+)[ \t]+/<\1/;
my @raw_rec = split(/\s+/,($line =~ /[|]/) ?
substr($line, 0, index($line, '|')):
$line);

View File

@@ -12,6 +12,6 @@
#include "exit_code.h"
exit_code_t root_check(void);
exit_code_t initrd_check(bool all_pers);
#endif /* ROOT_H */

View File

@@ -4,6 +4,16 @@ include ../../common.mak
ALL_CPPFLAGS += -I ../include -std=gnu99 -Wno-unused-parameter \
-Wno-missing-field-initializers
# Adding ZDEV_ALWAYS_UPDATE_INITRD=1 option will update the initial RAM-disk
# without the user interaction upon the modification of a persistent device
# configuration.
ifeq ($(ZDEV_ALWAYS_UPDATE_INITRD),1)
ALL_CPPFLAGS += -DZDEV_ALWAYS_UPDATE_INITRD=true
else
ALL_CPPFLAGS += -DZDEV_ALWAYS_UPDATE_INITRD=false
endif
# Core
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \

View File

@@ -3027,7 +3027,7 @@ int main(int argc, char *argv[])
!dryrun) {
/* If the root device/device type or early devices have been
* modified, additional work might be necessary. */
rc = root_check();
rc = initrd_check(ZDEV_ALWAYS_UPDATE_INITRD);
if (rc && !drc)
drc = rc;
}

View File

@@ -58,11 +58,50 @@ static void add_early_removed(struct util_list *selected)
}
}
static void add_pers_removed(struct util_list *strlist)
{
int i, j;
struct devtype *dt;
struct subtype *st;
struct device *dev;
for (i = 0; devtypes[i]; i++) {
dt = devtypes[i];
for (j = 0; dt->subtypes[j]; j++) {
st = dt->subtypes[j];
util_list_iterate(&st->devices->hash.list, dev) {
if (dev->persistent.deconfigured) {
strlist_add(strlist, "%s %s",
dev->subtype->devname, dev->id);
}
}
}
}
}
static bool is_zdev_early_0(struct selected_dev_node *sel)
{
struct setting *s;
struct device *dev;
dev = device_list_find(sel->st->devices, sel->id, NULL);
if (!dev)
return false;
s = setting_list_find(dev->persistent.settings,
internal_attr_early.name);
if (!s)
return false;
if (s->specified && strcmp(s->value, "0") == 0)
return true;
return false;
}
/* Determine if initial RAM-disk needs updating. If so, run the corresponding
* scripts if available. */
exit_code_t root_check(void)
exit_code_t initrd_check(bool all_pers)
{
struct util_list *selected, *params, *mod = NULL;
struct util_list *selected, *params, *mod = strlist_new();
struct selected_dev_node *sel;
struct device *dev;
char *params_str;
@@ -76,6 +115,20 @@ exit_code_t root_check(void)
/* Get list of devices that provide the root device or require
* early configuration. */
selected = selected_dev_list_new();
if (all_pers) {
/* Add all persistently configured devices. */
select = select_opts_new();
select->configured = 1;
select_devices(select, selected, 1, 0, 0, config_persistent,
scope_mandatory, err_ignore);
select_opts_free(select);
/* Ensure that removed devices are considered. */
add_pers_removed(mod);
goto check_mod;
}
/* First add devices that had zdev:early removed or changed to 0.
* The subsequent call to select_devices() will filter out any
* duplicates. */
@@ -95,8 +148,8 @@ exit_code_t root_check(void)
err_ignore);
select_opts_free(select);
check_mod:
/* Determine if any of the devices or device types has been modified. */
mod = strlist_new();
util_list_iterate(selected, sel) {
dt = sel->st->devtype;
@@ -127,17 +180,22 @@ exit_code_t root_check(void)
goto out;
}
/* Ask for confirmation. */
if (!confirm("Update initial RAM-disk now?")) {
rc = EXIT_ABORTED;
goto out;
if (!all_pers) {
/* Ask for confirmation. */
if (!confirm("Update initial RAM-disk now?")) {
rc = EXIT_ABORTED;
goto out;
}
}
/* Build the command line. */
params = strlist_new();
util_list_iterate(selected, sel) {
strlist_add(params, "%s", sel->st->name);
strlist_add(params, "%s", sel->id);
/* From the selected list, remove the devices with zdev:early=0 */
if (!is_zdev_early_0(sel)) {
strlist_add(params, "%s", sel->st->name);
strlist_add(params, "%s", sel->id);
}
}
params_str = strlist_flatten(params, " ");
strlist_free(params);

View File

@@ -407,7 +407,7 @@ void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
if (size == 0)
return;
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
l.mem_virt.chunk_cache->volnr = volnr;
}

View File

@@ -42,6 +42,8 @@ static int pt_load_add(Elf64_Phdr *phdr)
STDERR("Dump file \"%s\" is a user space core dump\n",
g.opts.device);
}
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
if (phdr->p_filesz == 0) {
/* Add zero memory chunk */
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, NULL,
@@ -52,8 +54,6 @@ static int pt_load_add(Elf64_Phdr *phdr)
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, off_ptr,
dfi_elf_mem_chunk_read_fn, zg_free);
}
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
return 0;
}

View File

@@ -280,6 +280,9 @@ off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
off_t rc;
if (off >= zg_fh->sb.st_size)
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
rc = lseek(zg_fh->fh, off, SEEK_SET);
if (rc == -1 && check != ZG_CHECK_NONE)
ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);

View File

@@ -3,6 +3,9 @@ include ../common.mak
CPIOINIT = $(call echocmd," CPIOINI ",/$@)./cpioinit
INSTALL_SCRIPTS = 10-zfcpdump.install
ALL_CFLAGS += -fno-sanitize=all
ALL_LDFLAGS += -fno-sanitize=all
ifeq (${HAVE_LIBC_STATIC},0)
all:

View File

@@ -10,7 +10,8 @@ ALL_CFLAGS = $(NO_PIE_CFLAGS) -Os -g $(INCLUDE_PARMS) \
-fno-delete-null-pointer-checks -fno-stack-protector \
-fexec-charset=IBM1047 -m64 -mpacked-stack \
-mstack-size=4096 -mstack-guard=128 -msoft-float \
-W -Wall -Wformat-security
-W -Wall -Wformat-security -fno-sanitize=all
ALL_LDFLAGS += -fno-sanitize=all
FILES = fba0.bin fba1b.bin fba2.bin \
eckd0_ldl.bin eckd0_cdl.bin \

View File

@@ -449,13 +449,14 @@ void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count)
* block number
*/
unsigned long write_dump_segment(unsigned long blk,
struct df_s390_dump_segm_hdr *segm,
unsigned long zero_page)
struct df_s390_dump_segm_hdr *segm)
{
unsigned long addr, start_blk, blk_count;
unsigned long addr, start_blk, blk_count, zero_page;
/* Write the dump segment header itself (1 page) */
zero_page = get_zeroed_page();
writeblock(blk, (unsigned long)segm, m2b(PAGE_SIZE), zero_page);
free_page(zero_page);
blk += m2b(PAGE_SIZE);
/* Write the dump segment */
addr = segm->start;
@@ -464,7 +465,9 @@ unsigned long write_dump_segment(unsigned long blk,
/* Remaining blocks to write */
blk_count = m2b(segm->len) - (blk - start_blk);
blk_count = MIN(blk_count, eckd_blk_max);
zero_page = get_zeroed_page();
writeblock(blk, addr, blk_count, zero_page);
free_page(zero_page);
progress_print(addr);
blk += blk_count;
addr += b2m(blk_count);

View File

@@ -48,7 +48,6 @@ void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
unsigned long zero_page);
void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count);
unsigned long write_dump_segment(unsigned long blk,
struct df_s390_dump_segm_hdr *segm,
unsigned long zero_page);
struct df_s390_dump_segm_hdr *segm);
#endif /* ECKD2DUMP_H */

View File

@@ -192,10 +192,13 @@ void dt_device_enable(void)
* Check for the volume timestamp and validate the dump signature
* before writing a dump.
*/
static void check_volume(unsigned long page)
static void check_volume(void)
{
struct mvdump_parm_table *mvdump_table_new;
struct df_s390_hdr *hdr_new;
unsigned long page;
page = get_zeroed_page();
/*
* Check whether parameter table on dump device has a valid
@@ -222,6 +225,8 @@ static void check_volume(unsigned long page)
if (dump_hdr->magic != hdr_new->mvdump_sign)
panic(ENOSIGN, "Wrong signature");
}
free_page(page);
}
/*
@@ -229,10 +234,10 @@ static void check_volume(unsigned long page)
* address to write for the next volume or memory size if the dump ended
* on this volume
*/
static unsigned long write_volume(unsigned long addr, unsigned long page,
static unsigned long write_volume(unsigned long addr,
struct df_s390_dump_segm_hdr *dump_segm)
{
unsigned long free_space, blk;
unsigned long free_space, blk, page;
/*
* Write dump header
@@ -245,7 +250,7 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
* header and the end marker)
*/
free_space = b2m(device.blk_end - blk + 1) - b2m(2);
memset((void *) page, 0, PAGE_SIZE);
/*
* Write dump data
*/
@@ -257,7 +262,7 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
addr = find_dump_segment(addr, dump_hdr->mem_size,
ROUND_DOWN(free_space, MIB),
dump_segm);
blk = write_dump_segment(blk, dump_segm, page);
blk = write_dump_segment(blk, dump_segm);
/* Update free space left on vol */
free_space -= dump_segm->len;
/* Reserve one block for the next segment header */
@@ -267,8 +272,10 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
/* Check if no more dump segments follow */
if (dump_segm->stop_marker) {
/* Write end marker */
page = get_zeroed_page();
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
free_page(page);
return dump_hdr->mem_size;
}
/*
@@ -286,19 +293,18 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
void dt_dump_mem(void)
{
struct df_s390_dump_segm_hdr *dump_segm;
unsigned long addr, page;
unsigned long addr;
dump_hdr->mvdump_sign = DF_S390_MAGIC_EXT;
dump_hdr->mvdump = 1;
addr = 0;
total_dump_size = 0;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
while (1) {
printf("Dumping to: 0.%x.%04x", device.sid.ssid, device.devno);
check_volume(page);
addr = write_volume(addr, page, dump_segm);
check_volume();
addr = write_volume(addr, dump_segm);
if (addr == dump_hdr->mem_size)
break;
/*
@@ -312,7 +318,6 @@ void dt_dump_mem(void)
set_device(device.sid, DISABLED);
dt_device_enable();
}
progress_print(addr);
free_page(page);
free_page(__pa(dump_segm));
progress_print(addr);
}

View File

@@ -66,7 +66,6 @@ void dt_dump_mem(void)
struct df_s390_dump_segm_hdr *dump_segm;
blk = device.blk_start;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
/* Write dump header */
@@ -79,18 +78,19 @@ void dt_dump_mem(void)
end = dump_hdr->mem_size;
while (addr < end) {
addr = find_dump_segment(addr, end, 0, dump_segm);
blk = write_dump_segment(blk, dump_segm, page);
blk = write_dump_segment(blk, dump_segm);
total_dump_size += dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
free_page(__pa(dump_segm));
progress_print(addr);
/* Write end marker */
page = get_zeroed_page();
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
free_page(page);
free_page(__pa(dump_segm));
}

View File

@@ -141,13 +141,14 @@ static void writeblock_fba(unsigned long blk, unsigned long addr,
* block number
*/
unsigned long write_dump_segment_fba(unsigned long blk,
struct df_s390_dump_segm_hdr *dump_segm,
unsigned long zero_page)
struct df_s390_dump_segm_hdr *dump_segm)
{
unsigned long addr, start_blk, blk_count;
unsigned long addr, start_blk, blk_count, zero_page;
/* Write the dump segment header itself (1 page) */
zero_page = get_zeroed_page();
writeblock_fba(blk, __pa(dump_segm), BLK_PER_PAGE, zero_page);
free_page(zero_page);
blk += BLK_PER_PAGE;
/* Write the dump segment */
addr = dump_segm->start;
@@ -156,7 +157,9 @@ unsigned long write_dump_segment_fba(unsigned long blk,
/* Remaining blocks to write */
blk_count = m2b(dump_segm->len) - (blk - start_blk);
blk_count = MIN(blk_count, BLK_PWRT);
zero_page = get_zeroed_page();
writeblock_fba(blk, addr, blk_count, zero_page);
free_page(zero_page);
progress_print(addr);
blk += blk_count;
addr += b2m(blk_count);
@@ -198,7 +201,6 @@ void dt_dump_mem(void)
ccw_program_init();
blk = device.blk_start;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
/* Write dump header */
@@ -211,18 +213,19 @@ void dt_dump_mem(void)
end = dump_hdr->mem_size;
while (addr < end) {
addr = find_dump_segment(addr, end, 0, dump_segm);
blk = write_dump_segment_fba(blk, dump_segm, page);
blk = write_dump_segment_fba(blk, dump_segm);
total_dump_size += dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
free_page(__pa(dump_segm));
progress_print(addr);
/* Write end marker */
page = get_zeroed_page();
df_s390_em_page_init(page);
writeblock_fba(blk, page, 1, 0);
free_page(page);
free_page(__pa(dump_segm));
}

View File

@@ -32,9 +32,10 @@ struct ex_table_entry {
};
#define MEM_ALLOC_START ((unsigned long) __heap_start)
#define MEM_ALLOC_CNT 4
#define MEM_ALLOC_END ((unsigned long) __heap_stop)
#define MEM_ALLOC_MAX 4
static uint8_t mem_page_alloc_vec[MEM_ALLOC_CNT];
static uint8_t mem_page_alloc_vec[MEM_ALLOC_MAX];
/*
* Initialize memory with value
@@ -417,10 +418,11 @@ void printf(const char *fmt, ...)
*/
unsigned long get_zeroed_page(void)
{
const int page_count = MIN(MEM_ALLOC_MAX, (int)((MEM_ALLOC_END - MEM_ALLOC_START) / PAGE_SIZE));
unsigned long addr;
int i;
for (i = 0; i < MEM_ALLOC_CNT; i++) {
for (i = 0; i < page_count; i++) {
if (mem_page_alloc_vec[i] != 0)
continue;
addr = MEM_ALLOC_START + i * PAGE_SIZE;
@@ -436,6 +438,9 @@ unsigned long get_zeroed_page(void)
*/
void free_page(unsigned long addr)
{
if (addr < MEM_ALLOC_START || addr >= MEM_ALLOC_END)
libc_stop(EINTERNAL);
mem_page_alloc_vec[(addr - MEM_ALLOC_START) / PAGE_SIZE] = 0;
}

View File

@@ -90,6 +90,7 @@ void start(void)
void *load_address;
struct component_entry *entry;
disk_blockptr_t *blockptr;
uint64_t load_psw;
void *load_page;
int config_nr;
@@ -133,11 +134,13 @@ void start(void)
if (entry->type != COMPONENT_EXECUTE)
panic(EWRONGTYPE, "");
load_psw = entry->address.load_psw;
free_page((unsigned long)load_page);
io_irq_disable();
set_device(subchannel_id, DISABLED);
execute(entry->address.load_psw);
execute(load_psw);
}
void panic_notify(unsigned long UNUSED(reason))

View File

@@ -444,6 +444,9 @@ type_determined:
}
/* Convert device size to size in physical blocks */
data->phy_blocks = devsize / (data->phy_block_size / 512);
/* Adjust start on SCSI according to block_size. device-mapper devices are skipped */
if (data->type == disk_type_scsi && target->targetbase == NULL)
data->geo.start = data->geo.start / (data->phy_block_size / 512);
if (data->partnum != 0)
data->partition = stats.st_rdev;
/* Try to get device name */

View File

@@ -34,6 +34,8 @@ endif
libs = $(rootdir)/libutil/libutil.a
CFLAGS += -DKMS_PLUGIN_LOCATION=\"$(ZKEYKMSPLUGINDIR)\"
detect-libcryptsetup.dep:
echo "#include <libcryptsetup.h>" > detect-libcryptsetup.dep
echo "#ifndef CRYPT_LUKS2" >> detect-libcryptsetup.dep

View File

@@ -44,9 +44,8 @@ libekmfweb.dep:
install: all install-libekmfweb.dep zkey-ekmfweb.so
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m 644 -c zkey-ekmfweb.1 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -d -m 755 $(DESTDIR)$(USRLIB64DIR)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRLIB64DIR)/zkey
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T zkey-ekmfweb.so $(DESTDIR)$(USRLIB64DIR)/zkey/zkey-ekmfweb.so
$(INSTALL) -d -m 755 $(DESTDIR)$(ZKEYKMSPLUGINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T zkey-ekmfweb.so $(DESTDIR)$(ZKEYKMSPLUGINDIR)/zkey-ekmfweb.so
clean:
rm -f *.o zkey-ekmfweb.so install-libekmfweb.dep libekmfweb.dep

View File

@@ -321,7 +321,7 @@ Specifies the subject name for generating a certificate signing request (CSR)
or self signed certificate, in the form
\fB<type>=<value>(;<type>=<value>)*[;]\fP with types recognized by OpenSSL.
.TP
.BR \-s ", " \-\-cert\-extensions\~\fIextensions\fP
.BR \-e ", " \-\-cert\-extensions\~\fIextensions\fP
Specifies the certificate extensions for generating a certificate signing
request (CSR) or self signed certificate, in the form
\fB<name>=[critical,]<value(s)>(;<name>=[critical,]<value(s)>)*[;]\fP
@@ -416,7 +416,7 @@ Configures the connection to the EKMF Web server on 'my.ekmfweb.server'.
.B zkey kms configure \-\-ekmfweb\-url https://my.ekmfweb.server \-\-tls\-pin\-server\-pubkey \-\-tls\-verify\-hostname
Configures the connection to the EKMF Web server on 'my.ekmfweb.server' and
pins the server's public key from the server's TSL certificate as well as
enables verification of the host nmae to match the server's Common Name in the
enables verification of the host name to match the server's Common Name in the
certificate.
.TP
.B zkey kms configure \-\-gen\-csr csr.pem \-\-cert\-subject \(dqCN=my.zkey.client;OU=Example;C=US\(dq
@@ -437,10 +437,10 @@ subject name and a certificate extension to limit the key usage, and stores it
in file 'cert.pem'.
.TP
.B zkey kms configure \-\-register cert.pem
Registers the zkey client with EKMF Web using the certifcate in file 'cert.pem'.
Registers the zkey client with EKMF Web using the certificate in file 'cert.pem'.
.TP
.B zkey kms configure \-\-register cert.pem \-\-label\-tags \(dqENV=TEST,APP=LINUX\(dq
Registers the zkey client with EKMF Web using the certifcate in file 'cert.pem'
Registers the zkey client with EKMF Web using the certificate in file 'cert.pem'
and the label tags 'ENV=TEST' and 'APP=LINUX' for the identity key.
.TP
.B zkey kms info
@@ -480,7 +480,7 @@ client is allowed to use it or not.
.TP
.B zkey kms list \-\-label \(dq*LUKS2*\(dq
Displays eligible secure keys managed by EKMF Web where the label name in EKMF
Web contains the work 'LUKS2'.
Web contains the word 'LUKS2'.
.TP
.B zkey kms import \-\-name seckey
Imports the secure key managed by EKMF Web with a zkey name of 'seckey'.

View File

@@ -2520,7 +2520,7 @@ static int _configure_connection(struct plugin_handle *ph,
"[y/N]? ",
program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
return -ECANCELED;
}
}
@@ -2651,10 +2651,10 @@ static int _configure_connection(struct plugin_handle *ph,
goto out;
}
}
printf("%s: Is this the EKMF Web server you intent to work with "
printf("%s: Is this the EKMF Web server you intend to work with "
"[y/N]? ", program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
rc = -ECANCELED;
goto out;
}
@@ -2948,7 +2948,7 @@ static int _generate_identity_key(struct plugin_handle *ph)
printf("%s: Re-generate the identity key [y/N]? ",
program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
return -ECANCELED;
}
} else {
@@ -3347,45 +3347,6 @@ static void _free_ekmf_tags(struct ekmf_tag_list *ekmf_tag_list)
ekmf_tag_list->num_tags = 0;
}
/**
* Gets the next sequence number of the template
*
* @param ph the plugin handle
* @param template_uuid the template UUID
*
* @returns an allocated string, or NULL in case of an error.
*/
static char *_get_seqno(struct plugin_handle *ph, const char *template_uuid)
{
unsigned int seqno = 0;
char *error_msg = NULL;
char *ret = NULL;
int rc;
rc = ekmf_get_last_seq_no(&ph->ekmf_config, &ph->curl_handle,
template_uuid, &seqno, &error_msg,
ph->verbose);
if (rc != 0) {
_set_error(ph, "Failed to get last used sequence number for "
"template '%s': %s",
template_uuid, error_msg != NULL ? error_msg :
strerror(-rc));
_remove_login_token_if_error(ph, rc);
goto out;
}
seqno++;
util_asprintf(&ret, "%05u", seqno);
pr_verbose(ph, "Seqno: '%s'", ret);
out:
if (error_msg != NULL)
free(error_msg);
return ret;
}
/**
* Parses the label tags passed in via option (<tag>=<value>;<tag>=<value;....)
* and allocates an array of KMS properties. The tags must be freed by the
@@ -3450,25 +3411,16 @@ static int _parse_label_tags(struct plugin_handle *ph,
if (value != NULL) {
ekmf_tag_list->tags[i].value =
util_strdup(value);
util_str_toupper((char *)
ekmf_tag_list->tags[i].value);
} else {
ekmf_tag_list->tags[i].value =
_get_seqno(ph,
template_info->uuid);
if (ekmf_tag_list->tags[i].value ==
NULL) {
rc = -EIO;
goto out;
}
util_strdup(EKMFWEB_SEQNO_NEXT);
}
k++;
} else {
ekmf_tag_list->tags[i].value =
_get_seqno(ph,
template_info->uuid);
if (ekmf_tag_list->tags[i].value == NULL) {
rc = -EIO;
goto out;
}
util_strdup(EKMFWEB_SEQNO_NEXT);
}
} else {
if (tag == NULL) {
@@ -3504,11 +3456,10 @@ static int _parse_label_tags(struct plugin_handle *ph,
}
ekmf_tag_list->tags[i].value = util_strdup(value);
util_str_toupper((char *)ekmf_tag_list->tags[i].value);
k++;
}
util_str_toupper((char *)ekmf_tag_list->tags[i].value);
pr_verbose(ph, "Tag: '%s', Value: '%s'",
ekmf_tag_list->tags[i].name,
ekmf_tag_list->tags[i].value);
@@ -3649,7 +3600,7 @@ static int _register_client(struct plugin_handle *ph, const char *cert_file,
printf("%s: Re-register the zkey client [y/N]? ",
program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
return -ECANCELED;
}
}
@@ -4566,22 +4517,23 @@ static int _properties_to_ekmf_tags(struct plugin_handle *UNUSED(ph),
struct ekmf_tag_list *ekmf_tag_list,
bool null_values_only)
{
size_t i;
size_t i, k;
ekmf_tag_list->num_tags = 0;
ekmf_tag_list->tags = util_malloc(
sizeof(struct ekmf_tag) * num_properties);
for (i = 0; i < num_properties; i++) {
for (i = 0, k = 0; i < num_properties; i++) {
if (!null_values_only && properties[i].value == NULL)
continue;
if (null_values_only && properties[i].value != NULL)
continue;
ekmf_tag_list->tags[i].name = util_strdup(properties[i].name);
ekmf_tag_list->tags[i].value = properties[i].value != NULL ?
ekmf_tag_list->tags[k].name = util_strdup(properties[i].name);
ekmf_tag_list->tags[k].value = properties[i].value != NULL ?
util_strdup(properties[i].value) : NULL;
ekmf_tag_list->num_tags++;
k++;
}
return 0;
@@ -4981,10 +4933,10 @@ int kms_set_key_properties(const kms_handle_t handle, const char *key_id,
for (i = 0; i < num_properties; i++) {
util_assert(properties[i].name != NULL,
"Internal error: property name is NULL");
util_assert(properties[i].value != NULL,
"Internal error: property value is NULL");
pr_verbose(ph, " Property '%s': '%s", properties[i].name,
properties[i].value);
pr_verbose(ph, " Property '%s': '%s'", properties[i].name,
properties[i].value != NULL ? properties[i].value :
"(null)");
}
_clear_error(ph);

View File

@@ -99,6 +99,7 @@ struct plugin_handle {
#define EKMFWEB_CURVE_PRIME "PRIME_CURVE"
#define EKMFWEB_CURVE_BAINPOOL "BRAINPOOL_CURVE"
#define EKMFWEB_SEQNO_TAG "seqno"
#define EKMFWEB_SEQNO_NEXT "next"
#define DEFAULT_IDENTITY_KEY_PUBLIC_EXPONENT 65537

View File

@@ -40,12 +40,16 @@ struct key_filenames {
char *skey_filename;
char *info_filename;
char *renc_filename;
char *pass_filename;
};
#define FILE_EXTENSION_LEN 5
#define SKEY_FILE_EXTENSION ".skey"
#define INFO_FILE_EXTENSION ".info"
#define RENC_FILE_EXTENSION ".renc"
#define PASS_FILE_EXTENSION ".pass"
#define DUMMY_PASSPHRASE_LEN 16
#define LOCK_FILE_NAME ".lock"
@@ -76,6 +80,7 @@ struct key_filenames {
#define REC_VOLUME_TYPE "Volume type"
#define REC_KMS "KMS"
#define REC_KMS_KEY_LABEL "KMS key label"
#define REC_PASSPHRASE_FILE "Dummy passphrase"
#define pr_verbose(keystore, fmt...) do { \
if (keystore->verbose) \
@@ -110,6 +115,8 @@ static int _keystore_get_key_filenames(struct keystore *keystore,
name, INFO_FILE_EXTENSION);
util_asprintf(&names->renc_filename, "%s/%s%s", keystore->directory,
name, RENC_FILE_EXTENSION);
util_asprintf(&names->pass_filename, "%s/%s%s", keystore->directory,
name, PASS_FILE_EXTENSION);
pr_verbose(keystore, "File names for key '%s': '%s' and '%s'", name,
names->skey_filename, names->info_filename);
@@ -128,6 +135,18 @@ static int _keystore_reencipher_key_exists(struct key_filenames *file_names)
return util_path_is_reg_file("%s", file_names->renc_filename);
}
/**
* Checks if the .pass file exists.
*
* @param[in] file_names names of the files
*
* @returns 1 if the file exist, 0 if the file do not exist
*/
static int _keystore_passphrase_file_exists(struct key_filenames *file_names)
{
return util_path_is_reg_file("%s", file_names->pass_filename);
}
/**
* Checks if both, the .skey and the .info (and .renc) files exist.
*
@@ -146,7 +165,8 @@ static int _keystore_exists_keyfiles(struct key_filenames *file_names)
if (rc_skey && rc_info)
return 1;
if (!rc_skey && !rc_info &&
_keystore_reencipher_key_exists(file_names) == 0)
_keystore_reencipher_key_exists(file_names) == 0 &&
_keystore_passphrase_file_exists(file_names) == 0)
return 0;
return -1;
}
@@ -220,6 +240,8 @@ static void _keystore_free_key_filenames(struct key_filenames *names)
free(names->info_filename);
if (names->renc_filename)
free(names->renc_filename);
if (names->pass_filename)
free(names->pass_filename);
}
/**
@@ -985,7 +1007,7 @@ static int _keystore_process_filtered(struct keystore *keystore,
process_key_t process_func,
void *process_private)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
char **apqn_filter_list = NULL;
char **vol_filter_list = NULL;
struct properties *key_props;
@@ -1593,6 +1615,129 @@ static int _keystore_set_default_properties(struct properties *key_props)
return 0;
}
/**
* Generate, Set or remove a dummy LUKS2 passphrase of a key.
*
* @param[in] keystore the key store
* @param[in] name the name of the key
* @param[in] file_names the file names of the key
* @param[in] properties the properties of the key
* @param[in] prompt if true, prompt for removal (if passphrase exists)
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_remove_passphrase(struct keystore *keystore,
const char *name,
const struct key_filenames *filenames,
struct properties *properties,
bool prompt)
{
int rc;
if (_keystore_passphrase_file_exists((struct key_filenames *)filenames)
&& prompt) {
util_print_indented("ATTENTION: When you remove the LUKS2 "
"dummy passphrase of a key, you might no "
"longer be able to open the LUKS2 volumes "
"associated with the key, unless you still "
"know a passphrase of one of the key slots "
"of these volumes!", 0);
_keystore_msg_for_volumes("The following volumes are encrypted "
"with this key:", properties, NULL);
printf("%s: Remove passphrase for key '%s' [y/N]? ",
program_invocation_short_name, name);
if (!prompt_for_yes(keystore->verbose)) {
warnx("Operation aborted");
return -ECANCELED;
}
}
rc = remove(filenames->pass_filename);
if (rc != 0 && errno != ENOENT) {
rc = -errno;
warnx("Failed to remove file '%s': %s",
filenames->pass_filename, strerror(-rc));
return rc;
}
return 0;
}
/**
* Generate, Set or remove a dummy LUKS2 passphrase of a key.
*
* @param[in] keystore the key store
* @param[in] name the name of the key
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2. If NULKL, the passphrase is generated by
* random.
* @param[in] file_names the file names of the key
* @param[in] properties the properties of the key
* @param[in] prompt if true, prompt for change, if passphrase exists
* already
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_set_passphrase(struct keystore *keystore,
const char *name,
const char *passphrase_file,
const struct key_filenames *filenames,
struct properties *properties,
bool prompt)
{
char *volume_type;
int rc;
if (_keystore_passphrase_file_exists((struct key_filenames *)filenames)
&& prompt) {
warnx("There is already a LUKS2 dummy passphrase associated "
"with key '%s'.", name);
util_print_indented("To change a dummy passphrase of a key, "
"first remove the currently associated "
"passphrase with command 'zkey change "
"--name <key> --remove-dummy-passphrase' "
"and then set the new dummy passphrase for "
"the key.", 0);
return -EEXIST;
}
volume_type = _keystore_get_volume_type(properties);
if (volume_type == NULL) {
pr_verbose(keystore, "No volume type available");
return -EINVAL;
}
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0) {
warnx("The LUKS2 dummy passphrase can only be set for keys "
"with a volume type of LUKS2.");
free(volume_type);
return -EINVAL;
}
free(volume_type);
if (passphrase_file != NULL) {
rc = copy_file(passphrase_file, filenames->pass_filename, 0);
if (rc != 0) {
warnx("Failed to copy the passphrase phase '%s': %s",
passphrase_file, strerror(-rc));
return rc;
}
} else {
rc = copy_file("/dev/urandom", filenames->pass_filename,
DUMMY_PASSPHRASE_LEN);
if (rc != 0) {
warnx("Failed to generate the dummy passphrase: %s",
strerror(-rc));
return rc;
}
}
rc = _keystore_set_file_permission(keystore, filenames->pass_filename);
if (rc != 0)
return rc;
return 0;
}
/**
* Creates the key properties for a key
*
@@ -1615,6 +1760,8 @@ static int _keystore_set_default_properties(struct properties *key_props)
* @param[in] key_type the type of the key
* @param[in] kms the name of the KMS plugin, or NULL if no KMS is bound
* @param[out] props the properties object is allocated and returned
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_create_info_props(struct keystore *keystore,
const char *name,
@@ -1721,7 +1868,7 @@ out:
*
* @param[in] keystore the key store
* @param[in] name the name of the key
* @param[in] info_filename the file name of the key info file
* @param[in] filenames the file names of the key files
* @param[in] description textual description of the key (optional, can be NULL)
* @param[in] volumes a comma separated list of volumes associated with this
* key (optional, can be NULL)
@@ -1735,7 +1882,12 @@ out:
* default is used.
* @param[in] volume_type the type of volume
* @param[in] key_type the type of the key
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] kms the name of the KMS plugin, or NULL if no KMS is bound
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_create_info_file(struct keystore *keystore,
const char *name,
@@ -1746,6 +1898,8 @@ static int _keystore_create_info_file(struct keystore *keystore,
size_t sector_size,
const char *volume_type,
const char *key_type,
bool gen_passphrase,
const char *passphrase_file,
const char *kms)
{
struct properties *key_props = NULL;
@@ -1758,12 +1912,24 @@ static int _keystore_create_info_file(struct keystore *keystore,
if (rc != 0)
return rc;
if (gen_passphrase || passphrase_file != NULL) {
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
NULL : passphrase_file,
filenames, key_props, true);
if (rc != 0) {
pr_verbose(keystore, "Failed to set the passphrase: %s",
strerror(-rc));
goto out;
}
}
rc = _keystore_ensure_vp_exists(keystore, filenames, key_props);
if (rc != 0) {
warnx("Failed to generate the key verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
remove(filenames->pass_filename);
goto out;
}
@@ -1772,12 +1938,14 @@ static int _keystore_create_info_file(struct keystore *keystore,
pr_verbose(keystore,
"Key info file '%s' could not be written: %s",
filenames->info_filename, strerror(-rc));
remove(filenames->pass_filename);
goto out;
}
rc = _keystore_set_file_permission(keystore, filenames->info_filename);
if (rc != 0) {
remove(filenames->info_filename);
remove(filenames->pass_filename);
goto out;
}
@@ -1809,6 +1977,9 @@ out:
* if NULL, the secure key is generated by random.
* @param[in] volume_type the type of volume
* @param[in] key_type the type of the key
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] pkey_fd the file descriptor of /dev/pkey
*
* @returns 0 for success or a negative errno in case of an error
@@ -1818,9 +1989,10 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
const char *apqns, bool noapqncheck,
size_t sector_size, size_t keybits, bool xts,
const char *clear_key_file, const char *volume_type,
const char *key_type, int pkey_fd)
const char *key_type, bool gen_passphrase,
const char *passphrase_file, int pkey_fd)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
char **apqn_list = NULL;
int rc;
@@ -1880,7 +2052,8 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
rc = _keystore_create_info_file(keystore, name, &file_names,
description, volumes, apqns,
noapqncheck, sector_size, volume_type,
key_type, NULL);
key_type, gen_passphrase,
passphrase_file, NULL);
if (rc != 0)
goto out_free_props;
@@ -1921,6 +2094,9 @@ out_free_key_filenames:
* @param[in] xts if true, an XTS key is generated
* @param[in] volume_type the type of volume
* @param[in] key_type the type of the key (can be NULL)
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] kms_options an array of KMS options specified, or NULL if no
* KMS options have been specified
* @param[in] num_kms_options the number of options in above array
@@ -1931,10 +2107,11 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
size_t sector_size, size_t keybits, bool xts,
const char *volume_type, const char *key_type,
bool gen_passphrase, const char *passphrase_file,
struct kms_option *kms_options,
size_t num_kms_options)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
struct kms_info *kms_info;
char *apqns = NULL;
@@ -2000,8 +2177,21 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
if (rc != 0)
goto out_free_key_filenames;
if (gen_passphrase || passphrase_file != NULL) {
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
NULL : passphrase_file,
&file_names, key_props, true);
if (rc != 0) {
pr_verbose(keystore, "Failed to set the passphrase: %s",
strerror(-rc));
goto out_free_key_filenames;
}
}
rc = generate_kms_key(kms_info, name, key_type, key_props, xts,
keybits, file_names.skey_filename,
_keystore_passphrase_file_exists(&file_names) ?
file_names.pass_filename : NULL,
kms_options, num_kms_options, keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to generate key '%s': %s",
@@ -2048,8 +2238,10 @@ out_del_info_file:
out_free_props:
if (key_props != NULL)
properties_free(key_props);
if (rc != 0)
if (rc != 0) {
remove(file_names.skey_filename);
remove(file_names.pass_filename);
}
out_free_key_filenames:
_keystore_free_key_filenames(&file_names);
if (apqns != NULL)
@@ -2081,6 +2273,9 @@ out_free_key_filenames:
* default is used.
* @param[in] import_file The name of a secure key containing the key to import
* @param[in] volume_type the type of volume
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] lib the external library struct
*
* @returns 0 for success or a negative errno in case of an error
@@ -2089,9 +2284,10 @@ int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
struct ext_lib *lib)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
size_t secure_key_size;
const char *key_type;
@@ -2206,7 +2402,8 @@ int keystore_import_key(struct keystore *keystore, const char *name,
rc = _keystore_create_info_file(keystore, name, &file_names,
description, volumes, apqns,
noapqncheck, sector_size, volume_type,
key_type, NULL);
key_type, gen_passphrase,
passphrase_file, NULL);
if (rc != 0)
goto out_free_props;
@@ -2256,23 +2453,33 @@ out_free_key_filenames:
* not be changed.
* @param[in] volume_type the type of volume. If NULL then the volume type is
* not changed.
* *
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] remove_passphrase if true, remove the (dummy) passphrase
* @param[in] quiet if true no confirmation prompt is shown when removing
* a (dummy) passphrase
*
* @returns 0 for success or a negative errno in case of an error
*
*/
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck,
long int sector_size, const char *volume_type)
long int sector_size, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
bool remove_passphrase, bool quiet)
{
struct volume_check vol_check = { .keystore = keystore, .name = name,
.set = 0, .nocheck = 0 };
struct apqn_check apqn_check = { .noonlinecheck = noapqncheck,
.nomsg = 0 };
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
const char **passphrase_upd = NULL;
char *upd_volume_type = NULL;
char *apqns_prop, *key_type;
const char *null_ptr = NULL;
char *upd_volumes = NULL;
size_t secure_key_size;
u8 mkvp[MKVP_LENGTH];
@@ -2401,6 +2608,38 @@ int keystore_change_key(struct keystore *keystore, const char *name,
upd_volume_type = properties_get(key_props,
PROP_NAME_VOLUME_TYPE);
/* Remove dummy passphrase if change to PLAIN volume type */
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0 &&
_keystore_passphrase_file_exists(&file_names)) {
rc = _keystore_remove_passphrase(keystore, name,
&file_names, key_props,
false);
if (rc != 0)
goto out;
passphrase_upd = &null_ptr;
}
}
if (gen_passphrase || passphrase_file != NULL) {
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
NULL : passphrase_file,
&file_names, key_props, true);
if (rc != 0)
goto out;
passphrase_upd = (const char **)&file_names.pass_filename;
}
if (remove_passphrase) {
if (_keystore_passphrase_file_exists(&file_names))
passphrase_upd = &null_ptr;
rc = _keystore_remove_passphrase(keystore, name, &file_names,
key_props, !quiet);
if (rc != 0)
goto out;
}
if (kms_bound) {
@@ -2412,7 +2651,7 @@ int keystore_change_key(struct keystore *keystore, const char *name,
description, upd_volumes,
upd_volume_type, sector_size >= 0 ?
sect_size : NULL,
keystore->verbose);
passphrase_upd, keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to set key properties "
"for key '%s': %s",
@@ -2441,6 +2680,8 @@ int keystore_change_key(struct keystore *keystore, const char *name,
pr_verbose(keystore, "Successfully changed key '%s'", name);
out:
if (rc != 0 && passphrase_upd != NULL && *passphrase_upd != NULL)
remove(*passphrase_upd);
_keystore_free_key_filenames(&file_names);
if (key_props != NULL)
properties_free(key_props);
@@ -2467,10 +2708,11 @@ out:
int keystore_rename_key(struct keystore *keystore, const char *name,
const char *newname)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames new_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct key_filenames new_names = { 0 };
struct properties *key_props = NULL;
bool reenc_exists = false;
bool pass_exists = false;
char *msg;
int rc;
@@ -2516,6 +2758,16 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
goto out_rename_info;
}
}
if (_keystore_passphrase_file_exists(&file_names)) {
pass_exists = true;
if (rename(file_names.pass_filename,
new_names.pass_filename) != 0) {
rc = -errno;
pr_verbose(keystore, "Failed to rename '%s': %s",
file_names.pass_filename, strerror(-rc));
goto out_rename_info;
}
}
key_props = properties_new();
rc = properties_load(key_props, new_names.info_filename, 1);
@@ -2531,7 +2783,7 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
rc = set_kms_key_properties(keystore->kms_info, key_props,
newname, NULL, NULL, NULL, NULL,
keystore->verbose);
NULL, keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to set key properties "
"for key '%s': %s",
@@ -2549,6 +2801,16 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
_keystore_msg_for_volumes(msg, key_props, VOLUME_TYPE_PLAIN);
free(msg);
if (_keystore_passphrase_file_exists(&new_names)) {
util_asprintf(&msg, "The following volumes are associated with "
"the renamed key '%s'. You should adjust the "
"corresponding crypttab entries to use the new "
"dummy passphrase file name '%s'.", newname,
new_names.pass_filename);
_keystore_msg_for_volumes(msg, key_props, VOLUME_TYPE_LUKS2);
free(msg);
}
pr_verbose(keystore, "Successfully renamed key '%s' to '%s'", name,
newname);
@@ -2557,6 +2819,8 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
out_rename_info:
if (reenc_exists)
rename(file_names.renc_filename, new_names.renc_filename);
if (pass_exists)
rename(file_names.pass_filename, new_names.pass_filename);
rename(new_names.info_filename, file_names.info_filename);
out_rename_skey:
@@ -2613,6 +2877,8 @@ static struct util_rec *_keystore_setup_record(bool validation)
util_rec_def(rec, REC_KMS, UTIL_REC_ALIGN_LEFT, 54, REC_KMS);
util_rec_def(rec, REC_KMS_KEY_LABEL, UTIL_REC_ALIGN_LEFT, 54,
REC_KMS_KEY_LABEL);
util_rec_def(rec, REC_PASSPHRASE_FILE, UTIL_REC_ALIGN_LEFT, 54,
REC_PASSPHRASE_FILE);
util_rec_def(rec, REC_CREATION_TIME, UTIL_REC_ALIGN_LEFT, 54,
REC_CREATION_TIME);
util_rec_def(rec, REC_CHANGE_TIME, UTIL_REC_ALIGN_LEFT, 54,
@@ -2629,7 +2895,8 @@ static void _keystore_print_record(struct util_rec *rec,
bool validation, const char *skey_filename,
size_t secure_key_size, bool is_xts,
size_t clear_key_bitsize, bool valid,
bool is_old_mk, bool reenc_pending, u8 *mkvp)
bool is_old_mk, bool reenc_pending, u8 *mkvp,
const char *pass_filename)
{
char temp_vp[VERIFICATION_PATTERN_LEN + 2];
char *kms_xts_key1_label = NULL;
@@ -2767,6 +3034,10 @@ static void _keystore_print_record(struct util_rec *rec,
label_argz_len);
else
util_rec_set(rec, REC_KMS_KEY_LABEL, "(local)");
if (pass_filename != NULL)
util_rec_set(rec, REC_PASSPHRASE_FILE, pass_filename);
else
util_rec_set(rec, REC_PASSPHRASE_FILE, "(none)");
util_rec_set(rec, REC_CREATION_TIME, creation);
util_rec_set(rec, REC_CHANGE_TIME,
change != NULL ? change : "(never)");
@@ -2966,7 +3237,9 @@ static int _keystore_process_validate(struct keystore *keystore,
is_xts_key(secure_key, secure_key_size),
clear_key_bitsize, valid, is_old_mk,
_keystore_reencipher_key_exists(file_names),
mkvp);
mkvp,
_keystore_passphrase_file_exists(file_names) ?
file_names->pass_filename : NULL);
if (valid && is_old_mk) {
util_print_indented("WARNING: The secure key is currently "
@@ -3434,8 +3707,8 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
{
struct volume_check vol_check = { .keystore = keystore, .name = newname,
.set = 0, .nocheck = 0 };
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames new_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct key_filenames new_names = { 0 };
struct properties *key_prop = NULL;
size_t secure_key_size;
bool kms_bound = false;
@@ -3536,7 +3809,6 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
pr_verbose(keystore,
"Key info file '%s' could not be written: %s",
new_names.info_filename, strerror(-rc));
remove(new_names.skey_filename);
goto out;
}
@@ -3544,6 +3816,23 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
if (rc != 0)
goto out;
if (_keystore_passphrase_file_exists(&file_names)) {
rc = copy_file(file_names.skey_filename,
new_names.pass_filename, 0);
if (rc != 0) {
pr_verbose(keystore,
"Passphrase file '%s' could not be copied: "
"%s", new_names.pass_filename,
strerror(-rc));
goto out;
}
rc = _keystore_set_file_permission(keystore,
file_names.pass_filename);
if (rc != 0)
goto out;
}
pr_verbose(keystore, "Successfully copied key '%s' to '%s'", name,
newname);
@@ -3551,6 +3840,7 @@ out:
if (rc != 0) {
remove(new_names.skey_filename);
remove(new_names.info_filename);
remove(new_names.pass_filename);
}
_keystore_free_key_filenames(&file_names);
@@ -3576,7 +3866,7 @@ out:
int keystore_export_key(struct keystore *keystore, const char *name,
const char *export_file)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
size_t secure_key_size;
u8 *secure_key;
int rc;
@@ -3675,7 +3965,7 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
bool quiet, struct kms_option *kms_options,
size_t num_kms_options)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
int rc;
@@ -3739,6 +4029,13 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
file_names.renc_filename, strerror(-rc));
}
}
if (_keystore_passphrase_file_exists(&file_names)) {
if (remove(file_names.pass_filename) != 0) {
rc = -errno;
pr_verbose(keystore, "Failed to remove '%s': %s",
file_names.pass_filename, strerror(-rc));
}
}
pr_verbose(keystore, "Successfully removed key '%s'", name);
out:
@@ -3794,7 +4091,9 @@ static int _keystore_display_key(struct keystore *keystore,
is_xts_key(secure_key, secure_key_size),
clear_key_bitsize, 0, 0,
_keystore_reencipher_key_exists(file_names),
NULL);
NULL,
_keystore_passphrase_file_exists(file_names) ?
file_names->pass_filename : NULL);
out:
free(secure_key);
@@ -3910,6 +4209,7 @@ struct crypt_info {
size_t key_file_size,
size_t sector_size,
const char *volume_type,
const char *passphrase_file,
struct crypt_info *info);
};
@@ -3925,6 +4225,7 @@ struct crypt_info {
* @param[in] key_file_size the size of the key file in bytes
* @param[in] sector_size the sector size in bytes or 0 if not specified
* @param[in] volume_type the volume type
* @param[in] passphrase_file the passphrase file name (can be NULL)
* @param[in] info processing info
*
* @returns 0 if successful, a negative errno value otherwise
@@ -3937,6 +4238,7 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
size_t key_file_size,
size_t sector_size,
const char *volume_type,
const char *passphrase_file,
struct crypt_info *info)
{
char *keyfile_opt = NULL, *offset_opt = NULL;
@@ -3957,6 +4259,9 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
if (info->keyfile_size > 0)
util_asprintf(&size_opt, "--keyfile-size %lu ",
info->keyfile_size);
} else if (passphrase_file != NULL) {
util_asprintf(&keyfile_opt, "--key-file '%s' ",
passphrase_file);
}
if (info->tries > 0)
util_asprintf(&tries_opt, "--tries %lu ", info->tries);
@@ -4069,6 +4374,7 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
* @param[in] key_file_size the size of the key file in bytes
* @param[in] sector_size the sector size in bytes or 0 if not specified
* @param[in] volume_type the volume type
* @param[in] passphrase_file the passphrase file name (can be NULL)
* @param[in] info processing info (not used here)
*
* @returns 0 if successful, a negative errno value otherwise
@@ -4082,37 +4388,30 @@ static int _keystore_process_crypttab(struct keystore *UNUSED(keystore),
size_t key_file_size,
size_t sector_size,
const char *volume_type,
const char *passphrase_file,
struct crypt_info *info)
{
char temp[1000];
if (strcasecmp(volume_type, VOLUME_TYPE_PLAIN) == 0) {
if (sector_size > 0) {
sprintf(temp,
"WARNING: volume '%s' is using a sector size "
"of %lu. At the time this utility was "
"developed, systemd's support of crypttab did "
"not support to specify a sector size with "
"plain dm-crypt devices. The generated "
"crypttab entry might or might not work, and "
"might need manual adoptions.", volume,
sector_size);
util_print_indented(temp, 0);
}
sprintf(temp, ",sector-size=%lu", sector_size);
printf("%s\t%s\t%s\tplain,cipher=%s,size=%lu%s\n",
dmname, volume, key_file_name, cipher_spec,
key_file_size * 8, sector_size > 0 ? temp : "");
} else if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) {
printf("%s\t%s\t%s\tluks", dmname, volume,
info->keyfile != NULL ? info->keyfile : "none");
if (info->keyfile != NULL) {
printf("%s\t%s\t%s\tluks", dmname, volume,
info->keyfile);
if (info->keyfile_offset > 0)
printf(",keyfile-offset=%lu",
info->keyfile_offset);
if (info->keyfile_size > 0)
printf(",keyfile-size=%lu", info->keyfile_size);
} else if (passphrase_file != NULL) {
printf("%s\t%s\t%s\tluks", dmname, volume,
passphrase_file);
} else {
printf("%s\t%s\tnone\tluks", dmname, volume);
}
if (info->tries > 0)
printf(",tries=%lu", info->tries);
@@ -4237,7 +4536,10 @@ static int _keystore_process_crypt(struct keystore *keystore,
rc = info->process_func(keystore, vol, dmname,
cipher_spec, file_names->skey_filename,
secure_key_size, sector_size,
volume_type, info);
volume_type,
_keystore_passphrase_file_exists(file_names) ?
file_names->pass_filename : NULL,
info);
if (rc != 0)
break;
}
@@ -4403,7 +4705,7 @@ int keystore_convert_key(struct keystore *keystore, const char *name,
const char *key_type, bool noapqncheck, bool quiet,
int pkey_fd, struct ext_lib *lib)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
u8 output_key[2 * MAX_SECURE_KEY_SIZE];
struct properties *properties = NULL;
int rc, min_level, selected = 1;
@@ -4920,6 +5222,7 @@ struct kms_import {
* @param[in] volumes the associated volumes of the key (can be NULL)
* @param[in] volume_type the volume type of the volume (can be NULL)
* @param[in] sector_size the sector size of the volume (0 means default)
* @param[in] passphrase the passphrase of the key (can be NULL)
* @param[in] addl_info_argz an argz string containing additional KMS plugin
* specific infos to be displayed, or NULL if none.
* @param[in] addl_info_len length of the argz string in addl_info_argz
@@ -4940,12 +5243,13 @@ static int _keystore_process_kms_import(const char *key1_id,
const char *volumes,
const char *volume_type,
size_t sector_size,
const char *passphrase,
const char *UNUSED(addl_info_argz),
size_t UNUSED(addl_info_len),
void *private_data)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct kms_import *import_data = private_data;
struct key_filenames file_names = { 0 };
u8 secure_key[2 * MAX_SECURE_KEY_SIZE];
struct properties *key_props = NULL;
char vp[VERIFICATION_PATTERN_LEN];
@@ -5042,6 +5346,23 @@ prompt_alt_name:
if (rc != 0)
goto out;
if (passphrase != NULL && volume_type != NULL &&
strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) {
rc = store_passphrase_from_base64(passphrase,
file_names.pass_filename,
keystore->verbose);
if (rc != 0) {
pr_verbose(keystore, "Failed to parse passphrase: %s",
strerror(-rc));
goto out;
}
rc = _keystore_set_file_permission(keystore,
file_names.pass_filename);
if (rc != 0)
goto out_remove;
}
rc = properties_set(key_props, xts ? PROP_NAME_KMS_XTS_KEY1_ID :
PROP_NAME_KMS_KEY_ID, key1_id);
if (rc != 0) {
@@ -5267,7 +5588,9 @@ static int _keystore_refresh_kms_key(struct keystore *keystore,
rc = refresh_kms_key(keystore->kms_info, properties,
&description, &cipher, &iv_mode, &volumes,
&volume_type, &sector_size,
file_names->skey_filename, keystore->verbose);
file_names->skey_filename,
file_names->pass_filename,
keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to refresh key '%s': %s",
keystore->kms_info->plugin_name, name, strerror(-rc));
@@ -5277,6 +5600,17 @@ static int _keystore_refresh_kms_key(struct keystore *keystore,
goto out;
}
rc = _keystore_set_file_permission(keystore, file_names->skey_filename);
if (rc != 0)
goto out;
if (_keystore_passphrase_file_exists(file_names)) {
rc = _keystore_set_file_permission(keystore,
file_names->pass_filename);
if (rc != 0)
goto out;
}
if (!refresh_data->refresh_properties)
goto save_props;
@@ -5345,6 +5679,10 @@ save_props:
goto out;
}
rc = _keystore_set_file_permission(keystore, file_names->info_filename);
if (rc != 0)
goto out;
out:
if (rc == 0) {
printf("Successfully refreshed key '%s'\n", name);

View File

@@ -54,12 +54,14 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
const char *apqns, bool noapqncheck,
size_t sector_size, size_t keybits, bool xts,
const char *clear_key_file, const char *volume_type,
const char *key_type, int pkey_fd);
const char *key_type, bool gen_passphrase,
const char *passphrase_file, int pkey_fd);
int keystore_generate_key_kms(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
size_t sector_size, size_t keybits, bool xts,
const char *volume_type, const char *key_type,
bool gen_passphrase, const char *passphrase_file,
struct kms_option *kms_options,
size_t num_kms_options);
@@ -67,12 +69,15 @@ int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
struct ext_lib *lib);
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck,
long int sector_size, const char *volume_type);
long int sector_size, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
bool remove_passphrase, bool quiet);
int keystore_rename_key(struct keystore *keystore, const char *name,
const char *newname);

View File

@@ -40,7 +40,9 @@
#define ENVVAR_ZKEY_KMS_PLUGINS "ZKEY_KMS_PLUGINS"
#define DEFAULT_KMS_PLUGINS "/etc/zkey/kms-plugins.conf"
#define KMS_PLUGIN_LOCATION "/usr/lib64/zkey"
#ifndef KMS_PLUGIN_LOCATION
#error KMS_PLUGIN_LOCATION must be defined
#endif
#define KMS_CONFIG_FILE "kms.conf"
#define KMS_CONFIG_PROP_KMS "kms"
@@ -62,6 +64,7 @@
#define KMS_KEY_PROP_XTS_KEY2_ID "xts-key2-id"
#define KMS_KEY_PROP_XTS_KEY1_LABEL "xts-key1-label"
#define KMS_KEY_PROP_XTS_KEY2_LABEL "xts-key2-label"
#define KMS_KEY_PROP_PASSPHRASE "dummy-passphrase-base64"
#define KMS_REC_LABEL "Key label"
#define KMS_REC_NAME "Name"
@@ -2118,6 +2121,8 @@ static char *_get_system_specific_prop_name(const char *prop_name)
* @param[in] keybits the key bit size (e.g. 128, 196, 256, 0 to use the
* plugin's default)
* @param[in] filename the file name to store the key in
* @param[in] passphrase_file the file name containing the LUKS2 passphrase,
* or NULL if no passphrase is set
* @param[in] kms_options an array of KMS options specified, or NULL if no
* KMS options have been specified
* @param[in] num_kms_options the number of options in above array
@@ -2129,6 +2134,7 @@ static char *_get_system_specific_prop_name(const char *prop_name)
int generate_kms_key(struct kms_info *kms_info, const char *name,
const char *key_type, struct properties *key_props,
bool xts, size_t keybits, const char *filename,
const char *passphrase_file,
struct kms_option *kms_options, size_t num_kms_options,
bool verbose)
{
@@ -2138,12 +2144,13 @@ int generate_kms_key(struct kms_info *kms_info, const char *name,
char key2_label[KMS_KEY_LABEL_SIZE + 1] = { 0 };
char key1_id[KMS_KEY_ID_SIZE + 1] = { 0 };
char key2_id[KMS_KEY_ID_SIZE + 1] = { 0 };
struct kms_property kms_props[12];
struct kms_property kms_props[13];
int xts_mode_prop = -1, rc = 0;
size_t key_size, key_blob_size;
enum kms_key_mode key_mode;
size_t num_kms_props = 0;
char *sys_volumes = NULL;
char *passphrase = NULL;
util_assert(kms_info != NULL, "Internal error: kms_info is NULL");
util_assert(name != NULL, "Internal error: name is NULL");
@@ -2207,6 +2214,19 @@ int generate_kms_key(struct kms_info *kms_info, const char *name,
"XTS-KEY-1");
}
if (passphrase_file != NULL) {
passphrase = read_passphrase_as_base64(passphrase_file,
verbose);
if (passphrase == NULL) {
pr_verbose(verbose, "Failed to read passphrase from "
"file '%s'", passphrase_file);
goto out;
}
ADD_KMS_PROPS(kms_props, num_kms_props, KMS_KEY_PROP_PASSPHRASE,
passphrase);
}
key_mode = xts ? KMS_KEY_MODE_XTS_1 : KMS_KEY_MODE_NON_XTS;
key_blob_size = key_size;
@@ -2331,6 +2351,8 @@ out:
free(sector_size);
if (sys_volumes != NULL)
free(sys_volumes);
if (passphrase != NULL)
free(passphrase);
return rc;
}
@@ -2346,20 +2368,28 @@ out:
* @param[in] volumes the volumes of the key (can be NULL)
* @param[in] vol_type the volume type of the key (can be NULL)
* @param[in] sector_size the sector_size of the key (can be NULL)
* @param[in] passphrase_file an address to a character string containing the
* file name containing the LUKS2 passphrase,
* or NULL if no passphrase is set. If
* passphrase_file itself is NULL, then no change in
* the passphrase property.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error.
*/
int set_kms_key_properties(struct kms_info *kms_info,
struct properties *key_props,
const char *name, const char *description,
const char *volumes, const char *vol_type,
const char *sector_size, bool verbose)
const char *sector_size,
const char **passphrase_file,
bool verbose)
{
char *key1_id = NULL, *key2_id = NULL;
struct kms_property kms_props[10];
struct kms_property kms_props[11];
size_t num_kms_props = 0;
char *sys_volumes = NULL;
char *passphrase = NULL;
char *sys_name = NULL;
bool xts = false;
@@ -2414,6 +2444,22 @@ int set_kms_key_properties(struct kms_info *kms_info,
if (sector_size != NULL)
ADD_KMS_PROPS(kms_props, num_kms_props,
KMS_KEY_PROP_SECTOR_SIZE, sector_size);
if (passphrase_file != NULL) {
/* *passphrase_file is NULL to remove the propoerty */
if (*passphrase_file != NULL) {
passphrase =
read_passphrase_as_base64(*passphrase_file,
verbose);
if (passphrase == NULL) {
pr_verbose(verbose, "Failed to read passphrase"
" from file '%s'", *passphrase_file);
goto out;
}
}
ADD_KMS_PROPS(kms_props, num_kms_props,
KMS_KEY_PROP_PASSPHRASE, passphrase);
}
if (num_kms_props == 0)
goto out;
@@ -2448,6 +2494,8 @@ out:
free(key1_id);
if (key2_id != NULL)
free(key2_id);
if (passphrase != NULL)
free(passphrase);
return rc;
}
@@ -2640,6 +2688,7 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
const char *name, *volumes, *cipher, *iv_mode, *description;
const char *xts_key2_id = NULL, *xts_key2_label = NULL;
const char *xts_key, *volume_type, *temp;
const char *passphrase;
size_t sector_size = 0;
bool xts = false;
@@ -2695,6 +2744,8 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
KMS_KEY_PROP_SECTOR_SIZE);
if (temp != NULL)
sscanf(temp, "%lu", &sector_size);
passphrase = _find_property(properties, num_properties,
KMS_KEY_PROP_PASSPHRASE);
if (process_data->label_filter != NULL) {
if (fnmatch(process_data->label_filter, key_label,
@@ -2728,6 +2779,7 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
xts ? key_bits * 2 : key_bits,
description, cipher, iv_mode,
volumes, volume_type, sector_size,
passphrase,
addl_info_argz, addl_info_len,
process_data->private_data);
}
@@ -2865,6 +2917,7 @@ static int _list_kms_keys_cb(const char *UNUSED(key1_id),
const char *UNUSED(cipher),
const char *UNUSED(iv_mode), const char *volumes,
const char *volume_type, size_t sector_size,
const char *UNUSED(passphrase),
const char *addl_info_argz, size_t addl_info_len,
void *private_data)
{
@@ -3139,6 +3192,7 @@ out:
* @param[out] volume_type on return: the volume_type property
* @param[out] sector_size on return: the sector_size property
* @param[in] filename the file name to store the refreshed key blob in
* @param[in] passphrase_file the file name to store the dummy passphras in
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error.
@@ -3146,7 +3200,8 @@ out:
int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
char **description, char **cipher, char **iv_mode,
char **volumes, char **volume_type, ssize_t *sector_size,
const char *filename, bool verbose)
const char *filename, const char *passphrase_file,
bool verbose)
{
struct kms_property *properties = NULL;
u8 key_blob[2 * MAX_SECURE_KEY_SIZE];
@@ -3239,6 +3294,29 @@ int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
if (str != NULL)
sscanf(str, "%lu", (long unsigned int *)sector_size);
}
if (passphrase_file != NULL && volume_type != NULL &&
*volume_type != NULL && strcasecmp(*volume_type, "luks2") == 0) {
str = _find_property(properties, num_properties,
KMS_KEY_PROP_PASSPHRASE);
if (str != NULL) {
rc = store_passphrase_from_base64(str, passphrase_file,
verbose);
if (rc != 0) {
pr_verbose(verbose,
"Failed to parse passphrase: %s",
strerror(-rc));
goto out;
}
} else {
rc = remove(passphrase_file);
if (rc != 0 && errno != ENOENT) {
pr_verbose(verbose,
"Failed to remove passphrase_file: "
"%s", strerror(errno));
goto out;
}
}
}
key_blob_size = sizeof(key_blob);
memset(key_blob, 0, key_blob_size);

View File

@@ -74,6 +74,7 @@ int get_kms_apqns_for_key_type(struct kms_info *kms_info, const char *key_type,
int generate_kms_key(struct kms_info *kms_info, const char *name,
const char *key_type, struct properties *key_props,
bool xts, size_t keybits, const char *filename,
const char *passphrase_file,
struct kms_option *kms_options, size_t num_kms_options,
bool verbose);
@@ -81,7 +82,9 @@ int set_kms_key_properties(struct kms_info *kms_info,
struct properties *key_props,
const char *name, const char *description,
const char *volumes, const char *vol_type,
const char *sector_size, bool verbose);
const char *sector_size,
const char **passphrase_file,
bool verbose);
int remove_kms_key(struct kms_info *kms_info, struct properties *key_props,
struct kms_option *kms_options, size_t num_kms_options,
@@ -94,6 +97,7 @@ typedef int (*kms_process_callback)(const char *key1_id, const char *key1_label,
const char *description, const char *cipher,
const char *iv_mode, const char *volumes,
const char *volume_type, size_t sector_size,
const char *passphrase,
const char *addl_info_argz,
size_t addl_info_len,
void *private_data);
@@ -118,6 +122,7 @@ int import_kms_key(struct kms_info *kms_info, const char *key1_id,
int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
char **description, char **cipher, char **iv_mode,
char **volumes, char **volume_type, ssize_t *sector_size,
const char *filename, bool verbose);
const char *filename, const char *passphrase_file,
bool verbose);
#endif

View File

@@ -1337,7 +1337,7 @@ int validate_secure_key(int pkey_fd,
int generate_key_verification_pattern(const u8 *key, size_t key_size,
char *vp, size_t vp_len, bool verbose)
{
int tfmfd = -1, opfd = -1, rc = 0;
int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0;
char null_msg[ENC_ZERO_LEN];
char enc_zero[ENC_ZERO_LEN];
struct af_alg_iv *alg_iv;
@@ -1385,12 +1385,30 @@ int generate_key_verification_pattern(const u8 *key, size_t key_size,
goto out;
}
retry_setkey:
if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key,
key_size) < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to set the key");
pr_verbose(verbose, "Failed to set the key: %s",
strerror(-rc));
/*
* After a master key change, it can happen that the setkey
* operation returns EINVAL or EAGAIN, although the key is
* valid. This is a temporary situation and the operation will
* succeed, once the firmware has completed some internal
* processing related with the master key change.
* Delay 1 second and retry up to 10 times.
*/
if ((rc == -EINVAL || rc == -EAGAIN) && retry_count < 10) {
pr_verbose(verbose, "Retrying after 1 second...");
retry_count++;
sleep(1);
goto retry_setkey;
}
goto out;
}
rc = 0;
opfd = accept(tfmfd, NULL, NULL);
if (opfd < 0) {

View File

@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -25,7 +26,8 @@
#include "lib/util_rec.h"
#include "lib/util_base.h"
#include <openssl/crypto.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include "utils.h"
#include "properties.h"
@@ -1128,6 +1130,7 @@ bool prompt_for_yes(bool verbose)
{
char str[20];
fflush(stdout);
if (fgets(str, sizeof(str), stdin) == NULL)
return false;
@@ -1174,3 +1177,199 @@ char *printable_mkvp(enum card_type cardtype, u8 *mkvp)
return mkvp_print_buf;
}
/*
* Copy the contents of one file into another file. If num_bytes is zero,
* then all content until EOF of the input file is copied. Otherwise only up to
* num_bytes is copied.
*
* @param[in] in_file_name the file name of the input file
* @param[in] out_file_name the file name of the output file
* @param[in] num_bytes the number of bytes to copy, or 0 to copy until
* EOF of the input file
*
* @returns zero for success, or a negative error in case of an error
*/
int copy_file(const char *in_file_name, const char *out_file_name,
size_t num_bytes)
{
FILE *fp_in = NULL, *fp_out = NULL;
size_t num = 0, len;
char buff[1024];
int rc = 0;
fp_in = fopen(in_file_name, "r");
if (fp_in == NULL) {
rc = -errno;
warnx("Failed to open '%s': %s", in_file_name, strerror(-rc));
goto out;
}
fp_out = fopen(out_file_name, "w");
if (fp_out == NULL) {
rc = -errno;
warnx("Failed to open '%s': %s", out_file_name, strerror(-rc));
goto out;
}
while (!feof(fp_in) && (num_bytes == 0 || num < num_bytes)) {
len = fread(buff, 1, num_bytes == 0 ? sizeof(buff) :
MIN(num_bytes - num, sizeof(buff)), fp_in);
if (ferror(fp_in)) {
rc = -EIO;
warnx("Failed to read from '%s': %s", in_file_name,
strerror(-rc));
break;
}
if (len == 0)
break;
if (fwrite(buff, len, 1, fp_out) != 1) {
rc = -errno;
warnx("Failed to write to '%s': %s", out_file_name,
strerror(-rc));
break;
}
num += len;
}
out:
if (fp_in != NULL)
fclose(fp_in);
if (fp_out != NULL)
fclose(fp_out);
return rc;
}
/**
* Reads the passphrase from the specified file and returns the passphrase as
* an base64 encoded string. The returned string must be freed by the caller.
*
* @param[in] filename the file name of the file containing the passphrase
* @param[in] verbose if true, additional error messages are printed.
*
* @returns an allocated string
*/
char *read_passphrase_as_base64(const char *filename, bool verbose)
{
unsigned char *ret = NULL, *buf = NULL;
int outlen, len;
struct stat sb;
FILE *fp;
if (stat(filename, &sb) != 0) {
pr_verbose(verbose, "stat on file '%s' failed: %s", filename,
strerror(errno));
return NULL;
}
if (sb.st_size == 0) {
pr_verbose(verbose, "File '%s' is empty", filename);
return NULL;
}
fp = fopen(filename, "r");
if (fp == NULL) {
pr_verbose(verbose, "Open of file '%s' failed: %s", filename,
strerror(errno));
return NULL;
}
buf = malloc(sb.st_size);
if (buf == NULL) {
pr_verbose(verbose, "Malloc failed");
goto out;
}
if (fread(buf, sb.st_size, 1, fp) != 1) {
pr_verbose(verbose, "Reading file '%s' failed: %s", filename,
strerror(errno));
goto out;
}
outlen = (sb.st_size / 3) * 4;
if (sb.st_size % 3 > 0)
outlen += 4;
ret = malloc(outlen + 1);
if (ret == NULL) {
pr_verbose(verbose, "Malloc failed");
goto out;
}
len = EVP_EncodeBlock(ret, buf, sb.st_size);
if (len != outlen) {
pr_verbose(verbose, "EVP_EncodeBlock failed");
free(ret);
ret = NULL;
goto out;
}
ret[outlen] = '\0';
out:
free(buf);
fclose(fp);
return (char *)ret;
}
/**
* Stores the passphrase into the specified file. Decodes the base64 string into
* bytes.
*
* @param[in] b64_string the passphrase as a base64 string
* @param[in] filename the file name of the file containing the passphrase
* @param[in] verbose if true, additional error messages are printed.
*
* @returns 0 for success or a negative errno in case of an error.
*/
int store_passphrase_from_base64(const char *b64_string, const char *filename,
bool verbose)
{
size_t len, outlen, rawlen, i;
unsigned char *buf;
FILE *fp = NULL;
int rc = 0;
len = strlen(b64_string);
rawlen = outlen = (len / 4) * 3;
for (i = len - 1; b64_string[i] == '='; i--, rawlen--)
;
buf = malloc(outlen);
if (buf == NULL) {
pr_verbose(verbose, "Malloc failed");
return -ENOMEM;
}
fp = fopen(filename, "w");
if (fp == NULL) {
pr_verbose(verbose, "Open of file '%s' failed: %s", filename,
strerror(errno));
rc = -EIO;
goto out;
}
len = EVP_DecodeBlock(buf, (unsigned char *)b64_string, len);
if (len != outlen) {
pr_verbose(verbose, "EVP_DecodeBlock failed");
goto out;
}
if (fwrite(buf, rawlen, 1, fp) != 1) {
pr_verbose(verbose, "Writing file '%s' failed: %s", filename,
strerror(errno));
goto out;
}
out:
if (fp != NULL)
fclose(fp);
free(buf);
return rc;
}

View File

@@ -77,4 +77,11 @@ bool prompt_for_yes(bool verbose);
char *printable_mkvp(enum card_type cardtype, u8 *mkvp);
int copy_file(const char *in_file_name, const char *out_file_name,
size_t num_bytes);
char *read_passphrase_as_base64(const char *filename, bool verbose);
int store_passphrase_from_base64(const char *hex_string, const char *filename,
bool verbose);
#endif

View File

@@ -126,6 +126,9 @@ key repository.
.RB [ \-\-key-type | \-K
.IR type ]
.RB [ \-\-local | \-L ]
.RB [ \-\-gen\-dummy\-passphrase ]
.RB [ \-\-set\-dummy\-passphrase
.IR passphrase\-file ]
.RB [ KMS\-plugin\ specific\ options ]
.RB [ \-\-verbose | \-V ]
.PP
@@ -379,6 +382,9 @@ EP11-AES to be installed. For the supported environments and downloads, see:
.IR bytes ]
.RB [ \-\-volume-type | \-t
.IR type ]
.RB [ \-\-gen\-dummy\-passphrase ]
.RB [ \-\-set\-dummy\-passphrase
.IR passphrase\-file ]
.RB [ \-\-verbose | \-V ]
.
.PP
@@ -515,6 +521,11 @@ because the secure key is contained in the LUKS2 header.
.IR bytes ]
.RB [ \-\-volume-type | \-t
.IR type ]
.RB [ \-\-gen\-dummy\-passphrase ]
.RB [ \-\-set\-dummy\-passphrase
.IR passphrase\-file ]
.RB [ \-\-remove\-dummy\-passphrase ]
.RB [ \-\-force | \-F ]
.RB [ \-\-verbose | \-V ]
.
.PP
@@ -661,7 +672,7 @@ option to generate crypttab entries for the specified volume type only.
For LUKS2 volumes, a passphrase is required. You are prompted for the
passphrase during system startup when crypttab is evaluated, unless option
.B \-\-key\-file
is specified. Option
is specified, or a dummy passphrase is associated with the secure key. Option
.B \-\-tries
specifies how often a passphrase can be re-entered. When option
.B \-\-key\-file
@@ -734,7 +745,7 @@ LUKS key slots is of less relevance.
For LUKS2 volumes, a passphrase is required. You are prompted for the
passphrase when running the generated commands, unless option
.B \-\-key\-file
is specified. Option
is specified, or a dummy passphrase is associated with the secure key. Option
.B \-\-tries
specifies how often a passphrase can be re-entered. When option
.B \-\-key\-file
@@ -1236,6 +1247,26 @@ system plugin (KMS plugin) is bound to the secure key repository. If the
repository is bound to a key management system plugin, then keys are generated
using the key management system by default.
.TP
.BR \-\-gen\-dummy\-passphrase
Generate a dummy passphrase randomly and associate it with the secure AES key
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
for the security of the volume(s), when an secure AES key is used to encrypt the
volume(s), and can therefore be stored insecurely inside the secure key
repository. If for a certain usage the passphrase is of relevance for
security, then do not use this option. This option can only be specified for
keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
Set a dummy passphrase that is read from the specified file and associate it
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
is of less or no relevance for the security of the volume(s), when an secure
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
inside the secure key repository. If for a certain usage the passphrase is of
relevance for security, then do not use this option. This option can only be
specified for keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.B KMS-plugin specific options
A key management system plugin may offer and even require plugin specific
options that can be specified with the generate command when the secure key
@@ -1372,6 +1403,26 @@ This option is only available if
has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled,
the default volume type is \fBplain\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-gen\-dummy\-passphrase
Generate a dummy passphrase randomly and associate it with the secure AES key
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
for the security of the volume(s), when an secure AES key is used to encrypt the
volume(s), and can therefore be stored insecurely inside the secure key
repository. If for a certain usage the passphrase is of relevance for
security, then do not use this option. This option can only be specified for
keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
Set a dummy passphrase that is read from the specified file and associate it
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
is of less or no relevance for the security of the volume(s), when an secure
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
inside the secure key repository. If for a certain usage the passphrase is of
relevance for security, then do not use this option. This option can only be
specified for keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.
.
.
@@ -1523,6 +1574,47 @@ This option is only available if
.B zkey
has been compiled with LUKS2 support enabled.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-gen\-dummy\-passphrase
Generate a dummy passphrase randomly and associate it with the secure AES key
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
for the security of the volume(s), when an secure AES key is used to encrypt the
volume(s), and can therefore be stored insecurely inside the secure key
repository. If for a certain usage the passphrase is of relevance for
security, then do not use this option. This option can only be specified for
keys with a volume type of \fBluks2\fP. When there is already a dummy
passphrase associated with the key, you muts first remove the dummy passphrase
with option \fB\-\-remove\-dummy\-passphrase\fP before you can associate a new
dummy passphrase.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
Set a dummy passphrase that is read from the specified file and associate it
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
is of less or no relevance for the security of the volume(s), when an secure
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
inside the secure key repository. If for a certain usage the passphrase is of
relevance for security, then do not use this option. This option can only be
specified for keys with a volume type of \fBluks2\fP. When there is already a
dummy passphrase associated with the key, you muts first remove the dummy
passphrase with option \fB\-\-remove\-dummy\-passphrase\fP before you can
associate a new dummy passphrase.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-remove\-dummy\-passphrase
Remove the associated dummy passphrase used with LUKS2 volume(s).
The user is prompted to confirm the removal of the associated dummy passphrase.
Use the \fB\-\-force\fP option to remove the associated dummy passphrase without
prompting for a confirmation.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-F ", " \-\-force\fP
The user is prompted to confirm the removal of the associated dummy passphrase.
Use this option to remove the associated dummy passphrase without prompting for
a confirmation.
This option is only used for secure keys contained in the secure key repository,
and can only be specified together with option
\fB\-\-remove\-dummy\-passphrase\fP.
.
.
.
@@ -1590,8 +1682,9 @@ has been compiled with LUKS2 support enabled.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-key\-file\~\fIfile\-name\fP
Reads the passphrase from the specified file. If this option is omitted, then
you are prompted to enter the passphrase interactively during system startup.
Reads the passphrase from the specified file. If this option is omitted, and
no dummy passphrase is associated with the secure key, then you are prompted to
enter the passphrase interactively during system startup.
This option is passed to the generated crypttab entries for LUKS2 volumes, and
is only available if
.B zkey
@@ -1677,10 +1770,11 @@ option, and is only available if
has been compiled with LUKS2 support enabled.
.TP
.BR \-\-key\-file\~\fIfile\-name\fP
Reads the passphrase from the specified file. If this option is omitted,
or if the file\-name is \fI-\fP (a dash), then you are prompted to enter the
passphrase interactively. This option is passed to the generated command(s)
for LUKS2 volumes, and is only available if
Reads the passphrase from the specified file. If this option is omitted, and
no dummy passphrase is associated with the secure key, or if the file\-name is
\fI-\fP (a dash), then you are prompted to enter the passphrase interactively.
This option is passed to the generated command(s) for LUKS2 volumes, and is
only available if
.B zkey
has been compiled with LUKS2 support enabled.
.TP

View File

@@ -79,6 +79,9 @@ static struct zkey_globals {
char *key_type;
char *label;
bool local;
bool gen_passphrase;
char *passphrase_file;
bool remove_passphrase;
bool kms_bound;
bool run;
bool batch_mode;
@@ -156,6 +159,9 @@ static struct zkey_globals {
#define OPT_NO_APQN_CHECK 262
#define OPT_NO_VOLUME_CHECK 263
#define OPT_REFRESH_PROPERTIES 264
#define OPT_GEN_DUMMY_PASSPHRASE 265
#define OPT_SET_DUMMY_PASSPHRASE 266
#define OPT_REMOVE_DUMMY_PASSPHRASE 267
/*
* Configuration of command line options
@@ -271,6 +277,31 @@ static struct util_opt opt_vec[] = {
"generated by the KMS per default.",
.command = COMMAND_GENERATE,
},
{
.option = { "gen-dummy-passphrase", 0, NULL,
OPT_GEN_DUMMY_PASSPHRASE},
.desc = "Generate a dummy passphrase and associate it with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_GENERATE,
},
{
.option = { "set-dummy-passphrase", required_argument, NULL,
OPT_SET_DUMMY_PASSPHRASE},
.argument = "passphrase-file",
.desc = "Set a dummy passphrase to be associated with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_GENERATE,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -429,6 +460,31 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_IMPORT,
},
#endif
{
.option = { "gen-dummy-passphrase", 0, NULL,
OPT_GEN_DUMMY_PASSPHRASE},
.desc = "Generate a dummy passphrase and associate it with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_IMPORT,
},
{
.option = { "set-dummy-passphrase", required_argument, NULL,
OPT_SET_DUMMY_PASSPHRASE},
.argument = "passphrase-file",
.desc = "Set a dummy passphrase to be associated with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_IMPORT,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -593,6 +649,45 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_CHANGE,
},
#endif
{
.option = { "gen-dummy-passphrase", 0, NULL,
OPT_GEN_DUMMY_PASSPHRASE},
.desc = "Generate a dummy passphrase and associate it with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_CHANGE,
},
{
.option = { "set-dummy-passphrase", required_argument, NULL,
OPT_SET_DUMMY_PASSPHRASE},
.argument = "passphrase-file",
.desc = "Set a dummy passphrase to be associated with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_CHANGE,
},
{
.option = { "remove-dummy-passphrase", 0, NULL,
OPT_REMOVE_DUMMY_PASSPHRASE},
.desc = "Remove an associated dummy passphrase used with LUKS2 "
"volume(s).",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_CHANGE,
},
{
.option = {"force", 0, NULL, 'F'},
.desc = "Do not prompt for a confirmation when removing an "
"associated dummy passphrase",
.command = COMMAND_CHANGE,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -1631,6 +1726,14 @@ static int command_generate_repository(void)
if (g.sector_size < 0)
g.sector_size = 0;
if (g.gen_passphrase && g.passphrase_file != NULL) {
warnx("Either '--gen-dummy-passphrase' or "
"'--set-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.kms_info.plugin_lib != NULL && !g.local) {
if (g.apqns != NULL) {
warnx("Option '--apqns|-a' is not valid for "
@@ -1655,6 +1758,8 @@ static int command_generate_repository(void)
g.description, g.volumes,
g.sector_size, g.keybits, g.xts,
g.volume_type, g.key_type,
g.gen_passphrase,
g.passphrase_file,
g.kms_options,
g.num_kms_options);
goto out;
@@ -1666,7 +1771,8 @@ static int command_generate_repository(void)
rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.noapqncheck, g.sector_size,
g.keybits, g.xts, g.clearkeyfile,
g.volume_type, g.key_type, g.pkey_fd);
g.volume_type, g.key_type, g.gen_passphrase,
g.passphrase_file, g.pkey_fd);
out:
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
@@ -1729,6 +1835,18 @@ static int command_generate(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase) {
warnx("Option '--gen-dummy-passphrase' is not valid "
"for generating a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.passphrase_file != NULL) {
warnx("Option '--sen-dummy-passphrase' is not valid "
"for generating a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = cross_check_apqns(NULL, NULL,
get_min_card_level_for_keytype(g.key_type),
@@ -2111,10 +2229,19 @@ static int command_import(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase && g.passphrase_file != NULL) {
warnx("Either '--gen-dummy-passphrase' or "
"'--set-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.noapqncheck, g.sector_size,
g.pos_arg, g.volume_type, &g.lib);
g.pos_arg, g.volume_type, g.gen_passphrase,
g.passphrase_file, &g.lib);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -2200,10 +2327,39 @@ static int command_change(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase && g.passphrase_file != NULL) {
warnx("Either '--gen-dummy-passphrase' or "
"'--set-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase && g.remove_passphrase) {
warnx("Either '--gen-dummy-passphrase' or "
"'--remove-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.passphrase_file != NULL && g.remove_passphrase) {
warnx("Either '--set-dummy-passphrase' or "
"'--remove-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.force && !g.remove_passphrase) {
warnx("Option '--force|-F' is only valid together with "
"the '--remove-dummy-passphrase' option");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.noapqncheck, g.sector_size,
g.volume_type);
g.volume_type, g.gen_passphrase,
g.passphrase_file, g.remove_passphrase,
g.force);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -3056,6 +3212,15 @@ int main(int argc, char *argv[])
case 'P':
g.refresh_properties = 1;
break;
case OPT_GEN_DUMMY_PASSPHRASE:
g.gen_passphrase = 1;
break;
case OPT_SET_DUMMY_PASSPHRASE:
g.passphrase_file = optarg;
break;
case OPT_REMOVE_DUMMY_PASSPHRASE:
g.remove_passphrase = 1;
break;
case 'h':
print_help(command, sub_command);
return EXIT_SUCCESS;