Compare commits

..

172 Commits

Author SHA1 Message Date
Steffen Eiden
9eea78b3ad New release s390-tools-2.32.0
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-03 16:18:09 +02:00
Steffen Eiden
0a3a556879 rust/Cargo.lock: Update curl-sys crate
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-03 16:18:09 +02:00
Steffen Eiden
aba8900074 rust/pv_core: Remove mockito dependency
With f6c6f0cc71 ("rust/pv/test: Code + Certificate refactoring")
no code uses mockito anymore, but it's dependency was not removed.

Remove the mockito dependency from the rust workspace.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-03 16:18:09 +02:00
Dan Horák
f5744b95db genprotimg: Fix build with OpenSSL 1.1
OpenSSL 1.1 seems to use a non-const parameter to X509_name_dup(), but
x509_armonk_locality_fixup() is passing a const there. The compile then
fails on "discards 'const' qualifier", when -Werror is used. Thus
resolve with a type-cast like in c2b_name().

Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/167
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Dan Horák
13d721afd3 libpv: Fix build with OpenSSL 1.1
OpenSSL 1.1 seems to use a non-const parameter to X509_name_dup(), but
x509_armonk_locality_fixup() is passing a const there. The compile then
fails on "discards 'const' qualifier", when -Werror is used. Thus
resolve with a type-cast like in pv_c2b_name().

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/167
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Eduard Shishkin
90a2e6d70e zipl/src: Fix leak of files
Fix leak of temporary files: if prepare_build_program_table_file()
is called in no dry-run mode and there was an error then the file
@filename will not be deleted in free_bootloader()).

Fix leak of renamed files as well as corruption of previously
created bootmap files with the same name in case of unsuccessful
IPL installation.

Add a special flag to keep a track of file's "temporary" state;
Base the cleanup decision on this flag instead of checking dry-run;
Release resources captured by prepare_bootloader() in the error path;
Move the final rename to be called only after successful installation.

                    Original logic:

prepare_bootloader_ipl():
prepare_bootloader_ngdump():

  always create temporary @filename
  if (!dry-run) rename @filename;
  install;
  cleanup: if (dry_run) drop @filename (*** LEAK ***)

prepare_bootloader_device():

  if (dry_run) create temporary @filename
  install, don't rename;
  cleanup: if (dry_run) drop @filename

                    New logic:

prepare_bootloader_ipl():
prepare_bootloader_ngdump():

  always create temporary @filename and set @tmp_filename_created;
  install;
  if (!dry_run) rename @filename and clear @tmp_filename_created;
  cleanup: if (@tmp_filename_created is set), drop @filename

prepare_bootloader_device():

  if (dry_run) create @filename and set @tmp_filename_created;
  install, don't rename;
  cleanup: if (@tmp_filename_created is set) drop @filename.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/165
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Marc Hartmayer
bc9f8a8100 genprotimg: Fix out-of-disk space handling
Convert the assertion to a GError since an out-of-disk-space situation
is a valid situation that should be handled.

ERROR:utils/crypto.c:1843:__encrypt_decrypt_bio: assertion failed: (num_bytes_written == out_len)
Bail out! ERROR:utils/crypto.c:1843:__encrypt_decrypt_bio: assertion failed: (num_bytes_written == out_len)

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Steffen Eiden
2b5e7b0491 pvattest: Fix root-ca parsing
The parser setup falsely set the argument type as filename array, but
code expected a single filename. Fixed by setting up the parser
correctly to expect a single file name.

Fixes: 3ab06d77fb ("pvattest: Create, perform, and verify attestation measurements")
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Steffen Eiden
d7c95265cd libpv: Support Armonk in IBM signing key subject
New IBM signing keys will have Armonk as locality in the subject.
Ensure that CRLs with Poughkeepsie as issuer locality are still
discovered if they are signed with the signing keys private key.
Also, drop the check for issuer/subject comparison and only rely on
validity period and cryptographic signatures.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
8751cfc409 genprotimg/samples/check_hostkeydoc: code formatting
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
01f96d30f6 genprotimg/samples/check_hostkeydoc: fix ShellCheck findings
Fix ShellCheck findings and two typos. White spaces in filenames are now
supported properly.

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
fffbd93f12 genprotimg/samples/check_hostkeydoc: improve argument parsing
+ use `getopts` POSIX builtin instead of external program
+ improve error reporting
+ support white spaces in the script name

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
ddcfbdc8d2 genprotimg/samples/check_hostkeydoc: support Armonk in IBM signing key subject
Newer IBM signing keys use `Armonk` in their subject therefore add
support for it.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
173fd7cdca genprotimg/samples/check_hostkeydoc: set LC_ALL=C for the sort command
Set `LC_ALL=C` for the `sort` command to get a stable sort order. See
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sort.html for
details on the effect of LC_* on `sort`. Adapt the default issuer
accordingly.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
d14e7593cc genprotimg: support Armonk in IBM signing key subject
New IBM signing certificates will have 'Armonk' as locality in the
subject. Make sure that certificate revocations lists (CRL) with
'Poughkeepsie' as issuer locality are still considered as valid as long
as they are signed with the IBM signing keys private key. In addition,
drop the check for 'issuer(HKD) == subject(HKSK)' as it doesn't improve
security. While at it, remove now unused functions and fix a memory leak
of @akid in `check_crl_issuer`.

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Steffen Eiden
1a3d0b74f7 rust/pv: Support Armonk in IBM signing key subject
New IBM signing keys will have Armonk as locality in the subject.
Ensure that CRLs with Poughkeepsie as issuer locality are still
discovered if they are signed with the signing keys private key.
Also, drop the check for issuer/subject comparison and only rely on
validity period and cryptographic signatures.

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
f6c6f0cc71 rust/pv/test: Code + Certificate refactoring
* Get rid of Mockito
* create certs with AKID
* simplify things in the `create_certs.py` script

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Thomas Richter
966e67a252 cpumf/lscpumf: add support for machine type 3932
Add support for machine type 3932 and list the
CPU Measurement facility counter sets.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Joern Siglen
1c128c0d11 dbginfo.sh: dash compatible copy sequence
rewrite the copy of dbginfo.sh for dash compatibility

Reviewed-by: Mike Storzer <MSTORZER@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
VasiliyS
a3199d58db rust/pv_core: Fix UvDeviceInfo::get() method.
`ATTESTATION_NR` flag was not set properly in case the device
didn't support `Info` IOCTL call.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/163
Signed-off-by: Vasiliy Suvorov <vsuvorov@gmail.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Vineeth Vijayan
659483031e zdev: Rearrange the options alphabetically in man page
re-arrange options in zdev manpages in the alphabetical order.

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:43 +01:00
Ingo Franzki
7dc2513205 zkey: Detect FIPS mode and generate PBKDF for luksFormat according to it
For LUKS2 volumes, zkey generates 'cryptsetup luksFormat' commands with
options '--pbkdf argon2i --pbkdf-memory 32 --pbkdf-force-iterations 4'
for low memory and time requirements. Using the default Argon2i options
might cause out-of-memory errors when multiple encrypted volumes are
unlocked automatically at boot through /etc/crypttab.

When the system runs in FIPS mode, which is indicated by file
/proc/sys/crypto/fips_enabled containing '1', the Argon2i password based
key derivation function might be disabled by a policy, and such
'cryptsetup luksFormat' commands might fail.

Generate '--pbkdf pbkdf2' instead if the system runs in FIPS mode.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:43 +01:00
Marc Hartmayer
0748d365a6 genprotimg/**/Makefile: Fix staged installs
Fix the support for staged installs. The Makefile variable `PKGDATADIR`
uses `DESTDIR` for all Makefile target, but actually it should only be
used for the `install*` and `uninstall*` targets. [1] Fix this by using
`DESTDIR` only for `install*` targets - uninstall* targets are not
supported by s390-tools.

Before this change, if `DESTDIR` was set for staged installs,
`genprotimg` has tried to find the bootloader binaries at the temporary
installation path `$DESTDIR$(TOOLS_DATADIR)/genprotimg/` instead of
`$(TOOLS_DATADIR)/genprotimg`.

[1] https://www.gnu.org/prep/standards/html_node/DESTDIR.html

Fixes: 65b9fc442c ("genprotimg: introduce new tool for the creation of PV images")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:38 +01:00
Marc Hartmayer
94a404ed10 pvattest: Makefile: Remove unused variable and CFLAGS
Remove unused variables and unused compiler flags.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Thomas Richter
ef1799f31f s390-tools/libutil: Add machine type 3932
Add support for machine type 3932.
Print identical product name for machine types 8561 and 8562.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
47b0960cc7 zdump: Make ngdump_get_part_path() public
Make ngdump_get_part_path() public in order for unit-tests to access it.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
2288331a6f zipl: Clear CCW-type DASD dumper upon ldipl-dump tool installation
Clear CCW-type DASD standalone dumper (if installed on the DASD) upon
successful installation of the List-Directed ECKD dump tool on the same
device. This helps to avoid 'zgetdump -d' confusion and have only one
'active' dump tool per disk.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
23e9156f43 s390_dump.h: Add DF_S390_DUMPER_MAGIC_SIZE constant
Add DF_S390_DUMPER_MAGIC_SIZE constant to s390_dump.h.
Use it instead of hardcoded length when processing dumper magics
in zgetdump code.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
8f99e7c4ea zdump: Move DUMPER_MAGIC constants to include/dump/s390_dump.h
Move DUMPER_MAGIC constants from df_s390.h to the global header
include/dump/s390_dump.h in order to reuse it in zipl code.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
f3bcd94524 zdump: Add zgetdump -d support for ECKD ldipl-dump
Make 'zgetdump -d' to identify ldipl-dump tool (ngdump) installed on DASD
volume just like it does for NVMe ngdump.

Output sample:
-------------
Dump device info:
  Dump tool.........: Next Generation (NGDump) dump tool
  Version...........: 1
  Architecture......: s390x (64 bit)

Partition info:
  Partition number..: 2

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
a2f8b19c2a dumpconf: Update the man page and etc/sysconfig/dumpconf template
Update dumpconf man page with list-directed ECKD dump information (new
attributes and configuration example for ECKD LDIPL dump).
Update etc/sysconfig/dumpconf with list-directed ECKD dump configuration
example.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
588d720517 dumpconf: Process br_chr and bootprog eckd attributes
- Write the following sysfs attributes for list-directed ECKD devices
  introducing setup_eckd_device() function.
    br_chr: location of boot record
    bootprog: boot program selector
- Remove redundant parameters from setup_ccw_device() and setup_fcp_device()
  functioins.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Ingo Franzki
cd822cb770 zkey: Fix convert command to accept only keys of type CCA-AESDATA
Reject conversion of other key types with a proper error message.
Also fix a typo in another error message of the convert command.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Ingo Franzki
b27b8e3cd3 zkey: Fix typos in error message
Use a colon instead of a semicolon in the message.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Steffen Maier
7a2c5dc980 zdev/dracut: Fix file mode of non-executable shell library zdev-lib.sh
Use similar `install` mode option in Makefile as in commit
9b2fb1d4d2 ("zdev: add helper to convert from dasd_mod.dasd to zdev
config").

Fixes: 73c46a3056 ("zdev/dracut: fix kdump by only activating required devices")
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:28 +01:00
Jan Höppner
d9e3763d1c Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 17:49:44 +01:00
Jan Höppner
6f15ed3264 New release s390-tools-2.31.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 17:49:44 +01:00
Joern Siglen
0d2b5af007 dbginfo.sh: check for DPM mode
check if the LPAR is running in DPM mode and reflect this in the summary.

Suggested-by: Mike Storzer <MSTORZER@de.ibm.com>
Acked-by: Eberhard Pasch <epasch@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Jan Höppner
9e7a8f48e8 common.mak: Set default C/C++ standard to gnu11/gnu++11
s390-tools doesn't define a common C/C++ standard at the moment.
Set the standard to gnu11/gnu++11, which is also used by the Kernel, and
establish a common baseline for all tools.

The -std flag is added to ALL_CFLAGS and ALL_CXXFLAGS to avoid losing it
in case CFLAGS are set by an outside entity.
It is also added to CLAGS_FOR_BUILD for this one special cross build
case.

The -std flag is removed from all tools that set it manually until now.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
98f7a0569c rust/pvsecret: User defined signatures and verifications
Introduces the ability to `pvsecret` to add a signature (ecdsa or rsa)
to the program-reserved space (user-data) of an add-secret request
during the request creation. Additionally, some arbitrary data may be
inserted.

The new command `verify` checks if add-secret requests are sane (e.g.
start with the correct magic value). If the request contains a
user-signature `verify` will also verify this signature.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
551f66282e rust/pvsecret: Streamline man and README
Makes the source for the manfiles&README more readable. Fixes some nits
like double spaces, unnessecary indentations, line breaks, ...
Removes pvsecret-version.1 as this command maps to the --version
option.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
3d2ba5aaed rust/pvsecret: Sync man and help
The output of --help and man pages got out of sync.
Apply changes to the help output to fix this.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
94942a48ab rust/pv: Add function to read a private key
Add a function to read a private key in PEM or DER format.

While at it, fix some documentation issues in read_{certs, crls}.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
ab8984a7a3 rust/pv: Remove unused functions
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Marc Hartmayer
4990f643c1 rust/pv: Add-Secret: Add user-data and user-defined signing keys
User-data can be added to add-secret requests. User-data can be unsigned
or containing a signature of the request using a custom private key.

The user-data is placed at offset 0x218 and 0x200 bytes long.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
34bef977e8 rust/pv: User-data signing and verifying
Add the ability to generate signed user-data and to verify the
signature.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
f36c34038b rust/pv: Add-Secret: Add user-data types
Add four new user-data types an add-secret request could have:
Unsigned, Signed(EcSECP521R1, Rsa(2048, 3072))

As the user-data enum was not marked as non-exaustive this might be a
breaking change for users. (Not for any crate in this repo though).

The addition of such user-data is provided by following patches.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:22 +01:00
Steffen Eiden
bfd0e12d22 rust/pv: Signing messages
Adds the ability to sign and verify messages using ECDH or RSA keys.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
1450f85ada rust/pv: Fix documentation issue
Add the missing plaintext flags to the request description.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Marc Hartmayer
2a0f1e6977 pvsecret: improve warning if host key document contains multiple certificates
Improve the warning for the case where a host key document contains
multiple certificates (only possible for a PEM file). In case there are
multiple host key document only the first certificate is used.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Marc Hartmayer
0f433b1142 pvsecret: fix panic if empty file is used as host key document
Fix a panic in `pvsecret` when a empty file is used as a host key
document.

$ touch hkd
$ pvsecret create --no-verify -k hkd --output req.bin --hdr sehdr
...
The host key document in 'bla' contains more than one certificate!
thread 'main' panicked at pvsecret/src/cmd/create.rs:192:31:

Fixes: dd82c26f87 ("rust: Add tool to manage UV-secrets")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Marc Hartmayer
ab6bcad263 pv/error.rs: fix typo
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Marc Hartmayer
e40a3e0621 pvapconfig/tests: use a temporary directory for tests
Use the `TemporaryDirectory` type to create a temporary directory. This
type has the advantage that the directory is automatically removed once
it goes out of scope. The old implementation in test_sysfs_write_i32
leaks a directory if a previous subtest failed. Also, using a temporary
directory for the LockFile test fixes the following error:

  $ RUST_BACKTRACE=1 cargo test -- helper::tests::test_lockfile
  ...
  running 1 test
  test helper::tests::test_lockfile ... FAILED

  failures:

  ---- helper::tests::test_lockfile stdout ----
  thread 'helper::tests::test_lockfile' panicked at pvapconfig/src/helper.rs:265:9:
  assertion failed: r1.is_ok()
  stack backtrace:
     0: rust_begin_unwind
	       at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/std/src/panicking.rs:597:5
     1: core::panicking::panic_fmt
	       at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/panicking.rs:72:14
     2: core::panicking::panic
	       at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/panicking.rs:127:5
     3: pvapconfig::helper::tests::test_lockfile
	       at ./src/helper.rs:265:9
     4: pvapconfig::helper::tests::test_lockfile::{{closure}}
	       at ./src/helper.rs:263:24
     5: core::ops::function::FnOnce::call_once
	       at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/ops/function.rs:250:5
     6: core::ops::function::FnOnce::call_once
	       at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/ops/function.rs:250:5
  note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-By: Harald Freudenberger <freude@de.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Marc Hartmayer
e56acf4f14 pv_core: add TemporaryDirectory
Add the type `TemporaryDirectory` that creates a temporary directory
that is automatically removed when it goes out of scope.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-By: Harald Freudenberger <freude@de.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Finn Callies
17977eda30 cpacfstats: Fix typo PCMKO to PCKMO
This commit fixes a typo in the cpacfstats.c client application and its
respective manpage cpacfstats.1.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
459a257568 rust/pvapconfig: Fix typos and clippy findings
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
fb65b53b9b rust/pvapconfig: use pv_base instead of pv crate
Replace the pv crate with the pv_core crate.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
c8d4062f73 rust/pv: bump up crate version to 1.0.0
Recent changes makes it reasonable to update the version string of pv
and pv_base to 1.0.0. Recent changes introduced some non-backwards
compatible changes, like move some Error definition from pv to the new
pv_core crate. Also, the pv crates seem to be in a good shape to be
considered released.

Therefore, move up the Semver to 1.0.0.
See also:
https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html

NOTE: As these crates are not published to `crates.io` as of now, the
version number is meaningless, as cargo will not pull them from
anywhere and just use the files provided by this repository.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
c8e0992814 rust/Cargo.lock: Update zerocopy crate
Update the zerocopy dependency from v0.6.* to the non forward compatible
v0.7.*. Incompatible changes are the requirment of the FromZeroes trait
for FromBytes trait and the non-default derive feature which this
patches handles as well.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
c0a12b29d0 rust/pv: Reorganize some tests
Use a static Mockito server instead of creating multiple on-the-fly
during testing. Add the `mockito_server_available` test to quickly
verify that the mockito server could be constructed.  Relocate the
verifier API test to the test folder as it tests the public API. Also,
make the Debug impl for CertVerifier public. The test relocation
requires this. Before, there could be a test local implementation of the
Debug impl as it was in the same crate.

While at it, get rid of the lazy_static crate in favor of the once_cell
crate. As the new std lib implementation is very near to the one from
once cell. The project will switch to the std impl when v1.70 is
available in all supported distros. See:
https://doc.rust-lang.org/std/sync/struct.OnceLock.html

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
02dded11a5 rust/pv: Replace libc wherever possible
Replace all libc references to rust-std references if available.
This eliminates the need to include libc in the pv crate.
However, pv_base still refers to libc::ioctl and libc::ENOTTY.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
b71279cda5 rust/pv: Remove memeq function
The rust std lib already provides functionality to compare two slies.
Replace all `memeq` invocations with == and remove the `memeq` function.
As a side effect this eliminates some unsafe code in this crate.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
c70477f8c6 rust/pv: Fix 'elided_lifetimes_in_associated_constant' warning
Fixes "warning: `&` without an explicit lifetime name cannot be used
here". This warning will become a hard error in "the future". For more
information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>

Closes: https://github.com/ibm-s390-linux/s390-tools/issues/162
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
9b51b8b882 rust/pv: Refactor pv crate
Big refactoring patch of the pv crate. The main reason behind this
refactoring is to simplify testing and maintaining the pv crate while
keeping OpenSSL/libcurl dependencies optional. Using crate features
increases the number of targets that have to be tested. This refactoring
eliminates the use of features by splitting the functionality of pv into
a use OpenSSL and no-use-OpenSSL crate.

Split off some code from the pv crate into a pv_core crate. pv requires
pv_core and reexports all symbols. pv_base contains all code from former
pv that does not use OpenSSL or libcurl functionalities. The refactored
pv crate contains functionalities to generate requests and validate host
key documents. All features from pv are dropped as they are not needed
anymore and to streamline the codebase for easier use and testing. While
at it fix some documentation issues.

Users (pvsecret & pvapconfig) have next to no code change, besides the
different import of the crate.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
48539596ef rust/pv: Use constants for invalid secret types
Add local constants for the reserved, and Null secret type and use
them.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Steffen Eiden
cafa99774c rust/pv: Replace file-macros with functions
A function does the job as well. This improves code readability and
useability. While at it remove the implicit Buffer wrapper. Users are
currently not use the benefits of a buffered write. Also, streamline the
write_out helper function.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Tobias Huschle
b5f7ac95d8 cpuplugd: adjust to CPU 0 being no longer hotpluggable
With kernel commit 496bb034f4ff ("s390/smp: disallow CPU hotplug
of CPU 0") it is no longer possible to hotplug CPU 0.

As a side effect, the sysfs handle /sys/devices/system/cpu/cpu0/online
does no longer exist. Since cpuplugd relies on checking all online
handles of all CPUs, this change causes cpuplugd to fail as it
interprets a non existing online file as an indicator that no other CPUs
with higher IDs exist as well. This leads to cpuplugd assuming that
there are no CPUs available.

Instead of checking for the online file, it is preferable to check for
the existence of the parent folder to verify the existence of a CPU.
As a consequence, all other checks for non-existing online files must
now imply that the CPU is online, but not hotpluggable.

Signed-off-by: Tobias Huschle <huschle@linux.ibm.com>
Tested-by: Mete Durlu <meted@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Thomas Richter
e984b97db0 s390-tools/cpumf: set exit code on pai data collection error
When pai records data it may fail in select() system call.
This error is not reported and the pai program exits with success.
Change this and exit with proper exit code.

Fixes: d7b1cbad8b ("cpumf/pai: Add Processor Activity Instrumentation tool")
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Thomas Richter
64d4e02b4f cpumf/pai: Handle perf records type PERF_RECORD_SWITCH
Running command pai -r <file> might encounter entries of type
PERF_RECORD_SWITCH. Entries of that type are currently not handled
and cause an error message:

 # pai -r ~/paicrypto.000
 unknown header-type 14 unknown header-type 14 \
 unknown header-type 14 ...

The error message is not terminated by a newline.

Handle entries of this type PERF_RECORD_SWITCH. These records
do not carry any payload at all, just a bit is set in the
header::misc member. This bit set determines context switch out.

Output after:
 # ./pai -r ~/paicrypto.000
 0x4b814018f4f3 6 cs-out
 0x4b817bc3c936 6 cs-in
 0x4b817bc5246c 6 cs-out
 0x4b817bd90e9a 6 cs-in
 ....
 #

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Marc Hartmayer
90ddef5a41 pre-commit: Provide pre-commit configuration
Add pre-commit (https://pre-commit.com/) configuration to allow
developers to run certain checks on their commits automatically.

Currently enabled checks and hooks are:
- Generic checks (e.g. merge-conflicts, trailing whitespace, etc.)
- git clang-format
- Codespell
- Shellcheck (https://www.shellcheck.net/)

Note: For some hooks Rust is excluded as a lot of false positives are
produced at the moment.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00
Joern Siglen
58ef99f76b dbginfo.sh: handle relative and absolute calling path
include the dbginfo.sh script used - enabled for relative paths

Reviewed-by: Michael Storzer <mstorzer@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-01-12 14:10:52 +01:00
Joern Siglen
43c34956fb dbginfo.sh: adding new step to man page
step "initrd config files" was added as 19th step to our data collection
updating for newer date and distro version in the sample output

Reviewed-by: Michael Storzer <mstorzer@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-01-12 14:10:52 +01:00
Joern Siglen
d7dee1b9d3 dbginfo.sh: change copyright for 2024
prepare for the next updates

Reviewed-by: Michael Storzer <mstorzer@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-01-12 14:10:52 +01:00
Harald Freudenberger
94a38ebc3a rust/pvapconfig: Introduce new tool pvapconfig
pvapconfig is a new tool for automatically configuring the APQNs
within an Secure Execution KVM guest with AP pass-through support.
Based on a given AP configuration it tries to find a matching
APQN and bind and associate it with the correct secret.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-01-12 14:10:52 +01:00
Steffen Eiden
0764460eaf rust/pv: Provide access for SecretList members
Adds getter for SecretList and SecretEntry.
Adds enum to represent secret types.
Add Iterator functionality for SecretList.

While at it, make the datatype of the capacity of the list transparent
for users.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-01-12 14:10:52 +01:00
Steffen Eiden
6fd02279da rust/Makefile: Fix CC/AR variables for TEST_TARGETS
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-01-12 14:10:52 +01:00
Yaakov Selkowitz
6274294bc5 libkmipclient: Fix build with libxml2-2.12.0
https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.12.0

"Several cyclic dependencies in public header files were fixed. As a
result, certain headers won't include other headers as before."

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/160
Signed-off-by: Yaakov Selkowitz <yselkowi@redhat.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-20 18:32:34 +01:00
Steffen Maier
27708026d4 zdev/dracut: state requirement for sed during kdump initrd build
v2.27.0 commit 73c46a3056 ("zdev/dracut: fix kdump by only activating
required devices") started using `sed` during kdump initrd build time.
It works, but explicitly add the tool as a requirement.

Fixes: 73c46a3056 ("zdev/dracut: fix kdump by only activating required devices")
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
849aa5b105 zdev/dracut: put temporary files under the subdir ${DRACUT_TMPDIR}
This way, dracut cleans up everything just in case the "rm" here fails.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
0be83bfbba dbginfo.sh: collect migration backups & logs from old persistent config
Complements commits
("zdev/dracut: add rd.zfcp cmdline option handling")
("zdev/dracut: add rd.dasd cmdline option handling")
and s390utils commits
("zfcp: migrate to consolidated persistent device config with
zdev (#1937046,#1937048)")
("dasd: migrate to consolidated persistent device config with
zdev (#1937046,#1937048)")
.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
f8592be43d dbginfo.sh: collect file list and config files from initrd-s
For each initrd, collect verbose content listing as well as
the content of files matching the file glob patterns in $CONFIGFILES.
For dracut-squash such as RHEL kdump, this includes squashfs content.

Code is intentionally compatible with dash, so no bashisms.

Ubuntu initramfs has zdev persistent device configuration udev rules under
/lib/udev/rules.d/ (as opposed to /etc/udev/rules.d/).
Ubuntu initramfs stores configuration under /conf/.
Ubuntu kdump-tools have initrds under /var/lib/kdump/.

SLES auxiliary boot stage with grub2-s390x-emu has initrds under /boot/zipl/.

Dracut initramfs stores configuration under /etc/cmdline.d/ and /etc/conf.d/.
Dracut kdump have initrds under /boot/.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
647ad51423 dbginfo.sh: collect other config data from zdev in initrd
Complements commit ("zdev/dracut: retain early persistent config over
switch root").

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
73f51e45a8 zdev: add helper to convert from zdev config to rd.znet
Converts zdev configuration into the syntax of the dracut cmdline option
rd.znet. Only znet options with non-default values are emitted. The result
string occurs on stdout. It represents one device-specification for the
given network interface name.

Example:
/lib/s390-tools/zdev-to-rd.znet persistent encbdf0
qeth,0.0.bdf0,0.0.bdf1,0.0.bdf2,layer2=1

User:
https://github.com/rhinstaller/anaconda/pull/5250
to generate dracut cmdline entries such as
rd.znet=qeth,0.0.bdf0,0.0.bdf1,0.0.bdf2,layer2=1

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
bc4f455151 zdev/dracut: retain early persistent config over switch root
Useful for debugging (what happened during early boot).

Also useful for distro installers, which can import the early config into
their own environment early after starting:
chzdev --import /run/zdev.initrd.config --persistent --yes \
       --no-root-update --force --verbose

After that, distro installers can modify/add the device config based
on interactive or unattended installation choices using
chzdev --enable --active --persistent ...

Finally, distro installers can likewise transfer the entire device config
to the installed system mounted under $SYSROOT:
chzdev --export /tmp/zdev.config --all --type --persistent --verbose

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
b4b5e0b6aa zdev/dracut: produce helpful user information on parsing rd.zfcp
It builds on the previously added helper function in parse-dasd.sh, which
gets sourced first by dracut so the function is also available to the later
parsing hook parse-zfcp.sh.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
9927023680 zdev/dracut: add rd.dasd cmdline option handling
Add parsing of dracut cmdline option "rd.dasd=..." at initrd runtime.
It delegates configuration to chzdev.

Implement `dracut --print-cmdline` and `dracut --hostonly-cmdline` for
initrd build time. Emit an rd.dasd option for each DASD disk in dracut's
device dependency graph (to mount the root-fs, or to access the kdump
target).

This allows a distribution independent device configuration.
Configuration is consistent by using chzdev as backend.
It also prevents duplicate activations of the same device.

Copy the udev rule for unique DASD device nodes under /dev/disk/
[59-dasd.rules] into initrd for the same functionality like 95dasd or
95dasd_rules.

Along with the existing functionality of zdev/dracut, it makes the
following dracut modules superfluous:
https://github.com/dracutdevs/dracut/tree/master/modules.d/95dasd
https://github.com/dracutdevs/dracut/tree/master/modules.d/95dasd_mod
https://github.com/dracutdevs/dracut/tree/master/modules.d/95dasd_rules

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
9b2fb1d4d2 zdev: add helper to convert from dasd_mod.dasd to zdev config
Shell library, which can be sourced by other POSIX compatible shell
scripts. Provide helper function parsing its stdin based on the syntax of
kernel device driver parameter dasd_mod.dasd= and invoking chzdev to
produce corresponding persistent device configurations. The helper function
takes one argument, which is either "globals" or "ranges". For a complete
configuration, call the function twice, first with "globals" and then with
"ranges".

The new script library file should be packaged in a core (sub)package of
s390-tools so the script is available for initrd environments.

Users with examples:

Subsequent commit ("zdev/dracut: add rd.dasd parsing") introduces
zdev/dracut/95zdev/parse-dasd.sh performing:
zdev_parse_rd_dasd | zdev_parse_dasd_list globals 2>&1 | zdev_vinfo
zdev_parse_rd_dasd | zdev_parse_dasd_list ranges 2>&1 | zdev_vinfo

https://github.com/dracutdevs/dracut/pull/2534 updates
modules.d/80cms/cmssetup.sh performing:
echo "$DASD" | zdev_parse_dasd_list globals 2>&1 | vinfo
echo "$DASD" | zdev_parse_dasd_list ranges 2>&1 | vinfo

The parsing code for rd.dasd using the same syntax as dasd_mod.dasd=
is inspired by the own implementation that used to be in linuxrc.s390
of https://github.com/rhinstaller/anaconda.
https://web.archive.org/web/20190721154444/https://www.redhat.com/archives/anaconda-devel-list/2009-February/msg00392.html
https://www.spinics.net/linux/fedora/anaconda-devel/msg08316.html
("Re: Improved linuxrc.s390 (third try)")
=> 9249e40f42ff ("IBM improvements to linuxrc.s390 (#475350)")
https://web.archive.org/web/20190721150254/https://www.redhat.com/archives/anaconda-devel-list/2009-July/msg00310.html
=> 5f0fcf6688d0 ("Update linuxrc.s390 and friends to reflect review comments.")
https://web.archive.org/web/20190721125255/https://www.redhat.com/archives/anaconda-devel-list/2009-August/msg00158.html
=> 523095c86876 ("Handle activation of DASDs in linuxrc.s390 since loader no longer works")

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
689b894506 zdev: add helper to convert from zdev config to dasd_mod.dasd
Converts zdev configuration into the syntax of the kernel module parameter
dasd_mod.dasd. Only DASD options with non-default values are emitted. The
result string occurs on stdout. It represents one device-specification for
the given DASD device bus-ID.

Example:
/lib/s390-tools/zdev-to-dasd_mod.dasd persistent 0.0.da5d
0.0.da5d(erplog)

User:
https://github.com/storaged-project/blivet/pull/1162
to generate dracut cmdline entries such as rd.dasd=0.0.da5d(erplog)

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
06a30ae529 zdev/dracut: add rd.zfcp cmdline option handling
Add parsing of dracut cmdline option "rd.zfcp=..." at initrd runtime.
It delegates configuration to chzdev.

Implement `dracut --print-cmdline` and `dracut --hostonly-cmdline` for
initrd build time. Emit an rd.zfcp option for each zfcp-attached SCSI disk
in dracut's device dependency graph (to mount the root-fs, or to access the
kdump target).

This allows a distribution independent device configuration.
Configuration is consistent by using chzdev as backend.
It also prevents duplicate activations of the same device.

Along with the existing functionality of zdev/dracut, it makes the
following dracut modules superfluous:
https://github.com/dracutdevs/dracut/tree/master/modules.d/95zfcp
[rd.zfcp.conf is no longer needed and thus ignored here; the preceding
 ("zdev/dracut: fix marking hostonly files so delete option works")
 makes rd.hostonly=0 work as a generic replacement]
https://github.com/dracutdevs/dracut/tree/master/modules.d/95zfcp_rules

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
ed106d7f28 zdev/dracut: add site support for early devices to the kdump case
The existing code can already determine the required devices for the
actively running system, but this does not work for execution environments
in different (disaster recovery) sites.

Kdump likely does not notice when running in a different site and does not
re-generate the kdump initrd (because the kdump config itself does not
change).

The new code allows users to explicitly specify devices required for early
boot in initrd on different sites. Assuming this is a small number of
devices and could even overlap between the root-fs and the kdump case, do
not further distinguish those two sets of devices, but simply use the same
marker attribute "zdev:early=1" for both cases. With all this site
information available at the (initial) kdump initrd generation, the
resulting kdump initrd can work on any site without having to re-generate.

Complements commit 3c7adcc3c81d ("zdev: dracut: modifiy the
module-setup.sh").

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
9d08fd8c7e zdev/dracut: import persistent config of early devices into kdump initrd
The existing code can already determine the required devices for the
actively running system. In case users would have a need to configure
additional devices for early boot in kdump initrd, import those devices
marked with "zdev:early=1" for completeness. Assuming this is a small
number of devices and could even overlap between the root-fs and the kdump
case, do not further distinguish those two sets of devices.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
7e8126704b zdev/dracut: fix to not depend on existing chzdev persistent config
Dracut knows exactly what dependencies it needs. Do not break it by
accidentally missing parts in the chzdev persistent configuration
(/etc/udev/rules.d/41-*.rules). Depicted as mathematical sets:

+-------------------------------+
| active                        |
|            +---------------------------------+
|            |                  |   persistent |
|   +------------------------------------+     |
|   |      root / kdump dependencies     |     |
|   | was    |                  |        |     |
|   | missing|   zdev so far    |   DR   |     |
|   +------------------------------------+     |
|            |                  |              |
+-------------------------------+              |
             |                                 |
             +---------------------------------+

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
d96767ee45 zdev/dracut: fix marking hostonly files so delete option works
Chzdev import generates persistent device configuration which are hostonly
files. Dracut cmdline rd.hostonly=0 should be able to delete those.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
63f31bf73e zdev/dracut: add field debugging capabilities with logging
Additional debugging output can be generated with e.g. dracut option
"--stdlog 5" (or short -L5). It shows the chzdev export result, the output
of chzdev imports, and an overview of the resulting persistent config
within the initrd.
On systems, which default to using dracut option "--quiet", you might need
an additional "--verbose" to counter "--quiet" so -L5 has effect.
Typically combined with "--debug" to get a shell trace from building an
initrd (Note: --debug does not increase the log levels).

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
7ecfe2353f zdev/dracut: respect hostonly mode choice
Otherwise it risks adding arbitrary persistent configuration of the build
host into generic dracut initrds such as those for distro installers.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
7bec672c7e zdev/dracut: fix kernel module install even for hostonly mode
Otherwise, dracut skips modules that are "not hostonly", i.e. not used /
loaded on the system when running dracut to build an initrd.
Without the fix, zdev device auto configuration only works for device
types for which a device driver happened to be loaded when building an
initrd. Likewise for specifying rd.* boot options.

Hostonly mode is often the default in Linux distributions.
Make zdev device auto configuration work nonetheless without users
having to know about and tweak dracut modes for initrd generation.

On the typical sloppy hostonly mode, the code disables hostonly for
installing kernel modules. This covers building regular initrds, where zdev
device auto configuration should even work for device types, for which
device drivers were not loaded when an initrd was generated. This can
happen when new devices of new types are configured for a DPM logical
partition. Also, users could want to start using dracut cmdline options
rd.{dasd,zfcp,znet} for a device type that was not used when the initrd was
built.

The special strict hostonly mode is used by some kdump implementations. In
that case, hostonly remains in effect intentionally because only support
for the really required devices as determined by dracut module 95zdev-kdump
should be included in a kdump initrd due to the memory-constrained kdump
environment. Cf. commit 73c46a3056 ("zdev/dracut: fix kdump by only
activating required devices"), which also provides more references on
strict hostonly mode. Even for non-kdump cases, let strict hostonly mode be
effective here in 95zdev in case some future use case appears for this
special mode beyond kdump.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
5aac5deb75 zdev/dracut/module-setup.sh: add comments for dracut called functions
Add a short explaining comment to those functions, which are just callbacks
invoked by the dracut core infrastructure. So nobody wonders how these
functions get called, especially if there are no local callers here in the
code.

Cf. dracut commit
https://github.com/dracutdevs/dracut/commit/8bcfd683bd0c
("*/module-setup.sh: add comments for dracut called functions")

For more information about the dracut module callback functions:
https://github.com/dracutdevs/dracut/blob/master/man/dracut.modules.7.asc#writing-a-module
https://github.com/dracutdevs/dracut/blob/master/docs/HACKING.md#writing-modules

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
54e016ae71 zdev/dracut: use namespace prefix in functions of zdev-lib.sh
Use namespace prefix in functions of zdev-lib.sh to avoid collisions with
different modules being sourced in the shell.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
6b53378839 zdev/dracut/95zdev: non-functional changes and annotations for shellcheck
Clears all shellcheck reports in old existing code so newly added code can
use shellcheck to find newly introduced suboptimal shell code.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
1266f86444 zdev/dracut: add shellcheck annotations for recently added code
The annotations and the one non-functional code change in
zdev/dracut/95zdev-kdump/module-setup.sh check() clear all shellcheck
reports.

complements
73c46a3056 ("zdev/dracut: fix kdump by only activating required devices")

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Steffen Maier
231c02cdeb zdev: fix typo for example in chzdev man page
Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/158
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Marc Hartmayer
454a8d9d7b systemd/cpi.service: add missing Requires=sysinit.target
`After=sysinit.target` configures only the order but not that the
systemd unit is required and must be activated. Therefore add the
missing `Requires=sysinit.target`. It probably does not fix anything
because sysinit.target should always be activated anyway but it's
cleaner to have it. See
https://www.freedesktop.org/software/systemd/man/systemd.unit.html for
details.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Marc Hartmayer
bbe92b9cd3 systemd/cpi.service: fix race condition between stopping unit and shutdown
There is a race condition between stopping the cpi systemd service and
systemd getting a request to exit the main loop, so it may proceed with
shutdown before all pending stop jobs have been processed. Therefore,
add `Before=shutdown.target` as it would have been added by
the (deactivated) default dependencies. [1]

While at it, sort the directives.

[1] https://www.freedesktop.org/software/systemd/man/systemd.service.html#Default%20Dependencies

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-14 15:25:22 +01:00
Jan Höppner
7bb41732fb Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-01 15:03:39 +01:00
Jan Höppner
c217f6be6a New release s390-tools-2.30.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-12-01 15:03:39 +01:00
Steffen Eiden
21662d38e6 rust/pv: Update mockito to version 1
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Niklas Schnelle
19f3842292 libutil: fix util_file_read_*() using wrong format specifiers
The sscanf() format specifiers for signed and unsigned int mistakenly
used "%d"/"%u" prefix analogous to "%l" for long but those do not exist.

Fixes: 37348ef662 ("libutil: add util_file_read_i()/util_file_read_ui()")
Acked-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Steffen Eiden
ae0cbf00b1 rust: Use default panic behaviour
Reviewed-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Steffen Eiden
9019c6864a rust: Sanitize minimal dependencies
The crate dependencies were a bit to slack. Due to the rust dependency
resolver's strategy of always selecting the latest version this never
lead to any issues.

This has no impact on the workspaces Cargo.lock

Reviewed-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Steffen Eiden
d1b61c37fa rust: Update dependency files
With the last patch introducing the rust workspace the location of
Cargo.lock has changed. Therefore, remove all crate level lock-files and
add rust/Cargo.lock as the only lock-file.

Steps to reproduce:
```
cd rust
mv pvsecret/Cargo.lock .
cargo build
cargo update -p openssl
cargo update -p curl-sys
cargo update -p rustix

```

While at it update some dependencies to get fixes for security issues.

Reviewed-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Steffen Eiden
32b68a5fad rust: Create workspace
A workspaces simplifies the build and packaging process significantly.
All build artifacts and binaries are now built in a single location
(e.g., rust/target/release/*), and a unified dependency resolution is
used. Hence one Cargo.lock for all crates at rust/Cargo.lock.

Closes: https://github.com/ibm-s390-linux/s390-tools/issues/156
Reviewed-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Matthew Rosato
55fdb17b18 ap_tools/ap-check: handle get-attributes between pre and post event
Since mdevctl commit acf78c1ff6c9 it is now possible for the
get-attributes event to occur between a pre-define and post-define.
This is done in order to obtain the active attributes for the device
before writing them to the config file, and implies that the
get-attributes cannot re-obtain the file lock.  For other cases
where mdevctl calls get-attributes, the file lock is not already
held and must be obtained by ap-check before reading attributes from
active devices.
To solve this, let's use the knowledge that mdevctl is a single-threaded
tool and add a test to detect this scenario.  If the file lock is
already held by the parent during a get-attributes, don't attempt to
re-acquire it.

Reported-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Matthew Rosato
af730c79a6 libutil/util_lockfile: add routine to return owning pid of file lock
Provide a mechanism via which a caller can query the pid of the process
currently holding the file lock.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Marc Hartmayer
041e6131d1 genprotimg/boot: stage3b: check cmdline for null-termination
Add a check to the stage3b that the kernel cmdline is always
null-terminated. While at it, ensure the coding style is consistent.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Marc Hartmayer
5a7d7e05b8 genprotimg: make sure the kernel command line is always null-terminated
Make sure that the kernel command line used for the Secure Execution
boot image is always null-terminated. Before this change, users had to
ensure that the provided kernel cmdline was null-terminated, which was
error-prone. But since the default s390x Linux kernel command line is
set to `root=/dev/ram0 ro` the remaining reserved memory for the kernel
command line is zeroed out. Therefore, the problem only shows up if the
used kernel command line is shorter than the default kernel command
line.

Fixes: 65b9fc442c ("genprotimg: introduce new tool for the creation of PV images")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:48 +01:00
Steffen Eiden
71b93d55ef rust/pv: fix Invalid write of size 1
Fix a valgrind finding. Fix an invalid read/write of one byte after the
actual struct to clear. Not fixing this may result in a illegal write or
memory corruption of the program. Fortunately, for the actual only user,
pvsecret this is not the case.

Fixes: c6f621d0 ("rust: Add library for pv tools")
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 10:24:40 +01:00
Thomas Richter
d2b5e1e2d6 cpumf/pai: Add command line option for realtime scheduling
Pai collects data from per CPU ring buffers and stores them in the
memory mapped output file. When data is collected from many CPUs at
the same time, writing data to output file can be slow.
Improve this and allow the pai recording to run with higher
real time priority. This is the same approach as done by the perf tool.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-12-01 09:58:47 +01:00
Mikhail Zaslonko
a3cb877c54 README: Add info about bundled zlib
Update Dependencies section for zipl with the information of zlib
compression support for CCW-type standalone dump.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/157
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Joern Siglen
6895a71cc4 dbginfo.sh: remove brakets on lsqeth device list
in customer situation we found lsqeth listing devices like:
Device name                      : (unnamed net_device)
Device name                      : enc2000
Device name                      : enc3000

- the braket around the "unnamed" device is braking the function call and
leads to stop the dbginfo.sh script.
- this patch removes brakets > the functions call works and call of osaoat
will report an unknown device instead of braking the dbginfo.sh script

Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Joern Siglen
d9034b01f1 dbginfo.sh: enhance ethtool collection for ROCE
collect module-info for new ROCE cards via ethtool

Suggested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Joern Siglen
488ac8c3f2 dbginfo.sh: fix shellcheck errors in double quoting
change use of double quote to fit the rules

Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Jan Höppner
ecf36d53c8 dasdfmt: Update -k/--keep_volser description
Make the description of the --keep_volser option more generic and avoid
mentioning specific tooling.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Jan Höppner
893ad920c5 dasdfmt: Fix trailing whitespace in man page
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Jan Höppner
0695c79f4e fdasd: Improve -k/--keep_volser description slightly
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Jan Höppner
8837ea24cb fdasd: Fix trailing whitespace in man page
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Marc Hartmayer
65222d03b9 zipl/boot: compile the bootloaders only if HOST_ARCH is s390x
The zipl bootloaders are s390x specific, so only build them if the
`HOST_ARCH' is set to s390x.

While at it, rename `INC_FILES` to `EMBEDDED_BOOTLOADERS`. Also
introduce `EXTERNAL_BOOTLOADERS` variable and use it in the `install`
Makefile target.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Ingo Franzki
54937495e2 zkey: Also check for deconfigured and check-stopped cards
When checking if a card or an APQN is online, not only check the 'online'
sysfs attribute, but also check the 'config' and 'chkstop' attribute.
Cards and APQNs in check-stopped or deconfigured state can still be reported
as online via the sysfs attribute, although they are not available to be
used for zkey.

In case the 2 additional sysfs attributes are not available in sysfs, then
don't fail, but rely on the 'online' attribute only.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Marc Hartmayer
8a783b81a4 Provide a ShellCheck configuration
This patch adds a ShellCheck configuration for s390-tools. See
https://www.shellcheck.net/wiki/Directive for details.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Marc Hartmayer
093da2a5a7 zipl: move responsibility for the stage3.bin installation to boot/Makefile
Move the code responsible for installing stage3.bin to the
boot/Makefile. In addition, remove the stage3.bin from the Makefile
`all` target prerequisites in src/Makefile, as zipl can be built without
it. While at it, use $(INSTALL) instead of $(CP) for the bootloader
installation.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Ingo Franzki
b68ea5fc7d zkey: Fix typos in man page
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Eric Farman
90c587408f cpictl: Limit kernel sublevel to one byte
Linux stable kernels can reach greater than 256 sublevels [1],
which can cause the cpi tooling to generate an invalid string
that gets passed to the firmware and causes unusual responses:

  $ uname -r
  5.4.255
  $ cat /sys/firmware/cpi/system_level
  0x04260000000504ff

  --reboot--

  $ uname -r
  5.4.256
  $ cat /sys/firmware/cpi/system_level
  0x4260000000504100

The first sublevel field is defined as one byte, so ensure that
a value larger than that isn't included.

[1] https://lore.kernel.org/lkml/1612534196241236@kroah.com/

Signed-off-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Thorsten Winkler
90475fbaa5 common.mak: use eval only once for defining variables
Using eval only once at the top most function "define_toolchain_variables",
makes the other subsequent eval calls redundant.

“The result of the eval function is always the empty string; thus, it
can be placed virtually anywhere in a makefile without causing syntax
errors.” [1]

So this patch also prevents potential syntax errors using GNU Make <v4.2.
Since version 4.2 GNU Make introduced a less errorness function calling and
variable expanding with commit
e971597 ("[SV 46995] Strip leading/trailing space from variable names")

Reference: https://git.savannah.gnu.org/cgit/make.git/commit/?h=4.2&id=e97159745d3359285cef535af780cd8e2b6b0791

[1] https://www.gnu.org/software/make/manual/html_node/Eval-Function.html

Signed-off-by: Thorsten Winkler <twinkler@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Vineeth Vijayan
07ff9e1da0 zdev: limit the derivation of ZDEV_SITE_ID
Currently ZDEV_SITE_ID is derived with the help of an additional
udev-rule, 40-zdev-id.rules. The sole purpose of this rule is to
determine the ZDEV_SITE_ID environment value with the help of zdev_id
binary. This solution is minimal, but this has some unwanted side-
effects. The zdev_id logic get executed for all the events, even
those completely unrelated to zdev/or site, and imports the unneeded
envionment values to the udev-db.

Instead of having an additional rule file, add this logic as part of
the udev-rule of those devices which are configured with site-support.
The logic will then be available on all those rules with the
site-supported devices only.

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>
2023-11-07 14:13:38 +01:00
Vineeth Vijayan
5637799c92 zdev: introduce dev_site_configured macro
Introduce dev_site_configured macro,which can be used to find the
availability of site configurations for the device during udev rule
creation.

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>
2023-11-07 14:13:38 +01:00
Vineeth Vijayan
73c82441e7 zdev: move all site-related definitions to one file
Previously SITE_FALLBACK and other site-specific configuration support
macros were defined in device.h. Instead, move them to a relatively
smaller header file which is exclusive for site-related definitions.
This way, light-weight zdev_id also can use the same header file.

Reported-by: Steffen Maier<maier@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>
2023-11-07 14:13:38 +01:00
Alexandra Winter
6d06921276 zdev:qeth: adapt performance_stats attribute semantics
Behaviour of the qeth performance_stats sysfs attribute has changed
with kernel commit
b0abc4f5df76 ("s390/qeth: overhaul ethtool statistics")
that went into kernel v5.1.

Before the kernel commit
- collection of statistics was turned on and off by writing 1 or 0
- default after device activation was 0
- statistics were reset by writing 0

After the kernel commit:
- collection is always on
- attribute always reads 1
- statistics is reset by writing 1; writing 0 is a no-op

Problems of chzdev on new kernels:
chzdev cannot reset statistics ('performance_stats=1' does nothing).
'chzdev --export' always lists performance_stats.
'chzdev qeth --help-attribute performance_stats' reflects old behaviour.

This patch will do the following:
'chzdev qeth --help-attribute performance_stats' reflects new behaviour.
'chzdev --export' does not list performance_stats on new kernels.
'chzdev performance_stats=1' resets statistics on new kernels.
'chzdev performance_stats=0' still resets statistics on old kernels,
    does nothing on new kernels.

Suggested-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-11-07 14:13:38 +01:00
Steffen Maier
2996b34ddf dbginfo.sh: collect debug data for zdev site support
Complements v2.24.0 commit c8ad5f57d0 ("zdev: modify zdev_id to read the
site_id from loadparm") and commit 2e89722ef0 ("zdev: make site specific
udev-rule for ccw").

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Steffen Maier
e5821301f6 dbginfo.sh: exclude (empty) cpu subdirs under zfcp sdev block mq sysfs
With many CPUs, such as triple digit counts, the by default many empty
sysfs directories are prohibitive to collect, especially if the number
of SCSI disk devices is also large, such as 4-digit counts.

Excluding them from being collected from sysfs saves hundreds times
thousands of archive entries and inodes on expansion.

Since the number device-mapper devices (multipath and other target types
such as LVM) is smaller and can include devices not backed by zfcp, keep
collecting
/sys/devices/virtual/block/dm-[0-9]*/mq/0/cpu[0-9]*/

Definitely keep collecting
/sys/kernel/debug/block/{sd,dm-}*/hctx0/cpu[0-9]*/
as it contains actual statistics files:
completed  default_rq_list  dispatched  merged  poll_rq_list  read_rq_list

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Steffen Maier
f4d1874ac5 dbginfo.sh: collect text export of udev data base
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Steffen Maier
f3428929a2 dbginfo.sh: collect potential kdump config under subdir /etc/kdump
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Mikhail Zaslonko
263d6950a1 zipl/boot/zlib: Replace static_assert() in zlib code
Replace static_assert() with STATIC_ASSERT macro from zt_common.h in order
to get rid of glibc dependencies in zipl/boot and comply with older
C standards.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Suggested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Marc Hartmayer
8024f8e31a editorconfig: add settings for EDIT_DESCRIPTION
Set the maximum line length for branch description messages (`git branch
--edit-description`) to 72 characters.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Marc Hartmayer
3849b29594 rust/**/*.rs: fix cargo clippy findings
Automatically fixed by the command `cargo clippy --fix` and `cargo fmt`.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Mikhail Zaslonko
0e4d4da0e5 zdump: Update zgetdump man page
Update zgetdump man page with the information of compressed DASD dumps
support as well as new verbose 'zgetdump -i' output entries.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:07 +02:00
Mikhail Zaslonko
ca3cd51f91 zdump/dt_s390: Support new dumper version by 'zgetdump -d'
Add new dumper version support to 'zgetdump -d' command.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
fda1e0d33d zdump: Move and rename DF_S390_DUMPER_SIZE constants
Move DF_S390_DUMPER_SIZE_* constants from zdump/df_s390.h to
boot/loaders_layout.h since ccw dumper size depends on the zipl boot
loader layout (to keep it all in one place).

Rename DF_S390_DUMPER_SIZE_* constants to STAGE2_DUMPER_SIZE_*

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
1a850392bc zdump/df_s390: Update 'zgetdump -i' output with zlib info
Update verbose 'zgetdump -i' output with zlib info (internal zlib version
and zlib compression unit size).

The following new entriees are to be dispalyed:
	Zlib version.......: 1
	Zlib compression unit: 1 MB

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
14a79eb142 zdump: Increase output buffer from 8 pages to 1 Mb
Increase the auxiliary buffer size from 8 pages to 1 megabyte in order to
significantly increase compressed dump processing speed.
For uncompressed dumps, the effect is minor.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
271b809495 zdump/dfi_s390: Support reading compressed s390_ext dumps
Update dfi_s390.c to support reading of compressed dump segments.
For this, introduce a callback function for reading memory chunks
associated with compressed dump segments. Apart from the segment location
on disk this function requires the entry_offset array from the dump segment
header in order to process each compressed entry separately, thus allowing
fast seek processing for zgetdump (no need to decompress a big dump segment
to extract a single piece of data).

In addition, split mem_chunks_add_ext() in several functions.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
2363269c1c zipl/boot: Set the new version in the dumper and in the dump header
Since we are using the existing s390 extended dump format for compressed
dumps as well, set the version of the s390_ext dumper with compression
support and also dump header of the compressed dump to '2' (in order for
zgetdump to distinguish).

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
f1db473d11 zipl/boot: Fix progress_print to correctly display 'Dump file size'
- Adjust progress_print() calls to pass updated address after the set of
  blocks has been written to disk.
- Currently total_dump_size value is updated only after the entire dump
  segment is written to disk what leads to ambiguos Dump file size values
  displayed by progress_print(). Change write_addr_range() to re-calculate
  total_dump_size after each set of blocks has been written to disk thus
  printing the correct value at the end of each log entry.
- Avoid final log entry duplication.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
e35d05a5e3 zipl/boot: Add print_progress parameter to write_addr_range()
With current implementation, printing progress while writing a compressed
data chunk might be very inaccurate. Thus, for compressed dump segments
skip progress_print() in write_addr_range() and call it after each
compressed memory chunk is written to disk. For that change
write_addr_range() to call progress_print() conditionally based on the new
print_progress parameter.

For non-compressed dump segments, call progress_print() from
write_addr_range() just as before.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
c61783546b zipl: Add --no-compress option to zipl command
Add --no-compress option to explicitly omit compression for single-volume
DASD dumper. Used primarily for test purposes.

Since only the lowest byte of mvdump_force field (struct
stage2dump_parm_tail) has been used, split it in two byte fields and use
one for the new no_compress attribute.

Update zipl help and zipl man page with the new parameter info.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
c08794bdfb zipl/src: Pass stage2dump_parm_tail struct to install_dump_ functions
Move struct stage2dump_parm_tail from stage2dump.h in to
include/dump/s390_dump.h

Pass the entire stage2dump_parm_tail structure to install_dump_* functions
instead of individual parameters.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
4905975f81 zipl/boot: Adjust Makefile, loaders layout and a linker script
Use a separate linker script eckd2dump_sv.lds for single volume dumper with
compression support.

The new dump tool with zlib compression support now has a size of 8 pages.
Since DASD stand alone dump requires a block size of 4K, we are not
affected by the stage 2 size limitations and can load the dumper to
stage 2 as before. We just need to move the HEAP section for ECKD dumper
in the layout definitions up to 0xb000 address. Also expand the stack by
unused 0x400 bytes.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
d53bfb9201 zipl/boot: Integrate zlib compression to single volume DASD dumper
Integrate zlib DFLTCC deflate compression to single volume dasd dumper
using the existing s390 extended dump format. Compression takes place
only if DFLTCC facility is available, otherwise dump is written
uncompressed as before.

First megabyte of memory is always written uncompressed and afterwards
this area is used for zlib workspace and for the compression output buffer.
The compression takes place in chunks of data of equal size (currently 1MB)
and the offset of each compressed chunk is stored in the dump segment
header. Since existing dump segment headers of 1 page size are used, we
need to limit the maximum size of compressed dump segments.
Chunk is written uncompressed in case of compression error or if
deflate compression only makes it bigger.

Thus every chunk of data is compressed separately and can be decompressed
independently. The main reason for that is to enable zgetdump to make fast
read seeks. Otherwise, zgetdump would need to decompress a big dump segment
in the worst case to extract a single piece of data.

Put compression related functions and structures to eckd2dump_zlib.c
and eckd2dump_zlib.h

Update zipl man page with the general information of zlib compression
support.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
0dac47cb62 zipl/boot: Introduce write_addr_range() helper function
Move code from write_dump_segment() to write_addr_range() function to use
it later for writing compressed dump segments as well.

Verify that passed address range is a multiple of dasd block size.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
7b68552359 zdump: Use global header s390_dump.h
Instead of using its own DF_S390_ constants and df_s390_ structs
in df_s390.h, include those from "dump/s390_dump.h" in order to minimize
duplicates. Adjust the code, where required, to use <stdint> types
instead of those defined in zt_common.h (e.g. use uint64_t instead of u64).

Adjust zdump include statements.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
775495c7e7 include/dump: Create a global header s390_dump.h
Move common dump related structures and constants to the global header
"dump/s390_dump.h" in order to get rid of many duplicates in zgetdump code.

Adjust zipl include statements and update Copyright statements.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
1057f13cdc zipl/zlib: Adjust zlib parts for zipl needs
Mainly zlib code remains unchanged for the sake of further maintenance.
Only minor adjustments of zlib deflate parts for build purposes:
- Make is_dfltcc_enabled() always return true
- Define CONFIG_ZLIB_DFLTCC in zlib.h to build zlib code with DFLTCC support
- Remove inflate related prototypes from zlib.h
- Adjust oesc_msg() to use snprintf from libc.h
- Remove BUG_ON from zlib_deflate_workspacesize()
- Replace bitrev32() with bi_reverse() from defutil.h
- Include <assert.h> to dfltcc.h header because of static_assert() calls
- Fix other include statements
- Adjust the text in zipl.h following Zlib License requirements

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Mikhail Zaslonko
ce59a299cb zipl/zlib: Copy required zlib_deflate parts
Add required zlib_deflate parts based on kernel zlib code in preparation
to DASD dumper DFLTCC deflate exploitation. Omit inflate modules in
order to minimize the dumper size (no decompression is required for the
dumping).

Adjust include statements leaving other code as is.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Harald Freudenberger
8235e025d4 zcrypt/lszcrypt: Improve lszcrypt output on SE guests
The AP queue states within a SE guest may have a so called asynchronous
error pending. When that's the case, the sysfs read of some AP queue
attributes fails with EIO. lszcrypt was not really prepared for this
and instead showed some incorrect output.

This patch fixes this oddity and now lszcrypt -c shows "error" in case
of ap_bound or ap_associate read errors and lszcrypt -V shows also
"error" if the BS bits could not get fetched.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Marc Hartmayer
b301381f90 (genprotimg|zipl)/boot: remove executable bit
The bootloader binaries cannot be executed via `exec()` therefore remove
the executable bit.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Jakub Čajka
c62f930634 osasnmpd: Fix missing semicolon
5.9.4 net-snmp started to require semicolon on the config_require there
are no docs covering this change.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2235734
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/155
Signed-off-by: Jakub Čajka <jcajka@redhat.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Marc Hartmayer
85eb44ac95 lib(ekmfweb|kmipclient): use pkg-config instead of (curl|xml2)-config
`pkg-config` is mandatory for compiling s390-tools anyway therefore
let's replace `curl-config` and `xml2-config` calls whenever possible.
In addition, `pkg-config` has the advantage that cross-compilation is
supported. While at it, use `pkg-config` for libcrypto, json-c, and
libssl as well.

Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Steffen Eiden
d5f8063900 rust/README.md: Fix some typos
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Steffen Eiden
ee66929465 rust/Makefile: Fix use of Cargoflags for 'make clean'
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-09-27 18:29:06 +02:00
Ingo Franzki
1b044b8a40 zkey: Support EP11 AES keys with prepended header to retain EP11 session
The pkey kernel module supports two key blob formats for EP11 AES keys.
The first one (PKEY_TYPE_EP11) contains a 16 bytes header that overlays
the first 32 bytes of the key blob which usually contain the ID of the
EP11 session to which the key is bound. For zkey/dm-crypt that session
ID used to be all zeros. The second blob format (PKEY_TYPE_EP11_AES)
prepends the 16 bytes header to the blob, an thus does not overlay the
blob. This format can be used for key blobs that are session-bound, i.e.
have a non-zero session ID in the first 32 bytes.

Change zkey to generate EP11 keys using the new format (i.e. pkey type
PKEY_TYPE_EP11_AES), but existing key blobs using the old format can
still be used.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Joerg Schmidbauer <jschmidb@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-08-21 17:09:26 +02:00
Jan Höppner
f46f6d34d3 gitignore: Add cpumf/lspai
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-08-21 17:09:26 +02:00
Thomas Richter
3a96e8826f cpumf: Add lspai program and man page to display PAI counter sets
Add lspai program and man page to display Processor Activity
Information (PAI) facility counter sets in the same way as
lscpumf for the CPU Measurement Facility counter sets.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-08-21 17:09:23 +02:00
Mete Durlu
84738668ca hyptop/helper: fix smt utilization calculation
When calculating smt utiliziation field, subresults are capped to a
minimum value of zero to prevent wrap around while converting values
from signed to unsigned integers. The capping of subresults cause slight
inaccuracies therefore capping has been moved from intermediate steps
and done at the end.

Fixes: 0209c11bc1 ("hyptop: Add real SMT utilization field")

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2023-08-21 17:07:44 +02:00
Jan Höppner
dbea311aa8 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2023-08-04 14:51:41 +02:00
275 changed files with 15913 additions and 3612 deletions

View File

@@ -1,5 +1,3 @@
parm
parms
crate
ser
deriver

View File

@@ -29,5 +29,5 @@ indent_size = 4
[{Makefile,*.mak}]
indent_style = tab
[COMMIT_EDITMSG]
[{COMMIT_EDITMSG,EDIT_DESCRIPTION}]
max_line_length = 72

1
.gitignore vendored
View File

@@ -32,6 +32,7 @@ cpacfstats/cpacfstatsd
cpumf/chcpumf
cpumf/lscpumf
cpumf/lshwc
cpumf/lspai
cpumf/pai
cpuplugd/cpuplugd
dasdfmt/dasdfmt

35
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,35 @@
---
exclude: \.(crt|crl)$
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
hooks:
- id: check-merge-conflict
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
exclude_types: ['rust']
- repo: local
hooks:
- id: git-clang-format
name: git-clang-format
description: Run git-clang-format
entry: git
args: [clang-format, --staged, --]
pass_filenames: true
language: system
require_serial: true
minimum_pre_commit_version: "2.9.0"
types_or: [c++, c]
- repo: https://github.com/codespell-project/codespell
rev: v2.2.1
hooks:
- id: codespell
exclude_types: ['rust']
- repo: https://github.com/jumanjihouse/pre-commit-hooks
rev: 3.0.0
hooks:
- id: shellcheck
args: ["--external-sources"]

5
.shellcheckrc Normal file
View File

@@ -0,0 +1,5 @@
# Search in the current script's directory by default (since 0.7.0)
source-path=SCRIPTDIR
# Allow external-sources (since 0.8.0)
external-sources=true

View File

@@ -27,6 +27,7 @@ List of all individuals having contributed content to s390-tools
- Eberhard Pasch
- Eduard Shishkin
- Einar Lueck
- Eric Farman
- Eric Sandeen
- Erwin Vicari
- Eugene Crosser
@@ -35,6 +36,7 @@ List of all individuals having contributed content to s390-tools
- Farhan Ali
- Fedor Loshakov
- Felix Beck
- Finn Callies
- Frank Blaschka
- Frank Heimes
- Frank Munzert
@@ -56,6 +58,7 @@ List of all individuals having contributed content to s390-tools
- Horst Hummel
- Ingo Franzki
- Ingo Tuchscherer
- Jakub Čajka
- Jan Glauber
- Jan Höppner
- Jan Willeke
@@ -124,6 +127,8 @@ List of all individuals having contributed content to s390-tools
- Thomas Richter
- Thomas Spatzier
- Thomas Weber
- Thorsten Winkler
- Tobias Huschle
- Tuan Hoang
- Ursula Braun
- Utz Bacher
@@ -134,3 +139,4 @@ List of all individuals having contributed content to s390-tools
- Volker Sameske
- Wenjia Zhang
- Wolfgang Taphorn
- Yaakov Selkowitz

View File

@@ -1,6 +1,76 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.32.0 (2024-04-03)__
For Linux kernel version: 6.8
Changes of existing tools:
- cpumf/lscpumf: add support for machine type 3932
- genprotimg, pvattest, and pvsecret accept IBM signing key with Armonk as
subject locality
- zdump/zipl: Support for List-Directed dump from ECKD DASD
- zkey: Detect FIPS mode and generate PBKDF for luksFormat according to it
Bug Fixes:
- dbginfo.sh: dash compatible copy sequence
- rust/pv_core: Fix UvDeviceInfo::get() method
- zipl/src: Fix leak of files if run with a broken configuration
- zkey: Fix convert command to accept only keys of type CCA-AESDATA
* __v2.31.0 (2024-02-02)__
For Linux kernel version: 6.7
General:
- common.mak: Set default C/C++ standard to gnu11/gnu++11
Add new tools / libraries:
- pvapconfig: Tool to automatically configure APQNs in SE KVM guests
- s390-tools: Provide pre-commit configuration
Changes of existing tools:
- cpuplugd: Adjust to CPU 0 being no longer hotpluggable
- dbginfo.sh: Check for Dynamic Partition Mode
- dbginfo.sh: Update man page and copyright
- rust/pv: Add user-data signing and verifying
- rust/pvsecret: Add user defined signatures and verifications
- zdev/dracut: Consolidate device configuration
Bug Fixes:
- dbginfo.sh: Fix relative path on script copy
- libkmipclient: Fix build with libxml2-2.12.0
- pvsecret: Fix panic if empty file is used as host key document
- rust/pv: Fix 'elided_lifetimes_in_associated_constant' warning
* __v2.30.0 (2023-12-01)__
For Linux kernel version: 6.6
Add new tools / libraries:
- lspai: Tool to display PAI counter sets
- s390-tools: Provide a ShellCheck configuration
Changes of existing tools / libraries:
- cpumf/pai: Add command line option for realtime scheduling
- dbginfo.sh: enhance ethtool collection for ROCE
- libutil/util_lockfile: add routine to return owning pid of file lock
- lszcrypt: Improve lszcrypt output on SE guests
- rust: Use a single workspace for all rust tools
- zdev: limit the derivation of ZDEV_SITE_ID
- zdump/df_s390: Update 'zgetdump -i' output with zlib info
- zdump/dfi_s390: Support reading compressed s390_ext dumps
- zipl/boot: Integrate zlib compression to single volume DASD dumper
- zipl/boot: compile the bootloaders only if HOST_ARCH is s390x
- zipl: Add --no-compress option to zipl command
- zkey: Also check for deconfigured and check-stopped cards
- dbginfo.sh: fix relative path on script copy
Bug Fixes:
- ap_tools/ap-check: handle get-attributes between pre and post event
- libutil: fix util_file_read_*() using wrong format specifiers
- rust/pv: fix Invalid write of size 1
* __v2.29.0 (2023-08-04)__
For Linux kernel version: 6.5

View File

@@ -386,6 +386,24 @@ the different tools are provided:
- Packages: blktrace, multipath-tools, sg3-utils
- Tools: rsync, tar, lsscsi
* zipl
For CCW-type DASD dump, zlib compression can be used to compress the dump
data before writing it to the DASD partition. It can benefit from
s390 on-chip compression accelerator (DFLTCC) and provide a faster dumping
process, hence lower system downtime.
The zlib version integrated with zipl (zipl/boot/zlib) is based on the Linux
kernel zlib (kernel version 6.3) which represents zlib version 1.1.3 with a
limited number of functions and a number of updates on top including s390
hardware compression (DFLTCC) support. Also, all memory allocations are
performed in advance, which aligns with zipl requirements.
The CCW-type standalone dumper is built as a single binary and must be
loaded to stage2 during boot. Hence, all required zlib functions must be
integrated into it, and its size is restricted. To limit the size, only
deflate-related parts are integrated (no decompression is required during
dumping).
Removing the inflate modules and function prototypes are the only major
modifications made to the kernel version of zlib.
* zgetdump
For building zgetdump you need OpenSSL version 1.1.0 or newer
installed (openssl-devel.rpm). Also required is glib2

View File

@@ -798,12 +798,34 @@ static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
FILE *f;
int rc;
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n", rc);
return -1;
/*
* For the get-attributes callout, we are typically called without the
* callout lock held. However, there is a particular scenario (define
* of an active mdev) where we may or may not be called with the lock
* already held on behalf of mdevctl, depending on the mdevctl version.
* Let's test for lock ownership first and, if already owned by the
* parent (mdevctl) proceed rather than waiting on the file lock.
*/
rc = ap_try_lock_callout();
switch (rc) {
case 0:
/* Lock acquired */
anc->cleanup_lock = true;
break;
case 1:
/* Lock held by parent -- trust the lock will remain held */
break;
default:
/* Lock not acquired or held by parent -- do a normal obtain */
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr,
"Failed to acquire configuration lock %d\n",
rc);
return -1;
}
anc->cleanup_lock = true;
}
anc->cleanup_lock = true;
/*
* Read the 'matrix' and 'control_domains' attributes to get the

View File

@@ -32,7 +32,7 @@ endif
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 29
RELEASE = 32
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -93,19 +93,19 @@ define cmd_define_and_export
endef
define define_toolchain_variables
$(eval $(call cmd_define_and_export, AS$(1)," AS$(1) ",$(2)as))
$(eval $(call cmd_define_and_export, CC$(1)," CC$(1) ",$(2)gcc))
$(eval $(call cmd_define_and_export, LINK$(1)," LINK$(1) ",$$(CC$(1))))
$(eval $(call cmd_define_and_export, CXX$(1)," CXX$(1) ",$(2)g++))
$(eval $(call cmd_define_and_export, LINKXX$(1)," LINKXX$(1) ",$$(CXX$(1))))
$(eval $(call cmd_define_and_export, CPP$(1)," CPP$(1) ",$(2)gcc -E))
$(eval $(call cmd_define_and_export, AR$(1)," AR$(1) ",$(2)ar))
$(eval $(call cmd_define_and_export, NM$(1)," NM$(1) ",$(2)nm))
$(eval $(call cmd_define_and_export, STRIP$(1)," STRIP$(1) ",$(2)strip))
$(eval $(call cmd_define_and_export,OBJCOPY$(1)," OBJCOPY$(1) ",$(2)objcopy))
$(eval $(call cmd_define_and_export,OBJDUMP$(1)," OBJDUMP$(1) ",$(2)objdump))
$(eval PKG_CONFIG$(1) = pkg-config)
$(eval export PKG_CONFIG$(1))
$(call cmd_define_and_export, AS$(1)," AS$(1) ",$(2)as)
$(call cmd_define_and_export, CC$(1)," CC$(1) ",$(2)gcc)
$(call cmd_define_and_export, LINK$(1)," LINK$(1) ",$$(CC$(1)))
$(call cmd_define_and_export, CXX$(1)," CXX$(1) ",$(2)g++)
$(call cmd_define_and_export, LINKXX$(1)," LINKXX$(1) ",$$(CXX$(1)))
$(call cmd_define_and_export, CPP$(1)," CPP$(1) ",$(2)gcc -E)
$(call cmd_define_and_export, AR$(1)," AR$(1) ",$(2)ar)
$(call cmd_define_and_export, NM$(1)," NM$(1) ",$(2)nm)
$(call cmd_define_and_export, STRIP$(1)," STRIP$(1) ",$(2)strip)
$(call cmd_define_and_export,OBJCOPY$(1)," OBJCOPY$(1) ",$(2)objcopy)
$(call cmd_define_and_export,OBJDUMP$(1)," OBJDUMP$(1) ",$(2)objdump)
PKG_CONFIG$(1) = pkg-config
export PKG_CONFIG$(1)
endef
# If the host architecture is not the same as the build architecture
@@ -119,8 +119,8 @@ ifneq ($(HOST_ARCH),$(BUILD_ARCH))
endif
endif
$(call define_toolchain_variables,_FOR_BUILD,)
$(call define_toolchain_variables,,$(CROSS_COMPILE))
$(eval $(call define_toolchain_variables,_FOR_BUILD,))
$(eval $(call define_toolchain_variables,,$(CROSS_COMPILE)))
$(eval $(call cmd_define, RUNTEST," RUNTEST ",$(S390_TEST_LIB_PATH)/s390_runtest))
@@ -304,7 +304,7 @@ ZFCPDUMP_FLAVOR = zfcpdump
export ZFCPDUMP_DIR ZFCPDUMP_IMAGE ZFCPDUMP_INITRD ZFCPDUMP_FLAVOR
CFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
CFLAGS_FOR_BUILD ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
CFLAGS_FOR_BUILD ?= -std=gnu11 $(DEFAULT_CFLAGS) $(OPT_FLAGS)
CPPFLAGS ?= $(DEFAULT_CPPFLAGS)
LDFLAGS ?= $(DEFAULT_LDFLAGS)
@@ -313,14 +313,14 @@ ALL_CFLAGS = -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
-DS390_TOOLS_DATADIR=$(TOOLS_DATADIR) \
-DS390_TOOLS_SYSCONFDIR=$(SYSCONFDIR) \
-DS390_TOOLS_BINDIR=$(BINDIR) \
$(CFLAGS)
-std=gnu11 $(CFLAGS)
CXXFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
ALL_CXXFLAGS = -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
-DS390_TOOLS_LIBDIR=$(TOOLS_LIBDIR) \
-DS390_TOOLS_DATADIR=$(TOOLS_DATADIR) \
-DS390_TOOLS_SYSCONFDIR=$(SYSCONFDIR) \
-DS390_TOOLS_BINDIR=$(BINDIR) \
$(CXXFLAGS)
-std=gnu++11 $(CXXFLAGS)
ALL_CPPFLAGS = -I $(rootdir)include $(CPPFLAGS)
ALL_LDFLAGS = $(LDFLAGS)

View File

@@ -355,13 +355,13 @@ PCKMO DES,
.IP \(bu
PCKMO 2key TDES,
.IP \(bu
PCMKO TDES,
PCKMO TDES,
.IP \(bu
PCKMO AES 128bit,
.IP \(bu
PCKMO AES 192bit,
.IP \(bu
PCMKO AES 256bit,
PCKMO AES 256bit,
.IP \(bu
PCKMO ECC P256,
.IP \(bu

View File

@@ -204,10 +204,10 @@ static const char *const pai_str[] = {
[142] = "KDSA EdDSA Sign Ed448 protected key",
[143] = "PCKMO DES",
[144] = "PCKMO 2key TDES",
[145] = "PCMKO TDES",
[145] = "PCKMO TDES",
[146] = "PCKMO AES 128bit",
[147] = "PCKMO AES 192bit",
[148] = "PCMKO AES 256bit",
[148] = "PCKMO AES 256bit",
[149] = "PCKMO ECC P256",
[150] = "PCKMO ECC P384",
[151] = "PCKMO ECC P521",

View File

@@ -1,7 +1,7 @@
include ../common.mak
BIN_FILES = lscpumf chcpumf lshwc pai
MAN_FILES = lscpumf.8 chcpumf.8 lshwc.8 pai.8
BIN_FILES = lscpumf chcpumf lshwc pai lspai
MAN_FILES = lscpumf.8 chcpumf.8 lshwc.8 pai.8 lspai.8
all: $(BIN_FILES)
@@ -11,6 +11,7 @@ lscpumf: lscpumf.o $(libs)
chcpumf: chcpumf.o $(libs)
lshwc: lshwc.o $(libs)
pai: pai.o $(libs)
lspai: lspai.o $(libs)
install: all install-man
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8

View File

@@ -3473,6 +3473,7 @@ static struct counters *get_counter(int ctrset, size_t *len)
read_ccerror(cp, *len);
break;
case UTIL_ARCH_MACHINE_TYPE_Z16:
case UTIL_ARCH_MACHINE_TYPE_Z16_A02:
cp = cpumcf_z16_counters;
*len = ARRAY_SIZE(cpumcf_z16_counters);
}

352
cpumf/lspai.c Normal file
View File

@@ -0,0 +1,352 @@
/* Copyright IBM Corp. 2023
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* List available Processor Assist Instrumentation (PAI) counters. */
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "lib/util_base.h"
#include "lib/util_path.h"
#include "lib/util_scandir.h"
#include "lib/util_libc.h"
#include "lib/util_file.h"
#include "lib/util_list.h"
#include "lib/libcpumf.h"
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPTIONS"),
{
.option = { "numeric", no_argument, NULL, 'n' },
.desc = "Sort PAI counters by counter number"
},
{
.option = { "type", required_argument, NULL, 't' },
.argument = "TYPE",
.desc = "Type of PAI counters to show: crypto, nnpa"
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
static const struct util_prg prg = {
.desc = "List Processor Assist Information counter sets",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2023,
.pub_last = 2023,
},
UTIL_PRG_COPYRIGHT_END
}
};
static bool numsort; /* If true sort counter numerically */
#define PAI_PATH "/bus/event_source/devices/%s"
enum pai_types { /* Bit mask for supported PAI counters */
pai_type_crypto = 0, /* PAI Crypto Counters */
pai_type_nnpa = 1, /* PAI NNPA Counters */
pai_type_max = 2, /* PAI maximum value, must be last */
};
static int pai_types_show;
struct pai_ctrname { /* List of defined counters */
char *name; /* Counter name */
unsigned long nr; /* Counter number */
};
struct pai_node { /* Head for PAI counter sets */
struct util_list_node node; /* Successor in PAI counter set list */
enum pai_types type; /* PAI type */
int pmu; /* Assigned PMU type number */
const char *name; /* Counter set name */
char *name_uc; /* Counter set name upper case */
const char *sysfs_name; /* Counter set name in /sysfs tree */
const char *filter_name; /* Counter set name for scandir filter */
struct pai_ctrname *ctrlist; /* List of counter names & numbers */
size_t ctrsize; /* Total size in bytes of ctrlist */
int ctridx; /* Index of last entry used in ctrlist */
unsigned long base; /* Base number for counter set */
};
static struct util_list pai_list;
/* Return base of counter set, this is the first counter of this set. */
static unsigned long pai_type_base(enum pai_types t)
{
switch (t) {
case pai_type_crypto:
return 0x1000;
case pai_type_nnpa:
return 0x1800;
case pai_type_max:
break;
}
return 0;
}
/* Test PAI counter name from command line option. */
static const char *pai_type_name(enum pai_types t)
{
switch (t) {
case pai_type_crypto:
return "crypto";
case pai_type_nnpa:
return "nnpa";
case pai_type_max:
break;
}
return "unknown";
}
/* Convert PAI counter type to sysfs directory name. Only validated
* input at this time.
*/
static const char *pai_type_sysfs(enum pai_types t)
{
if (t == pai_type_crypto)
return "pai_crypto";
return "pai_ext";
}
/* Convert PAI counter type to sysfs directory name filter for scandir(). */
static const char *pai_type_filter(enum pai_types t)
{
if (t == pai_type_nnpa)
return "^NNPA";
return "[^.]"; /* Matches anything but . and .. in sysfs */
}
/* Sort PAI counter names by assigned counter number. */
static int pai_ctrcmp(const void *p1, const void *p2)
{
struct pai_ctrname *l = (struct pai_ctrname *)p1;
struct pai_ctrname *r = (struct pai_ctrname *)p2;
return l->nr > r->nr ? 1 : -1;
}
/* Convert string to upper case. */
static char *str2uc(const char *s)
{
char *uc = util_strdup(s), *old_uc = uc;
for (; *uc; ++uc)
*uc = toupper(*uc);
return old_uc;
}
/* Read counter names and assigned event number from sysfs file tree.
* Exit when sysfs directory can not be scanned.
*/
static void read_counternames(struct pai_node *node)
{
int i, more = 0, ctr = 0, count = 0;
struct dirent **namelist = NULL;
char *path, *ctrpath;
/* Read counter names and assigned event number. */
path = util_path_sysfs(PAI_PATH "/events", node->sysfs_name);
count = util_scandir(&namelist, alphasort, path, node->filter_name);
if (count <= 0)
errx(EXIT_FAILURE, "Cannot open %s", path);
node->ctrsize = count * sizeof(*node->ctrlist);
node->ctrlist = util_malloc(node->ctrsize);
for (i = 0; i < count && ctr >= 0; i++) {
util_asprintf(&ctrpath, "%s/%s", path, namelist[i]->d_name);
if (util_file_read_va(ctrpath, "event=%x", &ctr) == 1) {
node->ctrlist[node->ctridx].name = util_strdup(namelist[i]->d_name);
node->ctrlist[node->ctridx++].nr = ctr;
more++;
} else {
warnx("Cannot parse %s", ctrpath);
}
free(ctrpath);
}
util_scandir_free(namelist, count);
free(path);
if (numsort && more > 1)
qsort(node->ctrlist, more, sizeof(*node->ctrlist), pai_ctrcmp);
}
static void show_painode(void)
{
struct pai_node *node;
int indent = 0;
int offset = 0;
util_list_iterate(&pai_list, node) {
for (int i = 0; i < node->ctridx; ++i)
indent = MAX((size_t)indent, strlen(node->ctrlist[i].name));
}
printf("RAW %*s NAME %*s DESCRIPTION\n", 3, "", indent - 5, "");
util_list_iterate(&pai_list, node) {
for (int i = 0; i < node->ctridx; ++i) {
printf("%d:%ld %s", node->pmu,
node->ctrlist[i].nr, node->ctrlist[i].name);
offset = indent - strlen(node->ctrlist[i].name) + 1;
printf("%*s", offset, "");
printf("Counter %ld / PAI %s counter set\n",
node->ctrlist[i].nr - node->base, node->name_uc);
}
}
}
/* Release all memory allocated at make_painode(). */
static void free_painode(void)
{
struct pai_node *next, *node;
util_list_iterate_safe(&pai_list, node, next) {
free(node->name_uc);
for (int i = 0; i < node->ctridx; ++i)
free(node->ctrlist[i].name);
free(node->ctrlist);
free(node);
}
}
static void make_painode(enum pai_types t)
{
struct pai_node *node = util_zalloc(sizeof(*node));
char *path;
node->type = t;
node->sysfs_name = pai_type_sysfs(t);
node->name = pai_type_name(t);
node->name_uc = str2uc(node->name);
node->filter_name = pai_type_filter(t);
node->base = pai_type_base(t);
/* Read PMU type number. */
path = util_path_sysfs(PAI_PATH, node->sysfs_name);
node->pmu = libcpumf_pmutype(path);
if (node->pmu < 0)
errx(EXIT_FAILURE, "Cannot open %s", path);
free(path);
read_counternames(node);
util_list_add_tail(&pai_list, node);
}
static int painode_cmp(void *a, void *b, void *UNUSED(data))
{
struct pai_node *n1 = (struct pai_node *)a;
struct pai_node *n2 = (struct pai_node *)b;
return n1->pmu < n2->pmu ? -1 : 1;
}
static void sort_painode(void)
{
util_list_sort(&pai_list, painode_cmp, NULL);
}
/* Check for hardware support and return false if not available. */
static bool have_support(enum pai_types t)
{
const char *sysfn = pai_type_sysfs(t);
char *path = util_path_sysfs(PAI_PATH, sysfn);
bool rc = true;
if (!util_path_is_dir(path)) {
warnx("No support for PAI %s facility", pai_type_name(t));
rc = false;
}
free(path);
return rc;
}
/*
* Check the argument for option -t. It must be a valid PAI counter set.
* Exit when an invalid PAI counter set name has been specified.
*/
static void check_type_name(const char *type)
{
bool no_match = true;
enum pai_types i;
const char *fn;
for (i = pai_type_crypto; i < pai_type_max; ++i) {
fn = pai_type_name(i);
if (!strcasecmp(fn, type)) {
pai_types_show |= (1 << i);
no_match = false;
}
}
if (no_match)
errx(EXIT_FAILURE, "Invalid argument for -t %s", type);
}
int main(int argc, char **argv)
{
int ch;
util_list_init(&pai_list, struct pai_node, node);
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
while ((ch = util_opt_getopt_long(argc, argv)) != -1) {
switch (ch) {
default:
util_opt_print_parse_error(ch, argv);
return EXIT_FAILURE;
case 'h':
util_prg_print_help();
util_opt_print_help();
return EXIT_SUCCESS;
case 'v':
util_prg_print_version();
return EXIT_SUCCESS;
case 'n':
numsort = true;
break;
case 't':
check_type_name(optarg);
break;
}
}
/* Nothing specified, show all PAI counters */
if (!pai_types_show)
pai_types_show = (1 << pai_type_crypto) | (1 << pai_type_nnpa);
/* Check for hardware support */
for (enum pai_types i = pai_type_crypto; i < pai_type_max; ++i) {
if ((pai_types_show & (1 << i))) {
if (!have_support(i))
pai_types_show &= ~(1 << i);
else
make_painode(i);
}
}
sort_painode();
show_painode();
free_painode();
return ch;
}

80
cpumf/man/lspai.8 Normal file
View File

@@ -0,0 +1,80 @@
.\" lspai.8
.\"
.\"
.\" Copyright IBM Corp. 2021
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\" ----------------------------------------------------------------------
.ds c \fBlspai\fP
.
.TH \*c "8" "August 2023" "s390-tools" "CPU-MF management programs"
.
.SH NAME
\*c \- list Processor Activity Instrumentation (PAI) counters
.
.SH SYNOPSIS
\*c
.RB [ \-n ]
.RB [ \-t
.IR "\ TYPE" ]
.br
\*c
.BR \-h | \-\-help
.br
\*c
.BR \-v | \-\-version
.
.
.SH DESCRIPTION
\*c displays the Processor Activity Instrumentation (PAI) counters
for Linux on IBM Z.
The output is a human-readable list of available PAI counter
names and numbers.
.SH OPTIONS
.TP
.BR \-h ", " \-\-help
Displays help information, then exits.
.
.TP
.BR \-v ", " \-\-version
Displays version information, then exits.
.
.TP
.BR \-t ", " \-\-type "\ TYPE"
Specifies the PAI counter set to list.
Valid counter set values are
.I crypto
and
.IR nnpa .
By default, the command lists all available PAI counter sets.
NNPA refers to the Neural Network Processing Assist facility counter set.
Crypto refers to the Cryptografic Processing Assist facility counter set.
.
.TP
.BR \-n ", " \-\-numeric
Shows the PAI counter sets sorted by counter number.
Default sort order is PAI counter name.
.
.SH "EXAMPLE"
The \*c invocation lists all PAI Neural Network Processing Assist Facility
(NNPA) counters in numeric order:
.nf
# lspai -t nnpa -n
RAW NAME DESCRIPTION
13:6144 NNPA_ALL Counter 0 / PAI NNPA counter set
13:6145 NNPA_ADD Counter 1 / PAI NNPA counter set
13:6146 NNPA_SUB Counter 2 / PAI NNPA counter set
13:6147 NNPA_MUL Counter 3 / PAI NNPA counter set
\&...
.fi
The first column shows the raw event number suitable for
.IR perf "(8)"
raw event specification.
The second column shows the PAI NNPA counter name,
suitable for
.IR perf "(8)"
event specification by name.
The third gives a short explanation, if available.
.SH "SEE ALSO"
.BR pai (8)
.BR lscpumf (8)

View File

@@ -18,6 +18,8 @@
.IR size ]
.RB [ \-i | \-\-interval
.IR ms ]
.RB [ \-R | \-\-realtime
.IR prio ]
.BR \-c | \-\-crypto [ \fIcpulist ][: \fIdata\fR "] [" \fIloops\fP ]
.br
\*c
@@ -25,6 +27,8 @@
.IR size ]
.RB [ \-i | \-\-interval
.IR ms ]
.RB [ \-R | \-\-realtime
.IR prio ]
.BR \-n | \-\-nnpa [ \fIcpulist ][: \fIdata\fR "] [" \fIloops\fP ]
.br
\*c
@@ -191,6 +195,14 @@ The ring buffer is created with the
.IR mmap (2)
system call.
.
.TP
.BR \-R ", " \-\-realtime "\ prio"
Collect data using the RT SCHED_FIFO priority specified by
.BR prio .
Valid values are integers in the range 1 (low) to 99 (high).
Use this option when gathering data from multiple CPUs
to prevent data loss.
.
.SH ARGUMENT
The command line options determine how command line
arguments are interpreted.

View File

@@ -320,7 +320,7 @@ static void readmap(int fd)
* ring buffer per event, sleep some short time and always read all
* ring buffer for new contents.
*/
static void collect(unsigned long cnt)
static int collect(unsigned long cnt)
{
fd_set r_fds, e_fds, a_fds;
struct pai_event *p;
@@ -328,6 +328,7 @@ static void collect(unsigned long cnt)
int rc, max_fd;
do {
rc = -1;
max_fd = -1;
tv.tv_sec = read_interval / 1000;
tv.tv_usec = (1000 * read_interval) % 1000000;
@@ -357,6 +358,7 @@ static void collect(unsigned long cnt)
}
}
} while (rc != -1 && --cnt > 0);
return rc;
}
static void lookup_event(__u64 evtnum, __u16 ctr, __u64 value)
@@ -449,6 +451,11 @@ static void evt_show(__u64 evtnum, const char *evtsel, struct pai_event_out *ev)
ev->u.s_comm.tid);
break;
case PERF_RECORD_SWITCH:
printf("cs-%s",
(ev->misc & PERF_RECORD_MISC_SWITCH_OUT) ? "out" : "in");
break;
case PERF_RECORD_SWITCH_CPU_WIDE:
if (ev->misc & PERF_RECORD_MISC_SWITCH_OUT) {
short p = PERF_RECORD_MISC_SWITCH_OUT_PREEMPT;
@@ -549,6 +556,9 @@ static int evt_scan(char *fn, unsigned char *buf, size_t len,
offset -= sizeof(__u64);
break;
case PERF_RECORD_SWITCH:
break;
case PERF_RECORD_SWITCH_CPU_WIDE:
memcpy(&ev.u, buf + offset, sizeof(ev.u.s_cs));
offset += sizeof(ev.u.s_cs);
@@ -583,7 +593,7 @@ static int evt_scan(char *fn, unsigned char *buf, size_t len,
break;
default:
printf("unknown header-type %d ", hdr->type);
printf("unknown header-type %d\n", hdr->type);
offset += hdr->size - sizeof(*hdr);
goto bypass;
}
@@ -944,6 +954,11 @@ static struct util_opt opt_vec[] = {
.option = { "report", no_argument, NULL, 'r' },
.desc = "Report file contents"
},
{
.option = { "realtime", required_argument, NULL, 'R' },
.argument = "PRIO",
.desc = "Collect data with this RT SCHED_FIFO priority"
},
{
.option = { "interval", required_argument, NULL, 'i' },
.argument = "NUMBER",
@@ -1007,6 +1022,19 @@ static unsigned long check_mapsize(unsigned long n)
return cnt == 1 ? n : 0;
}
static void setprio(const char *prio)
{
struct sched_param param;
char *endstr;
memset(&param, 0, sizeof(param));
param.sched_priority = strtoul(prio, &endstr, 0);
if (*endstr)
errno = EINVAL;
if (*endstr || sched_setscheduler(0, SCHED_FIFO, &param))
err(EXIT_FAILURE, "Could not set realtime priority");
}
int main(int argc, char **argv)
{
bool crypto_record = false, report = false;
@@ -1061,6 +1089,9 @@ int main(int argc, char **argv)
record_cpus_nnpa(optarg);
nnpa_record = true;
break;
case 'R':
setprio(optarg);
break;
case 'r':
report = true;
break;
@@ -1094,12 +1125,12 @@ int main(int argc, char **argv)
ev_install(group);
ev_enable();
collect(loop_count);
ch = collect(loop_count);
ev_disable();
ev_deinstall();
ev_dealloc();
return EXIT_SUCCESS;
return ch < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* Must be reporting */

View File

@@ -25,7 +25,7 @@ int get_numcpus()
for (i = 0; ; i++) {
/* check whether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i);
sprintf(path, "/sys/devices/system/cpu/cpu%d", i);
if (access(path, R_OK) == 0)
number++;
else
@@ -45,11 +45,13 @@ int get_num_online_cpus()
int status = 0;
int value_of_onlinefile, rc;
for (i = 0; i <= get_numcpus(); i++) {
for (i = 0; i < get_numcpus(); i++) {
/* check wether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i);
if (access(path, R_OK) != 0)
if (access(path, R_OK) != 0) {
status++;
continue;
}
filp = fopen(path, "r");
if (!filp)
cpuplugd_exit("Cannot open cpu online file: "
@@ -101,10 +103,8 @@ int hotplug(int cpuid)
cpuid);
return -1;
}
} else {
cpuplugd_error("hotplugging cpu with id %d failed\n", cpuid);
return -1;
}
cpuplugd_debug("cpu with id %d cannot be hotplugged\n", cpuid);
return -1;
}
@@ -135,9 +135,8 @@ int hotunplug(int cpuid)
fclose(filp);
if (state == 0)
return 1;
} else {
cpuplugd_error("unplugging cpu with id %d failed\n", cpuid);
}
cpuplugd_debug("cpu with id %d cannot be hotunplugged\n", cpuid);
return retval;
}
@@ -163,6 +162,8 @@ int is_online(int cpuid)
retval = 0;
}
fclose(filp);
} else {
retval = 1;
}
return retval;
}

View File

@@ -15,13 +15,13 @@ dasdfmt \- formatting of DASD (ECKD) disk drives.
.SH DESCRIPTION
\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
for usage with Linux for S/390.
for usage with Linux for S/390.
The \fIdevice\fR is the node of the device (e.g. '/dev/dasda').
Any device node created by udev for kernel 2.6 can be used
Any device node created by udev for kernel 2.6 can be used
(e.g. '/dev/dasd/0.0.b100/disc').
.br
\fBWARNING\fR: Careless usage of \fBdasdfmt\fR can result in
\fBWARNING\fR: Careless usage of \fBdasdfmt\fR can result in
\fBLOSS OF DATA\fR.
.SH OPTIONS
@@ -31,7 +31,7 @@ Print usage and exit.
.TP
\fB-t\fR or \fB--test\fR
Disables any modification of the disk drive.
Disables any modification of the disk drive.
.br
\fBdasdfmt\fR just prints
out, what it \fBwould\fR do.
@@ -41,7 +41,7 @@ out, what it \fBwould\fR do.
Increases verbosity.
.TP
\fB-y\fR
\fB-y\fR
Start formatting without further user-confirmation.
.TP
@@ -59,7 +59,7 @@ Omit the writing of a disk label after formatting.
.br
This makes only sense for the 'ldl' disk layout.
.br
The '-L' option has to be specified after the '-d ldl' option.
The '-L' option has to be specified after the '-d ldl' option.
.br
e.g. dasdfmt -d ldl -L /dev/...
@@ -84,13 +84,13 @@ Formats the device with compatible disk layout or linux disk layout.
\fIlayout\fR is either \fIcdl\fR for the compatible disk layout
(default) or \fIldl\fR for the linux disk layout.
.br
Compatible disk layout means a special handling of the
first two tracks of the volume. This enables other S/390 or zSeries
Compatible disk layout means a special handling of the
first two tracks of the volume. This enables other S/390 or zSeries
operating systems to access this device (e.g. for backup purposes).
.TP
\fB-p\fR or \fB--progressbar\fR
Print a progress bar while formatting.
Print a progress bar while formatting.
Do not use this option if you are using a 3270 console,
running in background or redirecting the output to a file.
@@ -164,30 +164,30 @@ and always be a power of two. The recommended blocksize is 4096 bytes.
.TP
\fB-l\fR \fIvolser\fR or \fB--label\fR=\fIvolser\fR
Specify the volume serial number or volume identifier to be written
to disk after formatting. If no label is specified, a sensible default
is used. \fIvolser\fR is interpreted as ASCII string and is automatically
Specify the volume serial number or volume identifier to be written
to disk after formatting. If no label is specified, a sensible default
is used. \fIvolser\fR is interpreted as ASCII string and is automatically
converted to uppercase and then to EBCDIC.
.br
e.g. -l LNX001 or --label=DASD01
.br
The \fIvolser\fR identifies by serial number the volume. A volume serial
The \fIvolser\fR identifies by serial number the volume. A volume serial
number is 1 through 6 alphanumeric or one of the following special
characters: $, #, @, %. Enclose a serial number that contains special
characters in apostrophes. If the number is shorter than six
characters: $, #, @, %. Enclose a serial number that contains special
characters in apostrophes. If the number is shorter than six
characters, it is padded with trailing blanks.
.br
.br
Do not code a volume serial number as SCRTCH, PRIVAT, or Lnnnnn (L with
five numbers); these are used in OS/390 messages to ask the operator to
mount a volume. Do not code a volume serial number as MIGRAT, which is
used by the OS/390 Hierarchical Storage Manager DFSMShsm for migrated
Do not code a volume serial number as SCRTCH, PRIVAT, or Lnnnnn (L with
five numbers); these are used in OS/390 messages to ask the operator to
mount a volume. Do not code a volume serial number as MIGRAT, which is
used by the OS/390 Hierarchical Storage Manager DFSMShsm for migrated
data sets.
.br
NOTE: Try to avoid using special characters in the volume serial. This may cause problems accessing a disk by volser.
NOTE: Try to avoid using special characters in the volume serial. This may cause problems accessing a disk by volser.
.br
In case you really have to use special characters, make sure you are using quotes. In addition there is a special handling for the '$' sign. Please specify it using '\\$' if necessary.
.br
@@ -197,9 +197,8 @@ e.g. -l 'a@b\\$c#' to get A@B$C#
.TP
\fB-k\fR or \fB--keep_volser\fR
Keeps the Volume Serial Number, when writing the Volume Label. This is
useful, if the Serial Number has been written with a VM Tool and should not
be overwritten.
Keeps the Volume Serial Number when writing the Volume Label. This is useful if
the volume already has a Serial Number that should not be overwritten.
.br
.SH SEE ALSO

View File

@@ -1,7 +1,7 @@
# Common definitions
include ../../common.mak
ALL_CPPFLAGS += -I../include -std=gnu99 -Wno-unused-parameter
ALL_CPPFLAGS += -I../include -Wno-unused-parameter
LDLIBS += -lpthread -lrt
ifneq ($(HAVE_ZLIB),0)
ALL_CPPFLAGS += -DHAVE_ZLIB

View File

@@ -28,6 +28,15 @@
# DEVICE=0.0.4e13
# DELAY_MINUTES=5
#
# Dump on ECKD device (DASD)
#
#ON_PANIC=dump
#DUMP_TYPE=eckd
#DEVICE=0.0.1004
#BOOTPROG=0
#BR_CHR=auto
#
# Dump on fcp device (SCSI Disk)
#

View File

@@ -19,10 +19,10 @@ help:
.br
\fBfdasd\fR {-h|-v}
.SH DESCRIPTION
\fBfdasd\fR writes a partition table to a cdl (compatible disk layout)
\fBfdasd\fR writes a partition table to a cdl (compatible disk layout)
formatted DASD, in the form of
a VTOC (volume table of contents) for usage with Linux for S/390
or zSeries. If fdasd detects a valid \fBVOL1\fR volume label, it
or zSeries. If fdasd detects a valid \fBVOL1\fR volume label, it
will use it, otherwise it asks to write a new one.
.br
@@ -34,51 +34,51 @@ will use it, otherwise it asks to write a new one.
Print usage information, then exit.
.TP
\fB-v\fR or \fB--version\fR
\fB-v\fR or \fB--version\fR
Print version information, then exit.
.TP
\fB-s\fR or \fB--silent\fR
\fB-s\fR or \fB--silent\fR
Suppress messages in non-interactive mode.
.TP
\fB-r\fR or \fB--verbose\fR
\fB-r\fR or \fB--verbose\fR
Provide more verbose output.
.TP
\fB-a\fR or \fB--auto\fR
Automatically create a partition using the entire disk in non-interactive
\fB-a\fR or \fB--auto\fR
Automatically create a partition using the entire disk in non-interactive
mode.
.TP
\fB-k\fR or \fB--keep_volser\fR
Keeps the volume serial when writing the volume label.
Keeps the Volume Serial Number when writing the Volume Label.
.br
This is useful, if the volume serial has been written before and should not
be overwritten. This option is only applicable in non-interactive mode.
This is useful if the volume already has a Serial Number that should not be
overwritten. This option is only applicable in non-interactive mode.
.TP
\fB-l\fR \fIvolser\fR or \fB--label\fR \fIvolser\fR
Specify the volume serial.
.br
\fIvolser\fR is interpreted as ASCII string and is automatically converted to
\fIvolser\fR is interpreted as ASCII string and is automatically converted to
uppercase, padded with blanks and finally converted to EBCDIC to be written
to disk. This option is only applicable in non-interactive mode.
.br
Do not use the following reserved volume serial: SCRTCH, PRIVAT, MIGRAT,
or Lnnnnn (L with five digit number); These are used as keywords by
Do not use the following reserved volume serial: SCRTCH, PRIVAT, MIGRAT,
or Lnnnnn (L with five digit number); These are used as keywords by
other operating systems (OS/390).
.br
A volume serial is 1 through 6 alphanumeric characters or one of the
following special characters: $, #, @, %. All other characters are simply
ignored.
A volume serial is 1 through 6 alphanumeric characters or one of the
following special characters: $, #, @, %. All other characters are simply
ignored.
.br
Try to avoid using special characters in the volume serial.
This may cause problems accessing a disk by volser.
In case you really have to use special characters, make sure you are using
quotes. In addition there is a special handling for the '$' sign.
Try to avoid using special characters in the volume serial.
This may cause problems accessing a disk by volser.
In case you really have to use special characters, make sure you are using
quotes. In addition there is a special handling for the '$' sign.
Please specify it using '\\$' if necessary.
.br
@@ -124,14 +124,14 @@ partitions that use the entire disk:
.br
.TP
\fB-i\fR or \fB--volser\fR
\fB-i\fR or \fB--volser\fR
Print the volume serial, then exit.
.TP
\fB-p\fR or \fB--table\fR
Print partition table, then exit.
\fB-p\fR or \fB--table\fR
Print partition table, then exit.
.br
In combination with the -s option fdasd will display a short version of the
In combination with the -s option fdasd will display a short version of the
partition table.
.TP
@@ -179,7 +179,7 @@ In case your are not using the device file system, please specify:
.br
where \fIx\fR is one or more lowercase letter(s) or any other device
node specification configured by udev for kernel 2.6 or higher.
node specification configured by udev for kernel 2.6 or higher.
.SH SEE ALSO
.BR dasdfmt (8)

View File

@@ -3,7 +3,7 @@ include ../common.mak
.DEFAULT_GOAL := all
PKGDATADIR := "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
PKGDATADIR := "$(TOOLS_DATADIR)/genprotimg"
TESTS :=
SUBDIRS := boot src man
RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
@@ -11,8 +11,8 @@ RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
all: all-recursive
install: install-recursive
$(INSTALL) -d -m 755 "$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(PKGDATADIR)"
$(INSTALL) -d -m 755 "$(DESTDIR)$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(DESTDIR)$(PKGDATADIR)"
clean: clean-recursive

View File

@@ -7,7 +7,7 @@ DEBUG_FILES := $(addsuffix .debug,$(FILES))
ifeq ($(HOST_ARCH),s390x)
ZIPL_DIR := $(rootdir)/zipl
ZIPL_BOOT_DIR := $(ZIPL_DIR)/boot
PKGDATADIR := $(DESTDIR)$(TOOLS_DATADIR)/genprotimg
PKGDATADIR := $(TOOLS_DATADIR)/genprotimg
INCLUDE_PATHS := $(ZIPL_BOOT_DIR) $(ZIPL_DIR)/include $(rootdir)/include
INCLUDE_PARMS := $(addprefix -I,$(INCLUDE_PATHS))
@@ -79,15 +79,16 @@ stage3b.elf: head.o $(ZIPL_OBJS)
%.bin.debug: %.elf
$(OBJCOPY) --only-keep-debug $< $@
@chmod a-x $@
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
@chmod a-x $@
install: stage3a.bin stage3b_reloc.bin
$(INSTALL) -d -m 755 "$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3a.bin "$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3b_reloc.bin "$(PKGDATADIR)"
$(INSTALL) -d -m 755 "$(DESTDIR)$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3a.bin "$(DESTDIR)$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3b_reloc.bin "$(DESTDIR)$(PKGDATADIR)"
else
# Don't generate the dependency files (see `common.mak` for the

View File

@@ -61,13 +61,17 @@ void __noreturn start(void)
if (cmdline->size > get_kernel_cmdline_size())
panic(EINTERNAL, "Command line is too large\n");
/* move the kernel cmdline */
memmove((void *)COMMAND_LINE,
(void *)cmdline->src,
cmdline->size);
if (cmdline->size > 0) {
/* make sure the cmdline is a null-terminated string */
if (((char *)cmdline->src)[cmdline->size - 1] != '\0')
panic(EINTERNAL, "Command line needs to be null-terminated\n");
/* move the kernel cmdline */
memmove((void *)COMMAND_LINE, (void *)cmdline->src, cmdline->size);
}
/* the initrd does not need to be moved */
if (initrd->size != 0) {
if (initrd->size > 0) {
/* copy initrd start address and size into new kernel space */
*(unsigned long long *)INITRD_START = initrd->src;
*(unsigned long long *)INITRD_SIZE = initrd->size;

View File

@@ -4,7 +4,7 @@
#
# Sample script to verify that a host key document is genuine by
# verifying the issuer, the validity date and the signature.
# Optionally verify the full trust chain using a CA certficate.
# Optionally verify the full trust chain using a CA certificate.
#
# Sample invocation:
#
@@ -15,31 +15,33 @@
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
# Allocate temporary files
ISSUER_PUBKEY_FILE=$(mktemp)
SIGNATURE_FILE=$(mktemp)
BODY_FILE=$(mktemp)
ISSUER_DN_FILE=$(mktemp)
SUBJECT_DN_FILE=$(mktemp)
DEF_ISSUER_DN_FILE=$(mktemp)
DEF_ISSUER_ARMONK_DN_FILE=$(mktemp)
DEF_ISSUER_POUGHKEEPSIE_DN_FILE=$(mktemp)
CANONICAL_ISSUER_DN_FILE=$(mktemp)
CRL_SERIAL_FILE=$(mktemp)
# Cleanup on exit
cleanup()
{
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
$CANONICAL_ISSUER_DN_FILE $CRL_SERIAL_FILE
rm -f "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" \
"$ISSUER_DN_FILE" "$SUBJECT_DN_FILE" "$DEF_ISSUER_ARMONK_DN_FILE" "$DEF_ISSUER_POUGHKEEPSIE_DN_FILE" \
"$CANONICAL_ISSUER_DN_FILE" "$CRL_SERIAL_FILE"
}
trap cleanup EXIT
# Enhanced error checking for bash
if [ -n "${BASH}" ]
then
if [ -n "${BASH}" ]; then
# shellcheck disable=SC3040
set -o posix
# shellcheck disable=SC3040
set -o pipefail
# shellcheck disable=SC3040
set -o nounset
fi
set -e
@@ -47,8 +49,8 @@ set -e
# Usage
usage()
{
cat <<-EOF
Usage: `basename $1` [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
cat <<-EOF
Usage: $(basename "$1") [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
Verify an IBM Secure Execution host key document against
a signing key.
@@ -71,8 +73,7 @@ check_verify_chain()
{
# Verify certificate chain in case a CA certificate file/bundle
# was specified on the command line.
if [ $# = 1 ]
then
if [ -z "$2" ]; then
cat >&2 <<-EOF
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
No CA certificate specified! Skipping trust chain verification.
@@ -80,37 +81,37 @@ Make sure that '$1' is a valid certificate.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
EOF
else
openssl verify -crl_download -crl_check $2 &&
openssl verify -crl_download -crl_check -untrusted $2 $1 ||
exit 1
openssl verify -crl_download -crl_check "$2" &&
openssl verify -crl_download -crl_check -untrusted "$2" "$1" ||
exit 1
fi
}
extract_pubkey()
{
openssl x509 -in $1 -pubkey -noout > $2
openssl x509 -in "$1" -pubkey -noout >"$2"
}
extract_signature()
{
# Assuming that the last field is the signature
SIGOFFSET=$(openssl asn1parse -in $1 | tail -1 | cut -d : -f 1)
SIGOFFSET=$(openssl asn1parse -in "$1" | tail -1 | cut -d : -f 1)
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
openssl asn1parse -in "$1" -out "$2" -strparse "$SIGOFFSET" -noout
}
extract_body()
{
# Assuming that the first field is the full cert body
SIGOFFSET=$(openssl asn1parse -in $1 | head -2 | tail -1 | cut -d : -f 1)
SIGOFFSET=$(openssl asn1parse -in "$1" | head -2 | tail -1 | cut -d : -f 1)
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
openssl asn1parse -in "$1" -out "$2" -strparse "$SIGOFFSET" -noout
}
verify_signature()
{
# Assuming that the signature algorithm is SHA512 with RSA
openssl sha512 -verify $1 -signature $2 $3
openssl sha512 -verify "$1" -signature "$2" "$3"
}
canonical_dn()
@@ -120,18 +121,30 @@ canonical_dn()
DNTYPE=$3
OUTPUT=$4
openssl $OBJTYPE -in $OBJ -$DNTYPE -noout -nameopt multiline \
| sort | grep -v $DNTYPE= > $OUTPUT
openssl "$OBJTYPE" -in "$OBJ" -"$DNTYPE" -noout -nameopt multiline |
LC_ALL=C sort | grep -v "$DNTYPE"= >"$OUTPUT"
}
default_issuer()
default_issuer_armonk()
{
cat <<-EOF
commonName = International Business Machines Corporation
countryName = US
localityName = Armonk
organizationName = International Business Machines Corporation
organizationalUnitName = Key Signing Service
stateOrProvinceName = New York
EOF
}
default_issuer_pougkeepsie()
{
cat <<-EOF
commonName = International Business Machines Corporation
countryName = US
localityName = Poughkeepsie
organizationalUnitName = Key Signing Service
organizationName = International Business Machines Corporation
organizationalUnitName = Key Signing Service
stateOrProvinceName = New York
EOF
}
@@ -141,42 +154,37 @@ EOF
# stripping off the prefix
verify_default_issuer()
{
default_issuer > $DEF_ISSUER_DN_FILE
default_issuer_pougkeepsie >"$DEF_ISSUER_POUGHKEEPSIE_DN_FILE"
default_issuer_armonk >"$DEF_ISSUER_ARMONK_DN_FILE"
sed "s/\(^[ ]*organizationalUnitName[ ]*=[ ]*\).*\(Key Signing Service$\)/\1\2/" \
$ISSUER_DN_FILE > $CANONICAL_ISSUER_DN_FILE
"$ISSUER_DN_FILE" >"$CANONICAL_ISSUER_DN_FILE"
if ! diff $CANONICAL_ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
then
if ! {
diff "$CANONICAL_ISSUER_DN_FILE" "$DEF_ISSUER_POUGHKEEPSIE_DN_FILE" ||
diff "$CANONICAL_ISSUER_DN_FILE" "$DEF_ISSUER_ARMONK_DN_FILE"
} >/dev/null 2>&1; then
echo Incorrect default issuer >&2 && exit 1
fi
}
verify_issuer_files()
{
if [ $1 -eq 1 ]
then
verify_default_issuer
fi
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
then
echo Issuer verification OK
else
echo Issuer verification failed >&2 && exit 1
if [ "$1" -eq 1 ]; then
verify_default_issuer
fi
}
cert_time()
{
DATE=$(openssl x509 -in $1 -$2 -noout | sed "s/^.*=//")
DATE=$(openssl x509 -in "$1" -"$2" -noout | sed "s/^.*=//")
date -d "$DATE" +%s
}
crl_time()
{
DATE=$(openssl crl -in $1 -$2 -noout | sed "s/^.*=//")
DATE=$(openssl crl -in "$1" -"$2" -noout | sed "s/^.*=//")
date -d "$DATE" +%s
}
@@ -188,8 +196,7 @@ verify_dates()
MSG="${3:-Certificate}"
NOW=$(date +%s)
if [ $START -le $NOW -a $NOW -le $END ]
then
if [ "$START" -le "$NOW" ] && [ "$NOW" -le "$END" ]; then
echo "${MSG} dates are OK"
else
echo "${MSG} date verification failed" >&2 && exit 1
@@ -198,22 +205,21 @@ verify_dates()
crl_serials()
{
openssl crl -in $1 -text -noout | \
grep "Serial Number" > $CRL_SERIAL_FILE
openssl crl -in "$1" -text -noout |
grep "Serial Number" >"$CRL_SERIAL_FILE"
}
check_serial()
{
CERT_SERIAL=$(openssl x509 -in $1 -noout -serial | cut -d = -f 2)
CERT_SERIAL=$(openssl x509 -in "$1" -noout -serial | cut -d = -f 2)
grep -q $CERT_SERIAL $CRL_SERIAL_FILE
grep -q "$CERT_SERIAL" "$CRL_SERIAL_FILE"
}
check_file()
{
[ $# = 0 ] ||
[ -e "$1" ] ||
(echo "File '$1' not found" >&2 && exit 1)
(echo "File '$1' not found" >&2 && exit 1)
}
# check args
@@ -221,28 +227,25 @@ CRL_FILE=
CA_FILE=
CHECK_DEFAULT_ISSUER=1
args=$(getopt -qu "dr:c:h" $*)
if [ $? = 0 ]
then
set -- $args
while [ $1 != "" ]
do
case $1 in
-d) CHECK_DEFAULT_ISSUER=0; shift;;
-r) CRL_FILE=$2; shift 2;;
-c) CA_FILE=$2; shift 2;;
-h) usage $0; exit 0;;
--) shift; break;;
esac
done
else
usage $0 >&2
exit 1
fi
while getopts 'dr:c:h' opt; do
case $opt in
d) CHECK_DEFAULT_ISSUER=0 ;;
r) CRL_FILE=$OPTARG ;;
c) CA_FILE=$OPTARG ;;
h)
usage "$0"
exit 0
;;
?)
usage "$0"
exit 1
;;
esac
done
shift "$((OPTIND - 1))"
if [ $# -ne 2 ]
then
usage $0 >&2
if [ $# -ne 2 ]; then
usage "$0" >&2
exit 1
fi
@@ -250,51 +253,51 @@ HKD_FILE=$1
HKSK_FILE=$2
# Check whether all specified files exist
check_file $HKD_FILE
check_file $HKSK_FILE
check_file $CA_FILE
check_file $CRL_FILE
check_file "$HKD_FILE"
check_file "$HKSK_FILE"
# CA and CRL are optional arguments
[ -n "$CA_FILE" ] && check_file "$CA_FILE"
[ -n "$CRL_FILE" ] && check_file "$CRL_FILE"
# Check trust chain
check_verify_chain $HKSK_FILE $CA_FILE
check_verify_chain "$HKSK_FILE" "$CA_FILE"
# Verify host key document signature
echo -n "Checking host key document signature: "
extract_pubkey $HKSK_FILE $ISSUER_PUBKEY_FILE &&
extract_signature $HKD_FILE $SIGNATURE_FILE &&
extract_body $HKD_FILE $BODY_FILE &&
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
exit 1
printf "Checking host key document signature: "
extract_pubkey "$HKSK_FILE" "$ISSUER_PUBKEY_FILE" &&
extract_signature "$HKD_FILE" "$SIGNATURE_FILE" &&
extract_body "$HKD_FILE" "$BODY_FILE" &&
verify_signature "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" ||
exit 1
# Verify the issuer
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
canonical_dn x509 "$HKD_FILE" issuer "$ISSUER_DN_FILE"
canonical_dn x509 "$HKSK_FILE" subject "$SUBJECT_DN_FILE"
verify_issuer_files $CHECK_DEFAULT_ISSUER
# Verify dates
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
verify_dates "$(cert_time "$HKD_FILE" startdate)" "$(cert_time "$HKD_FILE" enddate)"
# Check CRL if specified
if [ -n "$CRL_FILE" ]
then
echo -n "Checking CRL signature: "
extract_signature $CRL_FILE $SIGNATURE_FILE &&
extract_body $CRL_FILE $BODY_FILE &&
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
exit 1
if [ -n "$CRL_FILE" ]; then
printf "Checking CRL signature: "
extract_signature "$CRL_FILE" "$SIGNATURE_FILE" &&
extract_body "$CRL_FILE" "$BODY_FILE" &&
verify_signature "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" ||
exit 1
echo -n "CRL "
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
printf "CRL "
canonical_dn crl "$CRL_FILE" issuer "$ISSUER_DN_FILE"
canonical_dn x509 "$HKSK_FILE" subject "$SUBJECT_DN_FILE"
verify_issuer_files $CHECK_DEFAULT_ISSUER
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
verify_dates "$(crl_time "$CRL_FILE" lastupdate)" "$(crl_time "$CRL_FILE" nextupdate)" 'CRL'
crl_serials $CRL_FILE
check_serial $HKD_FILE &&
echo "Certificate is revoked, do not use it anymore!" >&2 &&
exit 1
crl_serials "$CRL_FILE"
check_serial "$HKD_FILE" &&
echo "Certificate is revoked, do not use it anymore!" >&2 &&
exit 1
fi
# We made it
echo All checks reqested for \'$HKD_FILE\' were successful
echo All checks requested for \'"$HKD_FILE"\' were successful

View File

@@ -3,7 +3,7 @@ include ../../common.mak
bin_PROGRAM = genprotimg
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
PKGDATADIR ?= "$(TOOLS_DATADIR)/genprotimg"
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
TOP_SRCDIR := $(SRC_DIR)/../
ROOT_DIR = $(TOP_SRC_DIR)/../../
@@ -27,7 +27,7 @@ $(bin_PROGRAM)_SRCS := $(bin_PROGRAM).c pv/pv_stage3.c pv/pv_image.c \
$(NULL)
$(bin_PROGRAM)_OBJS := $($(bin_PROGRAM)_SRCS:.c=.o)
ALL_CFLAGS += -std=gnu11 -DPKGDATADIR=$(PKGDATADIR) \
ALL_CFLAGS += -DPKGDATADIR=$(PKGDATADIR) \
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBCURL_CFLAGS) \
-DOPENSSL_API_COMPAT=0x10100000L \
$(WARNINGS) \

View File

@@ -17,7 +17,8 @@
/* IBM signing key subject */
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK "Armonk"
#define PV_IBM_Z_SUBJECT_ORGANIZATIONONAL_UNIT_NAME_SUFFIX "Key Signing Service"
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_STATE "New York"

View File

@@ -684,7 +684,26 @@ gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err)
{
g_autoptr(PvComponent) comp = NULL;
comp = pv_component_new_file(arg->type, arg->path, err);
switch (arg->type) {
case PV_COMP_TYPE_INITRD:
case PV_COMP_TYPE_KERNEL:
case PV_COMP_TYPE_STAGE3B:
comp = pv_component_new_file(arg->type, arg->path, err);
break;
case PV_COMP_TYPE_CMDLINE: {
g_autoptr(PvBuffer) buf = NULL;
g_autofree char *data = NULL;
gsize length;
if (!g_file_get_contents(arg->path, &data, &length, err))
return -1;
/* Add one for the null terminator */
buf = pv_buffer_take(g_steal_pointer(&data), length + 1);
comp = pv_component_new_buf(arg->type, buf, err);
} break;
}
if (!comp)
return -1;

View File

@@ -26,6 +26,15 @@ PvBuffer *pv_buffer_alloc(gsize size)
return ret;
}
PvBuffer *pv_buffer_take(char *data, gsize size)
{
PvBuffer *ret = g_new0(PvBuffer, 1);
ret->data = data;
ret->size = size;
return ret;
}
PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned)
{
PvBuffer *ret;

View File

@@ -21,6 +21,10 @@ typedef struct PvBuffer {
} PvBuffer;
PvBuffer *pv_buffer_alloc(gsize size);
/* After this call @data belongs to the PvBuffer and must no longer be modified
* by the caller.
*/
PvBuffer *pv_buffer_take(char *data, gsize size);
void pv_buffer_free(PvBuffer *buf);
void pv_buffer_clear(PvBuffer **buf);
gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err);

View File

@@ -664,62 +664,9 @@ static gboolean x509_name_data_by_nid_equal(X509_NAME *name, gint nid,
return memcmp(data, y, data_len) == 0;
}
static gboolean own_X509_NAME_ENTRY_equal(const X509_NAME_ENTRY *x,
const X509_NAME_ENTRY *y)
{
const ASN1_OBJECT *x_obj = X509_NAME_ENTRY_get_object(x);
const ASN1_STRING *x_data = X509_NAME_ENTRY_get_data(x);
const ASN1_OBJECT *y_obj = X509_NAME_ENTRY_get_object(y);
const ASN1_STRING *y_data = X509_NAME_ENTRY_get_data(y);
gint x_len = ASN1_STRING_length(x_data);
gint y_len = ASN1_STRING_length(y_data);
if (x_len < 0 || x_len != y_len)
return FALSE;
/* ASN1_STRING_cmp(x_data, y_data) == 0 doesn't work because it also
* compares the type, which is sometimes different.
*/
return OBJ_cmp(x_obj, y_obj) == 0 &&
memcmp(ASN1_STRING_get0_data(x_data),
ASN1_STRING_get0_data(y_data),
(unsigned long)x_len) == 0;
}
static gboolean own_X509_NAME_equal(const X509_NAME *x, const X509_NAME *y)
{
gint x_count = X509_NAME_entry_count(x);
gint y_count = X509_NAME_entry_count(y);
if (x != y && (!x || !y))
return FALSE;
if (x_count != y_count)
return FALSE;
for (gint i = 0; i < x_count; i++) {
const X509_NAME_ENTRY *entry_i = X509_NAME_get_entry(x, i);
gboolean entry_found = FALSE;
for (gint j = 0; j < y_count; j++) {
const X509_NAME_ENTRY *entry_j =
X509_NAME_get_entry(y, j);
if (own_X509_NAME_ENTRY_equal(entry_i, entry_j)) {
entry_found = TRUE;
break;
}
}
if (!entry_found)
return FALSE;
}
return TRUE;
}
/* Checks whether the subject of @cert is a IBM signing key subject. For this we
* must check that the subject is equal to: 'C = US, ST = New York, L =
* Poughkeepsie, O = International Business Machines Corporation, CN =
* Poughkeepsie or Armonk, O = International Business Machines Corporation, CN =
* International Business Machines Corporation' and the organization unit (OUT)
* must end with the suffix ' Key Signing Service'.
*/
@@ -743,8 +690,10 @@ static gboolean has_ibm_signing_subject(X509 *cert)
PV_IBM_Z_SUBJECT_STATE))
return FALSE;
if (!x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME))
if (!(x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE) ||
x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK)))
return FALSE;
if (!x509_name_data_by_nid_equal(subject, NID_organizationName,
@@ -806,6 +755,39 @@ static X509_NAME *x509_name_reorder_attributes(const X509_NAME *name, const gint
return g_steal_pointer(&ret);
}
/** Replace locality 'Armonk' with 'Pougkeepsie'. If Armonk was not set return
* `NULL`.
*/
static X509_NAME *x509_armonk_locality_fixup(const X509_NAME *name)
{
g_autoptr(X509_NAME) ret = NULL;
int pos;
/* Check if ``L=Armonk`` */
if (!x509_name_data_by_nid_equal((X509_NAME *)name, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK))
return NULL;
ret = X509_NAME_dup((X509_NAME *)name);
if (!ret)
g_abort();
pos = X509_NAME_get_index_by_NID(ret, NID_localityName, -1);
if (pos == -1)
return NULL;
X509_NAME_ENTRY_free(X509_NAME_delete_entry(ret, pos));
/* Create a new name entry at the same position as before */
if (X509_NAME_add_entry_by_NID(
ret, NID_localityName, MBSTRING_UTF8,
(const unsigned char *)&PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE,
sizeof(PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE) - 1, pos, 0) != 1)
return NULL;
return g_steal_pointer(&ret);
}
/* In RFC 5280 the attributes of a (subject/issuer) name is not mandatory
* ordered. The problem is that our certificates are not consistent in the order
* (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4 for details).
@@ -828,24 +810,10 @@ X509_NAME *c2b_name(const X509_NAME *name)
return X509_NAME_dup((X509_NAME *)name);
}
/* Verify that: subject(issuer) == issuer(crl) and SKID(issuer) == AKID(crl) */
/* Verify that SKID(issuer) == AKID(crl) if available */
static gint check_crl_issuer(X509_CRL *crl, X509 *issuer, GError **err)
{
const X509_NAME *crl_issuer = X509_CRL_get_issuer(crl);
const X509_NAME *issuer_subject = X509_get_subject_name(issuer);
AUTHORITY_KEYID *akid = NULL;
if (!own_X509_NAME_equal(issuer_subject, crl_issuer)) {
g_autofree char *issuer_subject_str = X509_NAME_oneline(issuer_subject,
NULL, 0);
g_autofree char *crl_issuer_str = X509_NAME_oneline(crl_issuer, NULL, 0);
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
_("issuer mismatch:\n%s\n%s"),
issuer_subject_str, crl_issuer_str);
return -1;
}
g_autoptr(AUTHORITY_KEYID) akid = NULL;
/* If AKID(@crl) is specified it must match with SKID(@issuer) */
akid = X509_CRL_get_ext_d2i(crl, NID_authority_key_identifier, NULL, NULL);
@@ -881,7 +849,6 @@ gint check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
return -1;
}
/* check that the @crl issuer matches with the subject name of @cert*/
if (check_crl_issuer(crl, cert, err) < 0)
return -1;
@@ -910,6 +877,60 @@ gint check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
return 0;
}
/* This function contains work-arounds for some known subject(CRT)<->issuer(CRL)
* issues.
*/
static STACK_OF_X509_CRL *quirk_X509_STORE_ctx_get1_crls(X509_STORE_CTX *ctx,
const X509_NAME *subject, GError **err)
{
g_autoptr(X509_NAME) fixed_subject = NULL;
g_autoptr(STACK_OF_X509_CRL) ret = NULL;
ret = Pv_X509_STORE_CTX_get1_crls(ctx, subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
/* Workaround to fix the mismatch between issuer name of the * IBM
* signing CRLs and the IBM signing key subject name. Locality name has
* changed from Poughkeepsie to Armonk.
*/
fixed_subject = x509_armonk_locality_fixup(subject);
/* Was the locality replaced? */
if (fixed_subject) {
X509_NAME *tmp;
sk_X509_CRL_free(ret);
ret = Pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
/* Workaround to fix the ordering mismatch between issuer name
* of the IBM signing CRLs and the IBM signing key subject name.
*/
tmp = fixed_subject;
fixed_subject = c2b_name(fixed_subject);
X509_NAME_free(tmp);
sk_X509_CRL_free(ret);
ret = Pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
X509_NAME_free(fixed_subject);
fixed_subject = NULL;
}
/* Workaround to fix the ordering mismatch between issuer name of the
* IBM signing CRLs and the IBM signing key subject name.
*/
fixed_subject = c2b_name(subject);
sk_X509_CRL_free(ret);
ret = Pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_CRL, _("no CRL found"));
return NULL;
}
/* Given a certificate @cert try to find valid revocation lists in @ctx. If no
* valid CRL was found NULL is returned.
*/
@@ -927,20 +948,9 @@ STACK_OF_X509_CRL *store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert,
return NULL;
}
ret = X509_STORE_CTX_get1_crls(ctx, subject);
if (!ret) {
/* Workaround to fix the mismatch between issuer name of the
* IBM Z signing CRLs and the IBM Z signing key subject name.
*/
g_autoptr(X509_NAME) broken_subject = c2b_name(subject);
ret = X509_STORE_CTX_get1_crls(ctx, broken_subject);
if (!ret) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_CRL,
_("no CRL found"));
return NULL;
}
}
ret = quirk_X509_STORE_ctx_get1_crls(ctx, subject, err);
if (!ret)
return NULL;
/* Filter out non-valid CRLs for @cert */
for (gint i = 0; i < sk_X509_CRL_num(ret); i++) {
@@ -1328,32 +1338,14 @@ gint check_chain_parameters(const STACK_OF_X509 *chain,
/* It's almost the same as X509_check_issed from OpenSSL does except that we
* don't check the key usage of the potential issuer. This means we check:
* 1. issuer_name(cert) == subject_name(issuer)
* 2. Check whether the akid(cert) (if available) matches the issuer skid
* 3. Check that the cert algrithm matches the subject algorithm
* 4. Verify the signature of certificate @cert is using the public key of
* 1. Check whether the akid(cert) (if available) matches the issuer skid
* 2. Check that the cert algrithm matches the subject algorithm
* 3. Verify the signature of certificate @cert is using the public key of
* @issuer.
*/
static gint check_host_key_issued(X509 *cert, X509 *issuer, GError **err)
{
const X509_NAME *issuer_subject = X509_get_subject_name(issuer);
const X509_NAME *cert_issuer = X509_get_issuer_name(cert);
AUTHORITY_KEYID *akid = NULL;
/* We cannot use X509_NAME_cmp() because it considers the order of the
* X509_NAME_Entries.
*/
if (!own_X509_NAME_equal(issuer_subject, cert_issuer)) {
g_autofree char *issuer_subject_str =
X509_NAME_oneline(issuer_subject, NULL, 0);
g_autofree char *cert_issuer_str =
X509_NAME_oneline(cert_issuer, NULL, 0);
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
_("Subject issuer mismatch:\n'%s'\n'%s'"),
issuer_subject_str, cert_issuer_str);
return -1;
}
g_autoptr(AUTHORITY_KEYID) akid = NULL;
akid = X509_get_ext_d2i(cert, NID_authority_key_identifier, NULL, NULL);
if (akid && X509_check_akid(issuer, akid) != X509_V_OK) {
@@ -1834,14 +1826,12 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
g_assert(out_len >= 0);
num_bytes_written = BIO_write(b_out, out_buf, out_len);
if (num_bytes_written < 0) {
if (num_bytes_written != out_len) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("Failed to write"));
return -1;
}
g_assert(num_bytes_written == out_len);
tmp_size_out += (guint)num_bytes_written;
/* Set new tweak value. Please keep in mind that the

View File

@@ -75,6 +75,7 @@ void x509_pair_free(x509_pair *pair);
/* Register auto cleanup functions */
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)

View File

@@ -404,11 +404,11 @@ s64 ht_calculate_smt_util(u64 core_us, u64 thr_us, u64 mgm_us, int thread_per_co
s64 component1, component2, smt_us;
double smt_factor = g.o.smt_factor;
component1 = G0(thread_per_core * core_us - thr_us);
component1 = thread_per_core * core_us - thr_us;
if (thread_per_core > 1)
component1 /= smt_factor;
component2 = G0(thr_us - core_us);
smt_us = component1 + component2 + mgm_us;
component2 = thr_us - core_us;
smt_us = G0(component1 + component2 + mgm_us);
return smt_us;
}

View File

@@ -22,11 +22,19 @@
#define STAGE2_DESC _AC(0x78, UL)
#define STAGE2_ENTRY _AC(0x2018, UL)
#define STAGE2_HEAP_ADDRESS _AC(0x6000, UL)
#define ECKD2DUMP_SV_HEAP_ADDRESS _AC(0xb000, UL)
#define STAGE2_HEAP_SIZE _AC(0x3000, UL)
#define STAGE2_STACK_ADDRESS _AC(0xe400, UL)
#define STAGE2_STACK_SIZE _AC(0x1c00, UL)
#define ECKD2DUMP_SV_STACK_ADDRESS _AC(0xe000, UL)
#define ECKD2DUMP_SV_STACK_SIZE _AC(0x2000, UL)
#define STAGE2_MAX_SIZE _AC(0x3000, UL)
#define STAGE2_DUMPER_SIZE_V1 _AC(0x1000, UL)
#define STAGE2_DUMPER_SIZE_V2 _AC(0x2000, UL)
#define STAGE2_DUMPER_SIZE_V3 _AC(0x3000, UL)
#define STAGE2_DUMPER_SIZE_ZLIB _AC(0x8000, UL)
#define STAGE3_ENTRY _AC(0xa000, UL)
#define STAGE2_LOAD_ADDRESS _AC(0x2000, UL)

View File

@@ -25,6 +25,7 @@
#define STACK_FRAME_OVERHEAD _AC(160, U)
/* Facilities */
#define DFLTCC_FACILITY _AC(151, U)
#define UNPACK_FACILITY _AC(161, U)
#ifndef __ASSEMBLER__

145
include/dump/s390_dump.h Normal file
View File

@@ -0,0 +1,145 @@
/*
* s390 related definitions and functions.
*
* Copyright IBM Corp. 2013, 2023
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef S390_DUMP_H
#define S390_DUMP_H
#include <stdint.h>
#include "boot/page.h"
#include "lib/zt_common.h"
/*
* S390 dump format defines
*/
#define DF_S390_MAGIC 0xa8190173618f23fdULL
#define DF_S390_MAGIC_EXT 0xa8190173618f23feULL
#define DF_S390_HDR_SIZE 0x1000
#define DF_S390_EM_SIZE 16
#define DF_S390_EM_MAGIC 0x44554d505f454e44ULL
#define DF_S390_EM_STR "DUMP_END"
#define DF_S390_CPU_MAX 512
#define DF_S390_MAGIC_BLK_ECKD 3
#define DF_S390_DUMPER_MAGIC_SIZE 7
#define DF_S390_DUMPER_MAGIC32 "ZECKD31"
#define DF_S390_DUMPER_MAGIC64 "ZECKD64"
#define DF_S390_DUMPER_MAGIC_EXT "XECKD64"
#define DF_S390_DUMPER_MAGIC32_FBA "ZDFBA31"
#define DF_S390_DUMPER_MAGIC64_FBA "ZDFBA64"
#define DF_S390_DUMPER_MAGIC_FBA_EXT "XDFBA64"
#define DF_S390_DUMPER_MAGIC_MV "ZMULT64"
#define DF_S390_DUMPER_MAGIC_MV_EXT "XMULT64"
#define OLD_DUMPER_HEX_INSTR1 "\x0d\x10\x47\xf0" /* BASR + 1st halfword of BC */
#define OLD_DUMPER_HEX_INSTR2 "\x0d\xd0" /* BASR 13,0 */
/*
* Architecture of dumped system
*/
enum df_s390_arch {
DF_S390_ARCH_32 = 1,
DF_S390_ARCH_64 = 2,
};
/*
* zipl parameters passed at tail of dump tools
*/
struct stage2dump_parm_tail {
char reserved[6];
uint8_t no_compress;
uint8_t mvdump_force;
uint64_t mem_upper_limit;
} __packed;
/*
* s390 dump header format
*/
struct df_s390_hdr {
uint64_t magic; /* 0x000 */
uint32_t version; /* 0x008 */
uint32_t hdr_size; /* 0x00c */
uint32_t dump_level; /* 0x010 */
uint32_t page_size; /* 0x014 */
uint64_t mem_size; /* 0x018 */
uint64_t mem_start; /* 0x020 */
uint64_t mem_end; /* 0x028 */
uint32_t num_pages; /* 0x030 */
uint32_t pad; /* 0x034 */
uint64_t tod; /* 0x038 */
uint64_t cpu_id; /* 0x040 */
uint32_t arch; /* 0x048 */
uint32_t volnr; /* 0x04c */
uint32_t build_arch; /* 0x050 */
uint64_t mem_size_real; /* 0x054 */
uint8_t mvdump; /* 0x05c */
uint16_t cpu_cnt; /* 0x05d */
uint16_t real_cpu_cnt; /* 0x05f */
uint8_t zlib_version_s390; /* 0x061 */
uint32_t zlib_entry_size; /* 0x062 */
uint8_t end_pad1[0x200 - 0x066]; /* 0x066 */
uint64_t mvdump_sign; /* 0x200 */
uint64_t mvdump_zipl_time; /* 0x208 */
uint8_t end_pad2[0x800 - 0x210]; /* 0x210 */
uint32_t lc_vec[DF_S390_CPU_MAX]; /* 0x800 */
} __packed __aligned(16);
/*
* End marker: Should be at the end of every valid s390 crash dump
*/
struct df_s390_em {
union {
uint64_t magic;
char str[8];
};
uint64_t tod;
} __packed __aligned(16);
/*
* Dump segment header
*/
struct df_s390_dump_segm_hdr {
union {
struct {
uint64_t start; /* 0x000 */
uint64_t len; /* 0x008 */
uint64_t stop_marker; /* 0x010 */
/* Size in blocks of compressed dump segment written to disk */
uint32_t size_on_disk; /* 0x018 */
uint8_t reserved_pad[0x30 - 0x1c]; /* 0x01c */
/*
* Number of compressed entries in this dump segment (up to
* 1011 entries)
*/
uint32_t entry_count; /* 0x030 */
/*
* Offsets in blocks to compressed entries written to disk
* from the start of the dump segment.
* High-order bit is set if the entry has been written
* uncompressed.
*/
uint32_t entry_offset[]; /* 0x034 */
} __packed;
uint8_t padding[PAGE_SIZE];
};
};
/* Data compression granularity (size of input data chunk for zlib deflate) */
#define DUMP_SEGM_ZLIB_ENTSIZE (1 * MIB)
/* Maximum number of compressed entries in one dump segment */
#define DUMP_SEGM_ZLIB_MAXENTS ((sizeof(struct df_s390_dump_segm_hdr) \
- offsetof(struct df_s390_dump_segm_hdr, entry_offset)) \
/ sizeof(uint32_t))
/*
* Maximum length of compressed dump segment considering the size of
* a single input chunk
*/
#define DUMP_SEGM_ZLIB_MAXLEN (DUMP_SEGM_ZLIB_MAXENTS * DUMP_SEGM_ZLIB_ENTSIZE)
/* Bitmask to mark uncompressed chunks */
#define DUMP_SEGM_ENTRY_UNCOMPRESSED 0x80000000
#endif /* S390_DUMP_H */

View File

@@ -89,6 +89,7 @@ void ap_list_remove_all(struct util_list *list);
/* Lock Functions */
int ap_get_lock(void);
int ap_get_lock_callout(void);
int ap_try_lock_callout(void);
int ap_release_lock(void);
int ap_release_lock_callout(void);

View File

@@ -27,6 +27,7 @@ enum util_arch_machine_type {
UTIL_ARCH_MACHINE_TYPE_Z15 = 8561,
UTIL_ARCH_MACHINE_TYPE_Z15_T02 = 8562,
UTIL_ARCH_MACHINE_TYPE_Z16 = 3931,
UTIL_ARCH_MACHINE_TYPE_Z16_A02 = 3932,
};
int util_arch_machine_type(void);

View File

@@ -23,4 +23,6 @@ int util_lockfile_parent_lock(char *lockfile, int retries);
int util_lockfile_release(char *lockfile);
int util_lockfile_parent_release(char *lockfile);
int util_lockfile_peek_owner(char *lockfile, int *pid);
#endif /** LIB_UTIL_LOCKFILE_H @} */

View File

@@ -40,6 +40,7 @@
#define LV_COMPAT_CYL 0xFFFE
#define VTOC_ERROR "VTOC error:"
#define MAX_VTOC_ENTRIES 9 /* max number of VTOC labels for cdl formatted DASD */
typedef struct ttr
{

View File

@@ -16,7 +16,8 @@
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK "Armonk"
#define PV_IBM_Z_SUBJECT_ORGANIZATIONAL_UNIT_NAME_SUFFIX "Key Signing Service"
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_STATE "New York"

View File

@@ -722,6 +722,34 @@ int ap_get_lock_callout(void)
return util_lockfile_parent_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
}
/**
* Attempt to acquire the ap config lock using the Parent Process ID without
* waiting/retries. Detect if the attempt was rejected because the lock is
* already held by the Parent Process ID.
*
* @retval 0 Lock acquired on behalf of parent process
* @retval 1 Lock not obtained, already held by parent
* @retval != 0 Lock was not obtained, other error
*/
int ap_try_lock_callout(void)
{
int pid, ppid, rc;
if (util_lockfile_parent_lock(AP_LOCKFILE, 0)) {
/* Lock is already held, let's peek at the owner */
ppid = getppid();
rc = util_lockfile_peek_owner(AP_LOCKFILE, &pid);
if (rc || pid != ppid) {
/* We didn't get the lock, unknown or other owner */
return 2;
}
/* Signify that the lock is already held by the caller */
return 1;
}
return 0;
}
/**
* Release the ap config lock
*

View File

@@ -55,7 +55,7 @@ check-dep-libekmfweb: detect-openssl-version.dep
"detect-openssl-version.dep", \
"openssl-devel version >= 1.1.1", \
"HAVE_OPENSSL=0", \
-I. -lcrypto -DOPENSSL_SUPPRESS_DEPRECATED)
-I. `$(PKG_CONFIG) --cflags --libs libcrypto` -DOPENSSL_SUPPRESS_DEPRECATED)
$(call check_dep, \
"libekmfweb", \
"json-c/json.h", \
@@ -66,7 +66,7 @@ check-dep-libekmfweb: detect-openssl-version.dep
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0" \
`$(CURL_CONFIG) --cflags` `$(CURL_CONFIG) --libs`)
`$(PKG_CONFIG) --cflags --libs libcurl`)
$(CURL_CONFIG) --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
touch check-dep-libekmfweb
@@ -85,8 +85,8 @@ ekmfweb.o: check-dep-libekmfweb ekmfweb.c utilities.h cca.h $(rootdir)include/ek
utilities.o: check-dep-libekmfweb utilities.c utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
cca.o: check-dep-libekmfweb cca.c cca.h utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `$(CURL_CONFIG) --cflags`
libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `$(CURL_CONFIG) --libs` -ldl
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `$(PKG_CONFIG) --cflags json-c libcurl libcrypto libssl`
libekmfweb.so.$(VERSION): LDLIBS = `$(PKG_CONFIG) --libs json-c libcurl libcrypto libssl` -ldl
libekmfweb.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libekmfweb.map \
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libekmfweb.so.$(VERM)
libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o $(libs)

View File

@@ -51,7 +51,6 @@ detect-openssl-version.dep:
mv $(TMPFILE) $@
CURL_CONFIG ?= curl-config
XML2_CONFIG ?= xml2-config
check-dep-libkmipclient: detect-openssl-version.dep
$(call check_dep, \
@@ -59,7 +58,7 @@ check-dep-libkmipclient: detect-openssl-version.dep
"detect-openssl-version.dep", \
"openssl-devel version >= 1.1.1", \
"HAVE_OPENSSL=0", \
-I. -lcrypto -DOPENSSL_SUPPRESS_DEPRECATED)
-I. `$(PKG_CONFIG) --cflags --libs libcrypto` -DOPENSSL_SUPPRESS_DEPRECATED)
$(call check_dep, \
"libkmipclient", \
"json-c/json.h", \
@@ -70,13 +69,13 @@ check-dep-libkmipclient: detect-openssl-version.dep
"libxml/tree.h", \
"libxml2-devel", \
"HAVE_LIBXML2=0", \
`$(XML2_CONFIG) --cflags` `$(XML2_CONFIG) --libs`)
`$(PKG_CONFIG) --cflags --libs libxml-2.0`)
$(call check_dep, \
"libkmipclient", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0" \
`$(CURL_CONFIG) --cflags` `$(CURL_CONFIG) --libs`)
`$(PKG_CONFIG) --cflags --libs libcurl`)
$(CURL_CONFIG) --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
touch check-dep-libkmipclient
@@ -107,8 +106,8 @@ tls.o: check-dep-libkmipclient tls.c kmip.h utils.h $(rootdir)include/kmipclient
names.o: check-dep-libkmipclient names.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
utils.o: check-dep-libkmipclient utils.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
libkmipclient.so.$(VERSION): ALL_CFLAGS += -fPIC `$(XML2_CONFIG) --cflags` `$(CURL_CONFIG) --cflags`
libkmipclient.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `$(XML2_CONFIG) --libs` `$(CURL_CONFIG) --libs`
libkmipclient.so.$(VERSION): ALL_CFLAGS += -fPIC `$(PKG_CONFIG) --cflags json-c libcrypto libssl libxml-2.0 libcurl`
libkmipclient.so.$(VERSION): LDLIBS = `$(PKG_CONFIG) --libs json-c libcrypto libssl libxml-2.0 libcurl`
libkmipclient.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libkmipclient.map \
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libkmipclient.so.$(VERM)
libkmipclient.so.$(VERSION): kmip.o request.o response.o attribute.o key.o ttlv.o json.o \

View File

@@ -16,6 +16,7 @@
#include <openssl/ssl.h>
#include <json-c/json.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <curl/curl.h>

View File

@@ -21,8 +21,7 @@ WARNINGS := -Wall -Wextra -Wshadow \
-Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \
$(NULL)
ALL_CFLAGS += -std=gnu11 \
-DOPENSSL_API_COMPAT=0x10101000L \
ALL_CFLAGS += -DOPENSSL_API_COMPAT=0x10101000L \
$(GLIB2_CFLAGS) \
$(LIBCRYPTO_CFLAGS) \
$(LIBCURL_CFLAGS) \

View File

@@ -857,7 +857,7 @@ static gboolean x509_name_data_by_nid_equal(X509_NAME *name, int nid, const char
/* Checks whether the subject of @cert is a IBM signing key subject. For this we
* must check that the subject is equal to: 'C = US, ST = New York, L =
* Poughkeepsie, O = International Business Machines Corporation, CN =
* Poughkeepsie or Armonk, O = International Business Machines Corporation, CN =
* International Business Machines Corporation' and the organization unit (OUT)
* must end with the suffix ' Key Signing Service'.
*/
@@ -879,7 +879,10 @@ static gboolean has_ibm_signing_subject(X509 *cert)
if (!x509_name_data_by_nid_equal(subject, NID_stateOrProvinceName, PV_IBM_Z_SUBJECT_STATE))
return FALSE;
if (!x509_name_data_by_nid_equal(subject, NID_localityName, PV_IBM_Z_SUBJECT_LOCALITY_NAME))
if (!(x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE) ||
x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK)))
return FALSE;
if (!x509_name_data_by_nid_equal(subject, NID_organizationName,
@@ -1085,10 +1088,9 @@ static int check_signature_algo_match(const EVP_PKEY *pkey, const X509 *subject,
/* It's almost the same as X509_check_issed from OpenSSL does except that we
* don't check the key usage of the potential issuer. This means we check:
* 1. issuer_name(cert) == subject_name(issuer)
* 2. Check whether the akid(cert) (if available) matches the issuer skid
* 3. Check that the cert algrithm matches the subject algorithm
* 4. Verify the signature of certificate @cert is using the public key of
* 1. Check whether the akid(cert) (if available) matches the issuer skid
* 2. Check that the cert algrithm matches the subject algorithm
* 3. Verify the signature of certificate @cert is using the public key of
* @issuer.
*/
static int check_host_key_issued(X509 *cert, X509 *issuer, GError **error)
@@ -1097,19 +1099,6 @@ static int check_host_key_issued(X509 *cert, X509 *issuer, GError **error)
const X509_NAME *cert_issuer = X509_get_issuer_name(cert);
g_autoptr(AUTHORITY_KEYID) akid = NULL;
/* We cannot use X509_NAME_cmp() because it considers the order of the
* X509_NAME_Entries.
*/
if (!own_X509_NAME_equal(issuer_subject, cert_issuer)) {
g_autofree char *issuer_subject_str = pv_X509_NAME_oneline(issuer_subject);
g_autofree char *cert_issuer_str = pv_X509_NAME_oneline(cert_issuer);
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
_("Subject issuer mismatch:\n'%s'\n'%s'"), issuer_subject_str,
cert_issuer_str);
return -1;
}
akid = X509_get_ext_d2i(cert, NID_authority_key_identifier, NULL, NULL);
if (akid && X509_check_akid(issuer, akid) != X509_V_OK) {
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_SKID_AKID_MISMATCH,
@@ -1286,21 +1275,10 @@ int pv_verify_cert(X509_STORE_CTX *ctx, X509 *cert, GError **error)
return 0;
}
/* Verify that: subject(issuer) == issuer(crl) and SKID(issuer) == AKID(crl) */
/* Verify that SKID(issuer) == AKID(crl) */
static int check_crl_issuer(X509_CRL *crl, X509 *issuer, GError **error)
{
const X509_NAME *crl_issuer = X509_CRL_get_issuer(crl);
const X509_NAME *issuer_subject = X509_get_subject_name(issuer);
AUTHORITY_KEYID *akid = NULL;
if (!own_X509_NAME_equal(issuer_subject, crl_issuer)) {
g_autofree char *issuer_subject_str = pv_X509_NAME_oneline(issuer_subject);
g_autofree char *crl_issuer_str = pv_X509_NAME_oneline(crl_issuer);
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
_("issuer mismatch:\n%s\n%s"), issuer_subject_str, crl_issuer_str);
return -1;
}
g_autoptr(AUTHORITY_KEYID) akid = NULL;
/* If AKID(@crl) is specified it must match with SKID(@issuer) */
akid = X509_CRL_get_ext_d2i(crl, NID_authority_key_identifier, NULL, NULL);
@@ -1325,7 +1303,6 @@ int pv_verify_crl(X509_CRL *crl, X509 *cert, int verify_flags, GError **error)
return -1;
}
/* check that the @crl issuer matches with the subject name of @cert*/
if (check_crl_issuer(crl, cert, error) < 0)
return -1;
@@ -1393,6 +1370,93 @@ int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error)
return 0;
}
/** Replace locality 'Armonk' with 'Pougkeepsie'. If Armonk was not set return
* `NULL`.
*/
static X509_NAME *x509_armonk_locality_fixup(const X509_NAME *name)
{
g_autoptr(X509_NAME) ret = NULL;
int pos;
/* Check if ``L=Armonk`` */
if (!x509_name_data_by_nid_equal((X509_NAME *)name, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK))
return NULL;
ret = X509_NAME_dup((X509_NAME *)name);
if (!ret)
g_abort();
pos = X509_NAME_get_index_by_NID(ret, NID_localityName, -1);
if (pos == -1)
return NULL;
X509_NAME_ENTRY_free(X509_NAME_delete_entry(ret, pos));
/* Create a new name entry at the same position as before */
if (X509_NAME_add_entry_by_NID(
ret, NID_localityName, MBSTRING_UTF8,
(const unsigned char *)&PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE,
sizeof(PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE) - 1, pos, 0) != 1)
return NULL;
return g_steal_pointer(&ret);
}
/* This function contains work-arounds for some known subject(CRT)<->issuer(CRL)
* issues.
*/
static STACK_OF_X509_CRL *quirk_X509_STORE_ctx_get1_crls(X509_STORE_CTX *ctx,
const X509_NAME *subject, GError **err)
{
g_autoptr(X509_NAME) fixed_subject = NULL;
g_autoptr(STACK_OF_X509_CRL) ret = NULL;
ret = pv_X509_STORE_CTX_get1_crls(ctx, subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
/* Workaround to fix the mismatch between issuer name of the * IBM
* signing CRLs and the IBM signing key subject name. Locality name has
* changed from Poughkeepsie to Armonk.
*/
fixed_subject = x509_armonk_locality_fixup(subject);
/* Was the locality replaced? */
if (fixed_subject) {
X509_NAME *tmp;
sk_X509_CRL_free(ret);
ret = pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
/* Workaround to fix the ordering mismatch between issuer name
* of the IBM signing CRLs and the IBM signing key subject name.
*/
tmp = fixed_subject;
fixed_subject = pv_c2b_name(fixed_subject);
X509_NAME_free(tmp);
sk_X509_CRL_free(ret);
ret = pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
X509_NAME_free(fixed_subject);
fixed_subject = NULL;
}
/* Workaround to fix the ordering mismatch between issuer name of the
* IBM signing CRLs and the IBM signing key subject name.
*/
fixed_subject = pv_c2b_name(subject);
sk_X509_CRL_free(ret);
ret = pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
g_set_error(err, PV_CERT_ERROR, PV_CERT_ERROR_NO_CRL, _("no CRL found"));
return NULL;
}
/* Given a certificate @cert try to find valid revocation lists in @ctx. If no
* valid CRL was found NULL is returned.
*/
@@ -1412,21 +1476,9 @@ STACK_OF_X509_CRL *pv_store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert,
return NULL;
}
ret = pv_X509_STORE_CTX_get1_crls(ctx, subject);
if (!ret) {
/* Workaround to fix the mismatch between issuer name of the
* IBM Z signing CRLs and the IBM Z signing key subject name.
*/
g_autoptr(X509_NAME) broken_subject = pv_c2b_name(subject);
ret = pv_X509_STORE_CTX_get1_crls(ctx, broken_subject);
if (!ret) {
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_NO_CRL, _("no CRL found"));
g_info("ERROR: %s", (*error)->message);
return NULL;
}
}
ret = quirk_X509_STORE_ctx_get1_crls(ctx, subject, error);
if (!ret)
return NULL;
/* Filter out non-valid CRLs for @cert */
for (int i = 0; i < sk_X509_CRL_num(ret); i++) {
X509_CRL *crl = sk_X509_CRL_value(ret, i);

View File

@@ -90,10 +90,10 @@ const char *util_arch_machine_type_to_str(int type)
case UTIL_ARCH_MACHINE_TYPE_Z14_ZR1:
return "IBM z14 ZR1";
case UTIL_ARCH_MACHINE_TYPE_Z15:
return "IBM z15";
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
return "IBM z15 Model T02";
return "IBM z15";
case UTIL_ARCH_MACHINE_TYPE_Z16:
case UTIL_ARCH_MACHINE_TYPE_Z16_A02:
return "IBM z16";
default:
return "Unknown machine type";
@@ -111,6 +111,7 @@ unsigned long util_arch_hsa_maxsize(void)
case UTIL_ARCH_MACHINE_TYPE_Z15:
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
case UTIL_ARCH_MACHINE_TYPE_Z16:
case UTIL_ARCH_MACHINE_TYPE_Z16_A02:
return HSA_SIZE_512M;
default:
return HSA_SIZE_32M;

View File

@@ -311,13 +311,13 @@ int util_file_read_i(int *val, int base, const char *fmt, ...)
return -1;
switch (base) {
case 8:
count = sscanf(buf, "%do", val);
count = sscanf(buf, "%o", val);
break;
case 10:
count = sscanf(buf, "%dd", val);
count = sscanf(buf, "%d", val);
break;
case 16:
count = sscanf(buf, "%dx", val);
count = sscanf(buf, "%x", val);
break;
default:
util_panic("Invalid base: %d\n", base);
@@ -425,13 +425,13 @@ int util_file_read_ui(unsigned int *val, int base, const char *fmt, ...)
return -1;
switch (base) {
case 8:
count = sscanf(buf, "%uo", val);
count = sscanf(buf, "%o", val);
break;
case 10:
count = sscanf(buf, "%uu", val);
count = sscanf(buf, "%u", val);
break;
case 16:
count = sscanf(buf, "%ux", val);
count = sscanf(buf, "%x", val);
break;
default:
util_panic("Invalid base: %d\n", base);

View File

@@ -299,3 +299,35 @@ int util_lockfile_parent_release(char *lockfile)
{
return do_lockfile_release(lockfile, getppid());
}
/**
* Return the pid that owns the specified lockfile.
*
* @param[in] lockfile Path to the lock file
* @param[in,out] pid Buffer to place owning pid
*
* @retval 0 pid provided in buffer
* @retval !=0 Error, no pid provided
*/
int util_lockfile_peek_owner(char *lockfile, int *pid)
{
char buf[BUFSIZE];
int fd, len;
if (!lockfile || !pid)
return UTIL_LOCKFILE_ERR;
/* Open lockfile, read the owning pid if it exists */
fd = open(lockfile, O_RDONLY);
if (fd < 0)
return UTIL_LOCKFILE_ERR;
len = read(fd, buf, sizeof(buf));
close(fd);
if (len <= 0)
return UTIL_LOCKFILE_ERR;
buf[len] = 0;
*pid = atoi(buf);
return 0;
}

View File

@@ -45,7 +45,7 @@ vmcmd: Trigger CP command according to the 'VMCMD_X' configuration in
.TP
\fB - DUMP_TYPE:\fR
Type of dump device. Possible values are 'ccw', 'fcp' and 'nvme'.
Type of dump device. Possible values are 'ccw', 'eckd', 'fcp' and 'nvme'.
.TP
\fB - DEVICE:\fR
@@ -71,6 +71,11 @@ Namespace ID for NVMe dump device.
\fB - BOOTPROG:\fR
Boot program selector.
.TP
\fB - BR_CHR:\fR
Boot record location in "C,H,R" format (comma separated values for
Cylinder, Head and Record) or "auto".
.TP
\fB - BR_LBA:\fR
Boot record logical block address.
@@ -146,6 +151,23 @@ DEVICE=0.0.1234
DELAY_MINUTES=5
.br
#
.br
# Example configuration for an ECKD dump device (DASD)
.br
#
.br
ON_PANIC=dump
.br
DUMP_TYPE=eckd
.br
DEVICE=0.0.1004
.br
BOOTPROG=0
.br
BR_CHR=auto
.br
#
.br
# Example configuration for an FCP dump device (SCSI Disk)

View File

@@ -16,7 +16,7 @@
/* we may use header_generic and header_simple_table from the util_funcs module */
config_require(util_funcs)
config_require(util_funcs);
/* function prototypes */

View File

@@ -3,7 +3,6 @@ include ../common.mak
.DEFAULT_GOAL := all
PKGDATADIR := "$(DESTDIR)$(TOOLS_DATADIR)/pvattest"
SUBDIRS := src man tools
RECURSIVE_TARGETS := all-recursive clean-recursive install-recursive

View File

@@ -1,10 +1,7 @@
include ../../common.mak
BIN_PROGRAM = pvattest
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/$(BIN_PROGRAM)"
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
PVATTESTDIR := $(rootdir)/pvattest
INCLUDE_PATHS = "$(SRC_DIR)" "$(rootdir)/include"
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
@@ -35,9 +32,7 @@ LIBCRYPTO_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcrypto)
LIBCURL_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags libcurl)
LIBCURL_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcurl)
ALL_CFLAGS += -std=gnu11 \
-DPKGDATADIR=$(PKGDATADIR) \
-DOPENSSL_API_COMPAT=0x10101000L \
ALL_CFLAGS += -DOPENSSL_API_COMPAT=0x10101000L \
$(GLIB2_CFLAGS) \
$(LIBCRYPTO_CFLAGS) \
$(LIBCURL_CFLAGS) \

View File

@@ -192,13 +192,13 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
}
/* NOTE REQUIRED */
#define _entry_root_ca(__arg_data, __indent) \
{ \
.long_name = "root-ca", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
.description = "Use FILE as the trusted root CA instead the\n" __indent \
"root CAs that are installed on the system (optional).\n", \
.arg_description = "FILE", \
#define _entry_root_ca(__arg_data, __indent) \
{ \
.long_name = "root-ca", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
.description = "Use FILE as the trusted root CA instead the\n" __indent \
"root CAs that are installed on the system (optional).\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */

3
rust/.gitignore vendored
View File

@@ -9,6 +9,3 @@ target/
# Generated during make build can be removed at any point
.check-dep-pvtools
.check-cargo
# Ignore lock files by default
Cargo.lock

View File

@@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.3.2"
@@ -69,6 +78,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -106,7 +121,7 @@ checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636"
dependencies = [
"anstream",
"anstyle",
"bitflags",
"bitflags 1.3.2",
"clap_lex",
"strsim",
"terminal_size",
@@ -121,7 +136,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.18",
"syn",
]
[[package]]
@@ -153,9 +168,9 @@ dependencies = [
[[package]]
name = "curl-sys"
version = "0.4.63+curl-8.1.2"
version = "0.4.72+curl-8.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aeb0fef7046022a1e2ad67a004978f0e3cacb9e3123dc62ce768f92197b771dc"
checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea"
dependencies = [
"cc",
"libc",
@@ -163,7 +178,7 @@ dependencies = [
"openssl-sys",
"pkg-config",
"vcpkg",
"winapi",
"windows-sys 0.52.0",
]
[[package]]
@@ -202,6 +217,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "getrandom"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -259,6 +285,12 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.146"
@@ -290,18 +322,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "once_cell"
version = "1.18.0"
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "openssl"
version = "0.10.54"
version = "0.10.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019"
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
dependencies = [
"bitflags",
"bitflags 2.4.1",
"cfg-if",
"foreign-types",
"libc",
@@ -318,7 +356,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.18",
"syn",
]
[[package]]
@@ -329,9 +367,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.88"
version = "0.9.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617"
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
dependencies = [
"cc",
"libc",
@@ -357,31 +395,68 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "proc-macro2"
version = "1.0.60"
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pv"
version = "0.9.0"
version = "1.0.0"
dependencies = [
"byteorder",
"cfg-if",
"clap",
"curl",
"libc",
"log",
"openssl",
"openssl_extensions",
"pv_core",
"serde",
"serde_test",
"thiserror",
"utils",
"zerocopy",
]
[[package]]
name = "pv_core"
version = "1.0.0"
dependencies = [
"byteorder",
"libc",
"log",
"serde",
"serde_test",
"thiserror",
"utils",
"zerocopy",
]
[[package]]
name = "pvapconfig"
version = "0.9.0"
dependencies = [
"clap",
"lazy_static",
"openssl",
"openssl-sys",
"pv_core",
"rand",
"regex",
"serde",
"serde_yaml",
"utils",
]
[[package]]
name = "pvsecret"
version = "0.9.0"
@@ -396,20 +471,79 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.28"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustix"
version = "0.37.20"
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"bitflags",
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustix"
version = "0.37.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
@@ -449,7 +583,16 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.18",
"syn",
]
[[package]]
name = "serde_test"
version = "1.0.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
dependencies = [
"serde",
]
[[package]]
@@ -483,20 +626,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.109"
version = "2.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb"
dependencies = [
"proc-macro2",
"quote",
@@ -530,7 +662,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.18",
"syn",
]
[[package]]
@@ -561,6 +693,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
@@ -604,7 +742,16 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.0",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.4",
]
[[package]]
@@ -622,6 +769,21 @@ dependencies = [
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows-targets"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@@ -634,6 +796,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -646,6 +814,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -658,6 +832,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -670,6 +850,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -682,6 +868,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -694,6 +886,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -707,10 +905,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "zerocopy"
version = "0.6.1"
name = "windows_x86_64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"byteorder",
"zerocopy-derive",
@@ -718,11 +922,11 @@ dependencies = [
[[package]]
name = "zerocopy-derive"
version = "0.3.2"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn",
]

16
rust/Cargo.toml Normal file
View File

@@ -0,0 +1,16 @@
[workspace]
members = [
"pv",
"pv_core",
"pvapconfig",
"pvsecret",
"utils",
]
resolver = "2"
[workspace.package]
edition = "2021"
license = "MIT"
[profile.release]
lto = true

View File

@@ -15,16 +15,17 @@ ifneq (${HAVE_CARGO},0)
BUILD_TARGETS = $(CARGO_TARGETS)
INSTALL_TARGETS := install-rust-tools install-man
CARGO_TEST_TARGETS = $(addsuffix, _test, $(CARGO_TARGETS))
CARGO_TEST_TARGETS = $(addsuffix .test, $(CARGO_TARGETS))
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_LIBCURL},0)
PV_TARGETS := pvsecret
PV_TARGETS := pvsecret pvapconfig
PV_BUILD_TARGETS = $(PV_TARGETS)
CARGO_TEST_TARGETS += $(addsuffix, _test, $(PV_TARGETS)) pv
PV_BUILD_TARGETS := $(PV_TARGETS)
CARGO_TEST_TARGETS += $(addsuffix .test,pv $(PV_TARGETS))
endif #LIBCURL
endif #OPENSSL
TEST_TARGETS := $(addsuffix _build,$(CARGO_TEST_TARGETS))
endif #CARGO
BUILD_TARGETS += $(PV_BUILD_TARGETS)
@@ -36,21 +37,18 @@ endif
# the cc crate uses these variables to compile c code. It does not open a shell
# to call the compiler, so no echo etc. allowed here, just a path to a program
$(BUILD_TARGETS) rust-test: CC = $(CC_SILENT)
$(BUILD_TARGETS) rust-test: AR = $(AR_SILENT)
$(BUILD_TARGETS) $(TEST_TARGETS) rust-test: CC = $(CC_SILENT)
$(BUILD_TARGETS) $(TEST_TARGETS) rust-test: AR = $(AR_SILENT)
$(CARGO_TARGETS): .check-cargo .no-cross-compile
$(CARGO_BUILD) --manifest-path=$@/Cargo.toml $(ALL_CARGOFLAGS)
.PHONY: $(CARGO_TARGETS)
$(PV_TARGETS): .check-dep-pvtools
$(PV_TARGETS) $(CARGO_TARGETS): .check-cargo .no-cross-compile
$(CARGO_BUILD) --bin $@ $(ALL_CARGOFLAGS)
.PHONY: $(PV_TARGETS) $(CARGO_TARGETS)
$(CARGO_TEST_TARGETS): .check-cargo .no-cross-compile
$(CARGO_TEST) --manifest-path=$@/Cargo.toml --all-features $(CARGOFLAGS)
.PHONY: $(CARGO_TEST_TARGETS)
$(PV_TARGETS): .check-cargo .no-cross-compile .check-dep-pvtools
$(CARGO_BUILD) --manifest-path=$@/Cargo.toml $(ALL_CARGOFLAGS)
.PHONY: $(PV_TARGETS)
$(TEST_TARGETS): ALL_CARGOFLAGS += --no-run
$(CARGO_TEST_TARGETS) $(TEST_TARGETS): .check-cargo .no-cross-compile
$(CARGO_TEST) --package $(basename $@) --all-features $(ALL_CARGOFLAGS)
.PHONY: $(TEST_TARGETS) $(CARGO_TEST_TARGETS)
skip-build:
echo " SKIP rust-tools due to unresolved dependencies"
@@ -65,22 +63,17 @@ print-rust-targets:
echo $(BUILD_TARGETS)
clean:
$(foreach target,$(CARGO_TARGETS),\
$(CARGO_CLEAN) --manifest-path=$(target)/Cargo.toml ${ALL_CARGOFLAGS} ;)
$(foreach target,$(PV_TARGETS),\
$(CARGO_CLEAN) --manifest-path=$(target)/Cargo.toml ${CARGOFLAGS} ;)
$(CARGO_CLEAN) ${ALL_CARGOFLAGS}
$(RM) -- .check-dep-pvtools .detect-openssl.dep.c .check-cargo
rust-test: .check-cargo .no-cross-compile
$(foreach target,$(CARGO_TEST_TARGETS),\
$(CARGO_TEST) --manifest-path=$(target)/Cargo.toml --all-features ${ALL_CARGOFLAGS} ;)
rust-test: $(CARGO_TEST_TARGETS)
install-rust-tools: $(BUILD_TARGETS)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
$(foreach target,$(CARGO_TARGETS),\
$(INSTALL) $(target)/target/release/$(target) $(DESTDIR)$(USRBINDIR);)
$(INSTALL) target/release/$(target) $(DESTDIR)$(USRBINDIR);)
$(foreach target,$(PV_TARGETS),\
$(INSTALL) $(target)/target/release/$(target) $(DESTDIR)$(USRBINDIR);)
$(INSTALL) target/release/$(target) $(DESTDIR)$(USRBINDIR);)
install-man:
$(foreach target,$(CARGO_TARGETS),\
@@ -118,13 +111,13 @@ endif
.check-dep-pvtools: .detect-openssl.dep.c
$(call check_dep, \
"$(BIN_PROGRAM)", \
"Rust-pv", \
$^, \
"openssl-devel / libssl-dev version >= 1.1.1", \
"HAVE_OPENSSL=0", \
"-I.")
$(call check_dep, \
"$(BIN_PROGRAM)", \
"Rust-pv", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")

View File

@@ -7,34 +7,36 @@ https://www.rust-lang.org/learn/get-started
## Building rust code
### s390-tools build system
If `cargo` is installed a simple `make` should do the job. Note that,
compiling rust programs take significaltly longer than C code. To closely
monitor the prgress use `make V=1` By default release builds are made.
compiling rust programs take significantly longer than C code. To closely
monitor the progress use `make V=1` By default release builds are made.
With `make CARGOFLAGS=<flags>` one can pass additional flags to cargo.
With `make HAVE_CARGO=0` one can turn of any compilation that requires cargo.
With `make CARGO=<...>` one can set the cargo binary
### cargo
If you need to run cargo directly, cd to each project you want to build and
If you need to run cargo directly, `cd` to each project you want to build and
issue your cargo commands. Do **NOT** forget to specify `--release` if you are
building tools for a release. The s390-tools expect the environment variable
`S390_TOOLS_RELEASE` to be present at build time. This is the version string the
rust tools provide.
Tpp: You can use `make version` to get the version string.
Tip: You can use `make version` to get the version string.
## Internal Libraries
* __utils__ _Library for rust tools that bundles common stuff for the 390-tools_
* currently only provides a macro to get the `S390_TOOLS_RELEASE` string
* provides a macro to get the `S390_TOOLS_RELEASE` string
* provides macros for compile time assertions
* __pv_core__ _Library for pv tools, providing uvdevice access and utilities to send, receive and interpret various UV-calls._
* __pv__ _Library for pv tools, providing uvdevice access, encryption utilities, and utilities for generating UV-request_
* requires openssl and libcurl for the feature `request`; use `HAVE_<OPENSSL|CURL>=0` to
disable build that use pv with the request feature.
* requires openssl and libcurl
* reexports ann symbols from __pv_core__
* if no encryption utilities required, use __pv_core__
## Tools
* __pvsecret__ _Manage secrets for IBM Secure Execution guests_
* requires pv with the `request` feature
## Writing new tools
We encourage to use Rust for new tools. However, for some use cases it makes
@@ -43,7 +45,7 @@ Exiting tools may be rewritten in Rust.
### What (third-party) crates can be used for s390-tools?
A huge list of libraries are made available through Rusts' ecosystem and is one
of many upsides. However, just like with Coding Style Guidlines, it is
of many upsides. However, just like with Coding Style Guidelines, it is
important to limit the usage of those libraries so that within a project,
everyone is on the same page and that code written in Rust uses similar
approaches. It makes it easier for code review and maintainability in general.
@@ -81,11 +83,27 @@ is a start, but can change over time.
Dependencies used by the crates listed above can be used, too.
### Add new tool
To add a new tool issue `cargo new <TOOLNAME>` in the `rust` directory.
To add a new tool issue `cargo new $TOOLNAME` in the `rust` directory.
Add the tool to the _s390-tools_ build system:
```Makefile
CARGO_TARGETS := TOOLNAME
CARGO_TARGETS := $TOOLNAME
```
Add the library to the _s390-tools_ test list:
```Makefile
CARGO_TEST_TARGETS := $LIBNAME
```
Add the tool/library to the cargo workspace:
```toml
[workspace]
members = [
"pv",
"pvsecret",
"$TOOLNAME",
"$LIBNAME"
"utils",
]
```
### Versions
@@ -98,8 +116,8 @@ use utils::release_string;
fn print_version() {
println!(
"{} version {}\nCopyright IBM Corp. 2023",
env!("CARGO_PKG_NAME"), // collapes into the crates name
release_string!() // this (very likely) collapes into a compile time constant
env!("CARGO_PKG_NAME"), // collapses into the crates name
release_string!() // this (very likely) collapses into a compile time constant
);
}
```

View File

@@ -1,36 +1,22 @@
[package]
name = "pv"
version = "0.9.0"
edition = "2021"
license = "MIT"
version = "1.0.0"
edition.workspace = true
license.workspace = true
[dependencies]
libc = "0.2"
log = { version = "0.4", features = ["std", "release_max_level_debug"] }
thiserror = "1"
zerocopy = "0.6"
cfg-if = "1.0.0"
byteorder = "1.3"
clap = { version ="4", features = ["derive", "wrap_help"] }
curl = "0.4.7"
log = { version = "0.4.6", features = ["std", "release_max_level_debug"] }
openssl = "0.10.49"
serde = { version = "1.0.139", features = ["derive"] }
thiserror = "1.0.33"
utils = {path = "../utils"}
zerocopy = { version="0.7", features = ["derive"] }
# dependencies for request feature
clap = { version ="4", features = ["derive", "wrap_help"], optional = true }
curl = { version ="0.4", optional = true }
openssl = {version = "0.10", optional = true }
openssl_extensions = { path = "openssl_extensions", optional = true }
serde = { version = "1", features = ["derive"], optional = true }
# misc optional dependencies
byteorder = {version = "1", optional = true }
openssl_extensions = { path = "openssl_extensions" }
pv_core = { path = "../pv_core" }
[dev-dependencies]
mockito = {version = "0.31", default-features = false }
serde_test = "1"
lazy_static = "1"
[features]
default = []
request = ["dep:openssl", "dep:curl", "dep:openssl_extensions", "dep:serde", "dep:clap"]
uvsecret = ["dep:byteorder", "dep:serde"]
[profile.release]
lto = true
panic = "abort" # release builds now do not clean up stack after panics. .1 Mb

View File

@@ -1,12 +1,12 @@
[package]
name = "openssl_extensions"
version = "0.1.0"
edition = "2021"
license = "MIT"
edition.workspace = true
license.workspace = true
[dependencies]
foreign-types = "0.3"
libc = {version = "0.2", features = [ "extra_traits"] }
log = { version = "0.4", features = ["std", "release_max_level_debug"] }
openssl = "0.10"
openssl-sys = "0.9"
foreign-types = "0.3.1"
libc = {version = "0.2.49", features = [ "extra_traits"] }
log = { version = "0.4.6", features = ["std", "release_max_level_debug"] }
openssl = "0.10.49"
openssl-sys = "0.9.85"

View File

@@ -5,15 +5,15 @@
use std::fmt;
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
use libc::c_int;
use openssl::x509::{X509CrlRef, X509Ref};
use std::ffi::c_int;
mod ffi {
extern "C" {
pub fn X509_check_akid(
issuer: *const openssl_sys::X509,
akid: *const openssl_sys::AUTHORITY_KEYID,
) -> ::libc::c_int;
) -> super::c_int;
}
}

View File

@@ -30,7 +30,7 @@ mod ffi {
pub fn X509_STORE_add_crl(
xs: *mut openssl_sys::X509_STORE,
x: *mut openssl_sys::X509_CRL,
) -> libc::c_int;
) -> std::ffi::c_int;
}
}

View File

@@ -5,13 +5,13 @@
use std::{marker::PhantomData, ptr};
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::c_int;
use openssl::{
error::ErrorStack,
stack::Stackable,
x509::{X509Crl, X509CrlRef},
};
use openssl_sys::BIO_new_mem_buf;
use std::ffi::c_int;
pub struct StackableX509Crl(*mut openssl_sys::X509_CRL);

View File

@@ -8,11 +8,10 @@ use std::{
};
// (SE) boot request control block aka SE header
use crate::{
assert_size, request::MagicValue, requires_feat, static_assert, Error, Result, PAGESIZE,
};
use crate::{assert_size, static_assert, Error, Result, PAGESIZE};
use log::debug;
use zerocopy::{AsBytes, BigEndian, FromBytes, U32, U64};
use pv_core::request::MagicValue;
use zerocopy::{AsBytes, BigEndian, FromBytes, FromZeroes, U32, U64};
/// Struct containing all SE-header tags.
///
@@ -22,7 +21,6 @@ use zerocopy::{AsBytes, BigEndian, FromBytes, U32, U64};
/// Tweak List Digest (tld)
/// SE Header Tag (seht)
///
#[doc = requires_feat!(request)]
#[repr(C)]
#[derive(Debug, Clone, Copy, AsBytes, PartialEq, Eq)]
pub struct BootHdrTags {
@@ -144,7 +142,7 @@ impl BootHdrTags {
}
#[repr(C)]
#[derive(Debug, Clone, FromBytes)]
#[derive(Debug, Clone, FromBytes, FromZeroes)]
struct BootHdrHead {
magic: U64<BigEndian>,
version: U32<BigEndian>,
@@ -205,7 +203,7 @@ mod tests {
#[test]
fn from_se_image_hdr() {
let bin_hdr = get_test_asset!("exp/secure_guest.hdr");
let hdr_tags = BootHdrTags::from_se_image(&mut Cursor::new(bin_hdr.clone())).unwrap();
let hdr_tags = BootHdrTags::from_se_image(&mut Cursor::new(*bin_hdr)).unwrap();
assert_eq!(hdr_tags, EXP_HDR);
}
@@ -220,7 +218,7 @@ mod tests {
));
// mess up magic
let mut bin_hdr_copy = bin_hdr.clone();
let mut bin_hdr_copy = *bin_hdr;
bin_hdr_copy.swap(0, 1);
assert!(matches!(
BootHdrTags::from_se_image(&mut Cursor::new(bin_hdr_copy)),

View File

@@ -2,14 +2,12 @@
//
// Copyright IBM Corp. 2023
use crate::misc::{create_file, open_file};
use crate::Result;
use crate::{create_buffered_file, open_buffered_file};
use clap::{ArgGroup, Args, ValueHint};
use std::io::{Read, Write};
/// CLI Argument collection for handling certificates.
///
#[doc = requires_feat!(request)]
#[derive(Args, Debug, PartialEq, Eq, Default)]
#[command(
group(ArgGroup::new("pv_verify").required(true).args(["no_verify", "certs"])),
@@ -32,15 +30,15 @@ pub struct CertificateOptions {
/// Disable the host-key document verification.
///
/// Does not require the host-key documents to be valid.
/// Do not use for a production request unless you verified the host-key document before.
/// Do not use for a production request unless you verified the host-key document beforehand.
#[arg(long)]
pub no_verify: bool,
/// Use FILE as a certificate to verify the host-key(s).
/// Use FILE as a certificate to verify the host key or keys.
///
/// The certificates are used to establish a chain of trust for the verification
/// of the host-key documents. Specify this option twice to specify the IBM Z signing key and
/// the intermediate CA certificate (signed by the rootCA).
/// the intermediate CA certificate (signed by the root CA).
#[arg(
short= 'C',
long = "cert",
@@ -54,7 +52,7 @@ pub struct CertificateOptions {
/// Use FILE as a certificate revocation list.
///
/// That list is used to check whether a certificate of the chain of
/// The list is used to check whether a certificate of the chain of
/// trust is revoked. Specify this option multiple times to use multiple CRLs.
#[arg(
long = "crl",
@@ -72,7 +70,7 @@ pub struct CertificateOptions {
/// Use FILE as the root-CA certificate for the verification.
///
/// If omitted, the system wide root CAs installed on the system are used.
/// If omitted, the system wide-root CAs installed on the system are used.
/// Use this only if you trust the specified certificate.
#[arg(long, requires("certs"))]
pub root_ca: Option<String>,
@@ -104,37 +102,25 @@ impl CertificateOptions {
}
/// stdout
#[cfg(feature = "request")]
pub const STDOUT: &str = "-";
/// stdin
#[cfg(feature = "request")]
pub const STDIN: &str = "-";
/// Converts an argument value into a Writer.
///
/// # Errors
/// No Error will occur but function must match a signature
///
#[cfg(feature = "request")]
pub fn get_writer_from_cli_file_arg(path: &str) -> Result<Box<dyn Write>> {
if path == STDOUT {
Ok(Box::new(std::io::stdout()))
} else {
Ok(Box::new(create_buffered_file!(path)))
Ok(Box::new(create_file(path)?))
}
}
/// Converts an argument value into a Reader.
///
/// # Errors
/// No Error will occur but function must match a signature
///
#[cfg(feature = "request")]
pub fn get_reader_from_cli_file_arg(path: &str) -> Result<Box<dyn Read>> {
if path == STDIN {
Ok(Box::new(std::io::stdin()))
} else {
Ok(Box::new(open_buffered_file!(path)))
Ok(Box::new(open_file(path)?))
}
}

View File

@@ -2,29 +2,29 @@
//
// Copyright IBM Corp. 2023
use crate::requires_feat;
use crate::{error::Result, secret::Secret, Error};
use openssl::rand::rand_bytes;
use openssl::{
derive::Deriver,
ec::{EcGroup, EcKey},
hash::{DigestBytes, MessageDigest},
md::MdRef,
nid::Nid,
pkey::{Id, PKey, Private, Public},
pkey::{HasPublic, Id, PKey, PKeyRef, Private, Public},
pkey_ctx::{HkdfMode, PkeyCtx},
symm::{encrypt, encrypt_aead, Cipher},
rand::rand_bytes,
rsa::Padding,
sign::{Signer, Verifier},
symm::{encrypt_aead, Cipher},
};
use std::convert::TryInto;
use std::{convert::TryInto, ops::Range};
/// An AES256-key that will purge itself out of the memory when going out of scope
///
#[doc = requires_feat!(request)]
pub type Aes256Key = Secret<[u8; 32]>;
pub(crate) const AES_256_GCM_TAG_SIZE: usize = 16;
/// Types of symmetric keys, to specify during construction.
///
#[doc = requires_feat!(request)]
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymKeyType {
@@ -34,7 +34,6 @@ pub enum SymKeyType {
/// Types of symmetric keys
///
#[doc = requires_feat!(request)]
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SymKey {
@@ -88,7 +87,6 @@ impl From<Aes256Key> for SymKey {
/// Performs an hkdf according to RFC 5869.
/// See [`OpenSSL HKDF`]()
///
#[doc = requires_feat!(request)]
/// # Errors
///
/// This function will return an OpenSSL error if the key could not be generated.
@@ -113,7 +111,6 @@ pub fn hkdf_rfc_5869<const COUNT: usize>(
/// Derive a symmetric key from a private and a public key.
///
#[doc = requires_feat!(request)]
/// # Errors
///
/// This function will return an error if something went bad in OpenSSL.
@@ -132,7 +129,6 @@ pub fn derive_key(k1: &PKey<Private>, k2: &PKey<Public>) -> Result<Aes256Key> {
/// Generate a random array.
///
#[doc = requires_feat!(request)]
/// # Errors
///
/// This function will return an error if the entropy source fails or is not available.
@@ -144,7 +140,6 @@ pub fn random_array<const COUNT: usize>() -> Result<[u8; COUNT]> {
/// Generate a new random EC-SECP521R1 key.
///
#[doc = requires_feat!(request)]
/// # Errors
///
/// This function will return an error if the key could not be generated by OpenSSL.
@@ -154,24 +149,6 @@ pub fn gen_ec_key() -> Result<PKey<Private>> {
PKey::from_ec_key(key).map_err(Error::Crypto)
}
/// Encrypt confidential Data with a symmetric key.
///
/// * `key` - symmetric key used for encryption
/// * `iv` - initialisation vector
/// * `conf` - data to be encrypted
///
#[doc = requires_feat!(request)]
/// # Errors
///
/// This function will return an error if the data could not be encrypted by OpenSSL.
pub fn encrypt_aes(key: &SymKey, iv: &[u8], conf: &[u8]) -> Result<Vec<u8>> {
match key {
SymKey::Aes256(key) => {
encrypt(Cipher::aes_256_gcm(), key.value(), Some(iv), conf).map_err(Error::Crypto)
}
}
}
/// Encrypt confidential Data with a symmetric key and provida a gcm tag.
///
/// * `key` - symmetric key used for encryption
@@ -179,7 +156,6 @@ pub fn encrypt_aes(key: &SymKey, iv: &[u8], conf: &[u8]) -> Result<Vec<u8>> {
/// * `aad` - additional authentic data
/// * `conf` - data to be encrypted
///
#[doc = requires_feat!(request)]
/// # Returns
/// [`Vec<u8>`] with the following content:
/// 1. `aad`
@@ -189,8 +165,13 @@ pub fn encrypt_aes(key: &SymKey, iv: &[u8], conf: &[u8]) -> Result<Vec<u8>> {
/// # Errors
///
/// This function will return an error if the data could not be encrypted by OpenSSL.
pub fn encrypt_aes_gcm(key: &SymKey, iv: &[u8], aad: &[u8], conf: &[u8]) -> Result<Vec<u8>> {
let mut tag = vec![0xff; 16];
pub fn encrypt_aes_gcm(
key: &SymKey,
iv: &[u8],
aad: &[u8],
conf: &[u8],
) -> Result<(Vec<u8>, Range<usize>, Range<usize>, Range<usize>)> {
let mut tag = vec![0xff; AES_256_GCM_TAG_SIZE];
let encr = match key {
SymKey::Aes256(key) => encrypt_aead(
Cipher::aes_256_gcm(),
@@ -202,17 +183,28 @@ pub fn encrypt_aes_gcm(key: &SymKey, iv: &[u8], aad: &[u8], conf: &[u8]) -> Resu
)?,
};
let mut res = vec![0; aad.len() + encr.len() + 16];
res[0..aad.len()].copy_from_slice(aad);
res[aad.len()..aad.len() + encr.len()].copy_from_slice(&encr);
res[aad.len() + encr.len()..aad.len() + encr.len() + 16].copy_from_slice(&tag);
let mut res = vec![0; aad.len() + encr.len() + tag.len()];
let aad_range = Range {
start: 0,
end: aad.len(),
};
let encr_range = Range {
start: aad.len(),
end: aad.len() + encr.len(),
};
let tag_range = Range {
start: aad.len() + encr.len(),
end: aad.len() + encr.len() + tag.len(),
};
Ok(res)
res[aad_range.clone()].copy_from_slice(aad);
res[encr_range.clone()].copy_from_slice(&encr);
res[tag_range.clone()].copy_from_slice(&tag);
Ok((res, aad_range, encr_range, tag_range))
}
/// Calculate the hash of a slice.
///
#[doc = requires_feat!(request)]
/// # Errors
///
/// This function will return an error if OpenSSL could not compute the hash.
@@ -220,10 +212,100 @@ pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes> {
openssl::hash::hash(t, data).map_err(Error::Crypto)
}
/// Calculate a digital signature scheme.
///
/// Calculates the digital signature of the provided message using the signing key. [`Id::EC`],
/// and [`Id::RSA`] keys are supported. For [`Id::RSA`] [`Padding::PKCS1_PSS`] is used.
///
/// # Errors
///
/// This function will return an error if OpenSSL could not compute the signature.
pub fn sign_msg(skey: &PKeyRef<Private>, dgst: MessageDigest, msg: &[u8]) -> Result<Vec<u8>> {
match skey.id() {
Id::EC => {
let mut sgn = Signer::new(dgst, skey)?;
sgn.sign_oneshot_to_vec(msg).map_err(Error::Crypto)
}
Id::RSA => {
let mut sgn = Signer::new(dgst, skey)?;
sgn.set_rsa_padding(Padding::PKCS1_PSS)?;
sgn.sign_oneshot_to_vec(msg).map_err(Error::Crypto)
}
_ => Err(Error::UnsupportedSigningKey),
}
}
/// Verify the digital signature of a message.
///
/// Verifies the digital signature of the provided message using the signing key.
/// [`Id::EC`] and [`Id::RSA`] keys are supported. For [`Id::RSA`] [`Padding::PKCS1_PSS`] is used.
///
/// # Returns
/// true if signature could be verified, false otherwise
///
/// # Errors
///
/// This function will return an error if OpenSSL could not compute the signature.
pub fn verify_signature<T: HasPublic>(
skey: &PKeyRef<T>,
dgst: MessageDigest,
msg: &[u8],
sign: &[u8],
) -> Result<bool> {
match skey.id() {
Id::EC => {
let mut ctx = Verifier::new(dgst, skey)?;
ctx.update(msg)?;
ctx.verify(sign).map_err(Error::Crypto)
}
Id::RSA => {
let mut ctx = Verifier::new(dgst, skey)?;
ctx.set_rsa_padding(Padding::PKCS1_PSS)?;
ctx.verify_oneshot(sign, msg).map_err(Error::Crypto)
}
_ => Err(Error::UnsupportedVerificationKey),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::*;
use crate::{get_test_asset, test_utils::*};
#[test]
fn sign_ec() {
let (ec_key, _) = get_test_keys();
let data = "sample".as_bytes();
let sign = sign_msg(&ec_key, MessageDigest::sha512(), data).unwrap();
assert!(sign.len() <= 139 && sign.len() >= 137);
assert!(verify_signature(&ec_key, MessageDigest::sha512(), data, &sign).unwrap());
}
#[test]
fn sign_rsa_2048() {
let keypair = get_test_asset!("keys/rsa2048key.pem");
let keypair = PKey::private_key_from_pem(keypair).unwrap();
let data = "sample".as_bytes();
let sign = sign_msg(&keypair, MessageDigest::sha512(), data).unwrap();
assert_eq!(256, sign.len());
assert!(verify_signature(&keypair, MessageDigest::sha512(), data, &sign).unwrap());
}
#[test]
fn sign_rsa_3072() {
let keypair = get_test_asset!("keys/rsa3072key.pem");
let keypair = PKey::private_key_from_pem(keypair).unwrap();
let data = "sample".as_bytes();
let sign = sign_msg(&keypair, MessageDigest::sha512(), data).unwrap();
assert_eq!(384, sign.len());
assert!(verify_signature(&keypair, MessageDigest::sha512(), data, &sign).unwrap());
}
#[test]
fn derive_key() {
@@ -285,7 +367,7 @@ mod tests {
0xee, 0x62, 0x98, 0xf7, 0x7e, 0x0c,
];
let res = encrypt_aes_gcm(
let (res, ..) = encrypt_aes_gcm(
&SymKey::Aes256(aes_gcm_key.into()),
&aes_gcm_iv,
&aes_gcm_aad,
@@ -294,32 +376,4 @@ mod tests {
.unwrap();
assert_eq!(res, aes_gcm_res);
}
#[test]
fn encrypt_aes_256() {
let aes_gcm_key = [
0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66, 0x5f, 0x8a,
0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, 0xa3, 0x52, 0x02, 0x93,
0xa5, 0x72, 0x07, 0x8f,
];
let aes_gcm_iv = [
0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84,
];
let aes_gcm_plain = [
0xf5, 0x6e, 0x87, 0x05, 0x5b, 0xc3, 0x2d, 0x0e, 0xeb, 0x31, 0xb2, 0xea, 0xcc, 0x2b,
0xf2, 0xa5,
];
let aes_gcm_res = vec![
0xf7, 0x26, 0x44, 0x13, 0xa8, 0x4c, 0x0e, 0x7c, 0xd5, 0x36, 0x86, 0x7e, 0xb9, 0xf2,
0x17, 0x36,
];
let res = encrypt_aes(
&&SymKey::Aes256(aes_gcm_key.into()),
&aes_gcm_iv,
&aes_gcm_plain,
)
.unwrap();
assert_eq!(res, aes_gcm_res);
}
}

View File

@@ -10,49 +10,19 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[cfg_attr(debug_assertions, error("Ultravisor: '{msg}' ({rc:#06x},{rrc:#06x})"))]
#[cfg_attr(not(debug_assertions), error("Ultravisor: '{msg}' ({rc:#06x})"))]
Uv {
rc: u16,
rrc: u16,
msg: &'static str,
},
#[error("Invalid SE header provided")]
#[cfg(feature = "request")]
InvBootHdr,
#[error("{0}")]
Specification(String),
#[error("Cannot {ty} {ctx} at `{path}`")]
FileIo {
ty: FileIoErrorType,
ctx: String,
path: String,
source: std::io::Error,
},
#[error("Cannot {ty} `{path}`")]
FileAccess {
ty: FileAccessErrorType,
path: String,
source: std::io::Error,
},
#[error("Host-key verification failed: {0}")]
#[cfg(feature = "request")]
HkdVerify(HkdVerifyErrorType),
#[error("No host-key provided")]
#[cfg(feature = "request")]
NoHostkey,
#[error("To many host-keys provided")]
#[cfg(feature = "request")]
#[error("Too many host-keys provided")]
ManyHostkeys,
#[error("Cannot load {ty} from {path}")]
#[cfg(feature = "request")]
X509Load {
path: String,
ty: &'static str,
@@ -60,77 +30,67 @@ pub enum Error {
},
#[error("Internal (unexpected) error: {0}, caused by {1}")]
#[cfg(feature = "request")]
InternalSsl(&'static str, #[source] openssl::error::ErrorStack),
#[error("Signing is only supported for EC and RSA keys")]
UnsupportedSigningKey,
#[error("Verifying signatures is only supported for EC and RSA keys")]
UnsupportedVerificationKey,
#[error("Provided binary request is too small")]
BinRequestSmall,
#[error("No Config UID found: {0}")]
NoCuid(String),
// errors from request types
#[cfg(feature = "uvsecret")]
#[error("Customer Communication Key must be 32 bytes long")]
CckSize,
#[cfg(feature = "uvsecret")]
#[error("Cannot encode secrets (Too many secrets)")]
ManySecrets,
#[error("Invalid {0} user-data for signing provided. Max {} bytes allowed", .0.max())]
AsrcbInvSgnUserData(UserDataType),
#[cfg(feature = "uvsecret")]
#[error("Cannot decode secret list")]
InvSecretList(#[source] std::io::Error),
#[error("Unsupported user data signing key provided. Only EC(secp521r1) and RSA(2048 & 3072 bit) are supported")]
BinAsrcbUnsupportedUserDataSgnKey,
#[cfg(feature = "uvsecret")]
#[error("Input does not contain an add-secret request")]
NoAsrcb,
#[error("No user-key for verification provided and user-data is signed")]
BinAsrcbNoUserDataSgnKey,
#[error("Input does not contain an add-secret request version 1")]
BinAsrcbInvVersion,
#[error("Provided user-data key type ({key}) does not match with the user-data ({kind})")]
AsrcbUserDataKeyMismatch { key: String, kind: UserDataType },
#[error(
"The user-defined request signature could not be verified with the provided certificate"
)]
AsrcbUserDataSgnFail,
// errors from other crates
#[error(transparent)]
PvCore(#[from] pv_core::Error),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
#[cfg(feature = "request")]
Crypto(#[from] openssl::error::ErrorStack),
#[error(transparent)]
ParseInt(#[from] std::num::ParseIntError),
#[cfg(feature = "request")]
#[error(transparent)]
Curl(#[from] curl::Error),
}
// used in macros
#[doc(hidden)]
impl Error {
pub const CRL: &str = "CRL";
pub const CERT: &str = "certificate";
}
/// Error cases for I/O operations
#[allow(missing_docs)]
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum FileIoErrorType {
#[error("read")]
Read,
#[error("write")]
Write,
}
/// Error cases for accessing files
#[allow(missing_docs)]
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum FileAccessErrorType {
#[error("open")]
Open,
#[error("create")]
Create,
pub const CRL: &'static str = "CRL";
pub const CERT: &'static str = "certificate";
}
/// Error cases for verifying host-key documents
///
#[doc = crate::requires_feat!(request)]
#[allow(missing_docs)]
#[derive(thiserror::Error, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[cfg(feature = "request")]
pub enum HkdVerifyErrorType {
#[error("Signature verification failed")]
Signature,
@@ -160,37 +120,11 @@ pub enum HkdVerifyErrorType {
IbmSignInvalid(#[source] openssl::x509::X509VerifyResult, u32),
}
macro_rules! path_to_str {
($path: expr) => {
$path.as_ref().to_str().unwrap_or("no UTF-8 path")
};
}
pub(crate) use path_to_str;
macro_rules! file_error {
($ty: tt, $ctx: expr, $path:expr, $src: expr) => {
$crate::Error::FileIo {
ty: $crate::FileIoErrorType::$ty,
ctx: $ctx.to_string(),
path: $path.to_string(),
source: $src,
}
};
}
pub(crate) use file_error;
#[cfg(feature = "request")]
macro_rules! bail_hkd_verify {
($var: tt) => {
return Err($crate::Error::HkdVerify($crate::HkdVerifyErrorType::$var))
};
}
#[cfg(feature = "request")]
pub(crate) use bail_hkd_verify;
macro_rules! bail_spec {
($str: expr) => {
return Err($crate::Error::Specification($str.to_string()))
};
}
pub(crate) use bail_spec;
use crate::request::uvsecret::UserDataType;

View File

@@ -2,7 +2,6 @@
//
// Copyright IBM Corp. 2023
#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]
#![deny(missing_docs)]
//! pv - library for pv-tools
//!
@@ -11,155 +10,85 @@
//! `pv` provides abstraction layers for encryption, secure memory management,
//! logging, and accessing the uvdevice.
//!
//! ## Feature Flags
//! The following feature flags are available:
//! - `request`
//! - optional
//! - Enables generation of UV requests
//! - `uvsecret`
//! - optional
//! - Enables support for the UV Secret API.
//! If you do not need any OpenSSL features use `pv_core`.
//! This crate reexports all symbols from `pv_core`
mod brcb;
mod cli;
mod crypto;
mod error;
mod log;
mod req;
mod secret;
mod utils;
mod uvdevice;
mod uvsecret;
mod verify;
/// Internal macro to conveninetly document required features on items
// #[macro_export]
/// utility functions for writing TESTS!!!
//hide any test helpers on docs!
#[doc(hidden)]
macro_rules! requires_feat {
(request) => {
" Requires the feature `request`"
};
(uvsecret) => {
" Requires the feature `uvsecret`"
};
(reqsecret) => {
"Requires the features `request` & `uvsecret`"
};
}
#[allow(unused_imports)]
use requires_feat;
//only some features need this
#[allow(dead_code)]
pub mod test_utils;
pub use ::utils::assert_size;
pub use ::utils::static_assert;
const PAGESIZE: usize = 0x1000;
cfg_if::cfg_if! {
if #[cfg(feature = "request")] {
mod brcb;
mod cli;
mod crypto;
mod req;
mod secret;
mod uvsecret;
mod verify;
/// utility functions for writing TESTS!!!
#[allow(dead_code)]
//hide any test helpers on docs!
#[doc(hidden)]
pub mod test_utils;
}
}
/// Definitions and functions for interacting with the Ultravisor
pub mod uv {
pub use crate::uvdevice::{
pub use pv_core::uv::{
uv_ioctl, ConfigUid, UvCmd, UvDevice, UvDeviceInfo, UvFlags, UvcSuccess,
};
#[cfg(feature = "uvsecret")]
pub use crate::uvsecret::{
secret_list::SecretList,
uvc::{AddCmd, ListCmd, LockCmd},
};
pub use pv_core::uv::{AddCmd, ListCmd, LockCmd};
pub use pv_core::uv::{ListableSecretType, SecretEntry, SecretList};
}
/// Miscellaneous functions and definitions
pub mod misc {
#[cfg(feature = "request")]
pub use crate::cli::{
get_reader_from_cli_file_arg, get_writer_from_cli_file_arg, CertificateOptions, STDIN,
STDOUT,
};
pub use crate::log::PvLogger;
pub use crate::utils::{
memeq, parse_hex, pv_guest_bit_set, read, read_exact_file, read_file, to_u16, to_u32,
try_parse_u128, try_parse_u64, write, write_file, Flags, Lsb0Flags64, Msb0Flags64,
};
#[cfg(feature = "request")]
pub use crate::utils::{read_certs, read_crls};
pub use crate::utils::{read_certs, read_crls, read_private_key};
pub use pv_core::misc::*;
pub use pv_core::PvLogger;
}
#[cfg(feature = "request")]
pub use crate::error::HkdVerifyErrorType;
pub use error::{Error, FileAccessErrorType, FileIoErrorType, Result};
pub use error::{Error, Result};
/// Functionalities to build UV requests
#[doc = requires_feat!(request)]
pub mod request {
pub use crate::brcb::{BootHdrMagic, BootHdrTags};
pub use crate::crypto::derive_key;
pub use crate::crypto::random_array;
pub use crate::crypto::{encrypt_aes_gcm, gen_ec_key};
pub use crate::crypto::{hash, hkdf_rfc_5869};
pub use crate::crypto::{sign_msg, verify_signature};
pub use crate::crypto::{Aes256Key, SymKey, SymKeyType};
pub use crate::req::{Aad, BinReqValues, Encrypt, Keyslot, ReqEncrCtx, Request};
pub use crate::secret::{Secret, Zeroize};
pub use crate::verify::{CertVerifier, HkdVerifier, NoVerifyHkd};
cfg_if::cfg_if! {
if #[cfg(feature = "request")] {
pub use crate::brcb::{BootHdrTags, BootHdrMagic};
pub use crate::crypto::{
derive_key, encrypt_aes, encrypt_aes_gcm, gen_ec_key, hash, hkdf_rfc_5869,
random_array, Aes256Key, SymKey, SymKeyType,
};
pub use crate::req::{Aad, Encrypt, Keyslot, ReqEncrCtx, Request};
pub use crate::secret::{Secret, Zeroize};
pub use crate::verify::HkdVerifier;
/// Reexports some useful OpenSSL symbols
///
#[doc = requires_feat!(request)]
pub mod openssl {
pub use openssl::error::ErrorStack;
pub use openssl::hash::MessageDigest;
pub use openssl::md::Md;
pub use openssl::pkey;
}
}
/// Reexports some useful OpenSSL symbols
pub mod openssl {
pub use openssl::error::ErrorStack;
pub use openssl::hash::MessageDigest;
pub use openssl::md::Md;
pub use openssl::pkey;
}
cfg_if::cfg_if! {
if #[cfg(feature = "uvsecret")] {
/// Functionalities for creating add-secret requests
pub mod uvsecret {
#[cfg(feature = "request")]
pub use crate::uvsecret::{
asrcb::{AddSecretFlags, AddSecretRequest, AddSecretVersion,},
ext_secret::ExtSecret,
guest_secret::GuestSecret,
};
pub use crate::uvsecret::AddSecretMagic;
pub use crate::uvsecret::UserDataType;
}
}
}
/// Version number of the request in system-endian
pub type RequestVersion = u32;
/// Request magic value
///
/// The first 8 byte of a request providing an identifier of the request type
/// for programs
pub type RequestMagic = [u8; 8];
/// A `MagicValue` is a bytepattern, that indicates if a byte slice contains the specified
/// (binary) data.
pub trait MagicValue<const N: usize> {
/// Magic value as byte array
const MAGIC: [u8; N];
/// Test whether the given slice starts with the magic value.
fn starts_with_magic(v: &[u8]) -> bool {
if v.len() < Self::MAGIC.len() {
return false;
}
crate::misc::memeq(&v[..Self::MAGIC.len()], &Self::MAGIC)
}
/// Functionalities for creating add-secret requests
pub mod uvsecret {
pub use crate::uvsecret::{
asrcb::{AddSecretFlags, AddSecretRequest, AddSecretVersion},
ext_secret::ExtSecret,
guest_secret::GuestSecret,
user_data::verify_asrcb_and_get_user_data,
};
pub use pv_core::request::uvsecret::AddSecretMagic;
pub use pv_core::request::uvsecret::UserDataType;
}
pub use pv_core::request::RequestMagic;
}
/// Provides cargo version Info about this crate.
@@ -168,39 +97,3 @@ pub mod request {
pub const fn crate_info() -> &'static str {
concat!(env!("CARGO_PKG_NAME"), "-crate ", env!("CARGO_PKG_VERSION"))
}
#[doc(hidden)]
#[macro_export]
macro_rules! file_acc_error {
($ty: tt, $path:expr, $src: expr) => {
$crate::Error::FileAccess {
ty: $crate::FileAccessErrorType::$ty,
path: $path.to_string(),
source: $src,
}
};
}
#[macro_export]
/// Create a file wrapped in a [BufWriter]
///
/// [BufWriter]: std::io#BufWriter
macro_rules! create_buffered_file {
($path: expr) => {
std::io::BufWriter::new(
std::fs::File::create($path).map_err(|e| $crate::file_acc_error!(Create, $path, e))?,
)
};
}
#[macro_export]
/// Open a file wrapped in a [BufReader]
///
/// [BufReader]: std::io#BufReader
macro_rules! open_buffered_file {
($path: expr) => {
std::io::BufReader::new(
std::fs::File::open($path).map_err(|e| $crate::file_acc_error!(Open, $path, e))?,
)
};
}

View File

@@ -2,19 +2,21 @@
//
// Copyright IBM Corp. 2023
use crate::crypto::AES_256_GCM_TAG_SIZE;
use crate::misc::to_u32;
use crate::request::{
derive_key, encrypt_aes, encrypt_aes_gcm, gen_ec_key, random_array, RequestMagic,
RequestVersion, SymKey, SymKeyType,
};
use crate::request::{derive_key, encrypt_aes_gcm, gen_ec_key, random_array, SymKey, SymKeyType};
use crate::{Error, Result};
use openssl::bn::{BigNum, BigNumContext};
use openssl::ec::{EcGroupRef, EcPointRef};
use openssl::error::ErrorStack;
use openssl::hash::{hash, MessageDigest};
use openssl::pkey::{PKey, PKeyRef, Private, Public};
use pv_core::request::{RequestMagic, RequestVersion};
use std::convert::TryInto;
use zerocopy::{AsBytes, BigEndian, FromBytes, U32};
use std::mem::size_of;
use std::ops::Range;
use utils::assert_size;
use zerocopy::{AsBytes, BigEndian, FromBytes, FromZeroes, U32};
/// Encrypt a _secret_ using self and a given private key.
pub trait Encrypt {
@@ -94,7 +96,7 @@ impl Encrypt for Keyslot {
to: &mut Vec<u8>,
) -> Result<()> {
let derived_key = derive_key(priv_key, &self.0)?;
let mut wrpk_and_kst = encrypt_aes_gcm(&derived_key.into(), &[0; 12], &[], prot_key)?;
let (mut wrpk_and_kst, ..) = encrypt_aes_gcm(&derived_key.into(), &[0; 12], &[], prot_key)?;
let phk: EcdhPubkeyCoord = self.0.as_ref().try_into()?;
to.reserve(80);
@@ -215,10 +217,11 @@ impl ReqEncrCtx {
}
}
let rql = to_u32(auth_data.len() + encr_size + 16)
.ok_or_else(|| Error::Specification("Configured request size to large".to_string()))?;
let rql = to_u32(auth_data.len() + encr_size + 16).ok_or_else(|| {
pv_core::Error::Specification("Configured request size to large".to_string())
})?;
let sea = to_u32(encr_size)
.ok_or_else(|| Error::Specification("Encrypted size to large".to_string()))?;
.ok_or_else(|| pv_core::Error::Specification("Encrypted size to large".to_string()))?;
let req_hdr = RequestHdr::new(version, rql, self.iv, nks, sea, magic);
// copy request header to the start of the request
@@ -235,17 +238,6 @@ impl ReqEncrCtx {
self.priv_key.as_ref().try_into().map_err(Error::Crypto)
}
/// Encrypt confidential Data with this encryption context.
///
/// * `conf` - data to be encrypted
///
/// # Errors
///
/// This function will return an error if the data could not be encrypted by OpenSSL.
pub fn encrypt(&self, conf: &[u8]) -> Result<Vec<u8>> {
encrypt_aes(&self.prot_key, &self.iv, conf)
}
/// Encrypt confidential Data with this encryption context and provide a gcm tag.
///
/// * `aad` - additional authentic data
@@ -260,7 +252,11 @@ impl ReqEncrCtx {
/// # Errors
///
/// This function will return an error if the data could not be encrypted by OpenSSL.
pub fn encrypt_aead(&self, aad: &[u8], conf: &[u8]) -> Result<Vec<u8>> {
pub fn encrypt_aead(
&self,
aad: &[u8],
conf: &[u8],
) -> Result<(Vec<u8>, Range<usize>, Range<usize>, Range<usize>)> {
encrypt_aes_gcm(&self.prot_key, &self.iv, aad, conf)
}
}
@@ -309,7 +305,7 @@ ecdh_from!(Public);
/// Representation of the shared parts of the request header.
/// Used by [`ReqEncrCtx`]
#[repr(C)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
struct RequestHdr {
magic: [u8; 8],
rqvn: U32<BigEndian>,
@@ -321,6 +317,7 @@ struct RequestHdr {
reserved28: u32,
sea: U32<BigEndian>,
}
assert_size!(RequestHdr, 48);
impl RequestHdr {
fn new(rqvn: u32, rql: u32, iv: [u8; 12], nks: u8, sea: u32, magic: Option<[u8; 8]>) -> Self {
@@ -379,6 +376,67 @@ pub trait Request {
fn add_hostkey(&mut self, hostkey: PKey<Public>);
}
/// A struct to represent some parts of a binary/encrypted request.
#[derive(Debug)]
#[allow(unused)]
#[allow(clippy::len_without_is_empty)]
pub struct BinReqValues<'a> {
iv: &'a [u8],
aad: &'a [u8],
req_dep_aad: &'a [u8],
encr: &'a [u8],
tag: &'a [u8],
version: u32,
len: usize,
}
impl<'a> BinReqValues<'a> {
pub(crate) const TAG_LEN: usize = AES_256_GCM_TAG_SIZE;
/// Get the locations from this request.
///
/// Does minimal sanity test, just tests to prevent panics.
/// `req` may be larger than the actual request.
pub fn get(req: &'a [u8]) -> Result<Self> {
let hdr = RequestHdr::read_from_prefix(req).ok_or(Error::BinRequestSmall)?;
let rql = hdr.rql.get() as usize;
let sea = hdr.sea.get() as usize;
if rql < req.len() || sea + Self::TAG_LEN > rql {
return Err(Error::BinRequestSmall);
}
let aad_size = rql - sea - Self::TAG_LEN;
if aad_size < size_of::<RequestHdr>() {
return Err(Error::BinRequestSmall);
}
let iv = &req[0x10..0x1c];
let aad = &req[..aad_size];
let req_dep_aad = &req[size_of::<RequestHdr>()..aad_size];
let encr = &req[aad_size..(aad_size + sea)];
let tag = &req[rql - Self::TAG_LEN..];
Ok(Self {
iv,
aad,
req_dep_aad,
encr,
tag,
version: hdr.rqvn.get(),
len: rql,
})
}
/// Returns the version of this [`BinReqValues`].
pub fn version(&self) -> u32 {
self.version
}
/// Returns the length of this [`BinReqValues`].
pub fn len(&self) -> usize {
self.len
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -451,7 +509,7 @@ mod tests {
let ks = vec![
Keyslot::new(host_key.clone()),
Keyslot::new(host_key.clone()),
Keyslot::new(host_key.clone()),
Keyslot::new(host_key),
];
let mut aad = Vec::<Aad>::new();
ks.iter().for_each(|ks| aad.push(Aad::Ks(ks)));

View File

@@ -34,8 +34,8 @@ impl Zeroize for Vec<u8> {
// * Vec allocated at least capacity elements continuously
// * dst points always to a valid location
unsafe {
std::ptr::write_volatile(dst, 0);
dst = dst.add(1);
std::ptr::write_volatile(dst, 0)
}
}
std::sync::atomic::compiler_fence(std::sync::atomic::Ordering::SeqCst);

View File

@@ -1,336 +1,18 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp. 2023
use crate::{
error::{bail_spec, file_error, path_to_str},
Error, FileIoErrorType, Result,
use crate::{Error, Result};
use openssl::{
pkey::{PKey, Private},
x509::{X509Crl, X509},
};
#[cfg(feature = "request")]
use openssl::x509::X509Crl;
#[cfg(feature = "request")]
use openssl::x509::X509;
use std::io::{Read, Write};
use std::path::Path;
use zerocopy::{AsBytes, BigEndian, FromBytes, U64};
/// Asserts a constant expression evaluates to `true`.
///
/// If the expression is not evaluated to `true` the compilation will fail.
#[macro_export]
macro_rules! static_assert {
($condition:expr) => {
const _: () = core::assert!($condition);
};
}
/// Asserts that a type has a specific size.
///
/// Useful to validate structs that are passed to C code.
/// If the expression is not evaluated to `true` the compilation will fail.
///
/// # Example
/// ```rust
/// # use pv::assert_size;
/// # fn main() {}
/// #[repr(C)]
/// struct c_struct {
/// v: u64,
/// }
/// assert_size!(c_struct, 8);
/// // assert_size!(c_struct, 7);//won't compile
/// ```
#[macro_export]
macro_rules! assert_size {
($t:ty, $sz:expr ) => {
$crate::static_assert!(::std::mem::size_of::<$t>() == $sz);
};
}
/// Trait that describes bitflags, represented by `T`.
pub trait Flags<T>: From<T> + for<'a> From<&'a T> {
/// Set the specified bit to one.
/// # Panics
///Panics if bit is >= 64
fn set_bit(&mut self, bit: u8);
/// Set the specified bit to zero.
/// # Panics
///Panics if bit is >= 64
fn unset_bit(&mut self, bit: u8);
/// Test if the specified bit is set.
/// # Panics
///Panics if bit is >= 64
fn is_set(&self, bit: u8) -> bool;
}
/// Bitflags in MSB0 ordering
///
/// Wraps an u64 to set/get individual bits
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, AsBytes, FromBytes)]
pub struct Msb0Flags64(U64<BigEndian>);
impl Flags<u64> for Msb0Flags64 {
#[track_caller]
fn set_bit(&mut self, bit: u8) {
assert!(bit < 64, "Flag bit set to greater than 63");
let mut v = self.0.get();
v |= 1 << (63 - bit);
self.0.set(v)
}
#[track_caller]
fn unset_bit(&mut self, bit: u8) {
assert!(bit < 64, "Flag bit set to greater than 63");
let mut v = self.0.get();
v &= !(1 << (63 - bit));
self.0.set(v)
}
#[track_caller]
fn is_set(&self, bit: u8) -> bool {
assert!(bit < 64, "Flag bit set to greater than 63");
self.0.get() & (1 << (63 - bit)) > 0
}
}
impl From<u64> for Msb0Flags64 {
fn from(value: u64) -> Self {
Self(value.into())
}
}
impl From<&u64> for Msb0Flags64 {
fn from(value: &u64) -> Self {
(*value).into()
}
}
/// Bitflags in LSB0 ordering
///
/// Wraps an u64 to set/get individual bits
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, AsBytes, FromBytes)]
pub struct Lsb0Flags64(U64<BigEndian>);
impl Flags<u64> for Lsb0Flags64 {
#[track_caller]
fn set_bit(&mut self, bit: u8) {
assert!(bit < 64, "Flag bit set to greater than 63");
let mut v = self.0.get();
v |= 1 << bit;
self.0.set(v)
}
#[track_caller]
fn unset_bit(&mut self, bit: u8) {
assert!(bit < 64, "Flag bit set to greater than 63");
let mut v = self.0.get();
v &= !(1 << bit);
self.0.set(v)
}
#[track_caller]
fn is_set(&self, bit: u8) -> bool {
assert!(bit < 64, "Flag bit set to greater than 63");
self.0.get() & (1 << bit) > 0
}
}
impl From<u64> for Lsb0Flags64 {
fn from(value: u64) -> Self {
Self(value.into())
}
}
impl From<&u64> for Lsb0Flags64 {
fn from(value: &u64) -> Self {
(*value).into()
}
}
/// Tries to convert a BE hex string into a 128 unsigned integer
/// The hexstring must contain 32chars of hexdigits
///
/// * `hex_str` - string to convert can be prepended with "0x"
/// * `ctx` - Error context string in case of an error
/// ```rust
/// # use std::error::Error;
/// # use pv::misc::try_parse_u128;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let hex = "11223344556677889900aabbccddeeff";
/// try_parse_u128(&hex, "The test")?;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
/// If `hex_string` is not a 32 byte hex string an Error appears
pub fn try_parse_u128(hex_str: &str, ctx: &str) -> Result<[u8; 16]> {
let hex_str = if hex_str.starts_with("0x") {
hex_str.split_at(2).1
} else {
hex_str
};
if hex_str.len() != 32 {
bail_spec!(format!(
"{ctx} hexstring must be 32chars long to cover all 16 bytes"
));
}
parse_hex(hex_str).try_into().map_err(|_| {
Error::Specification(format!(
"{ctx} hexstring must be 32chars long to cover all 16 bytes"
))
})
}
/// Tries to convert a BE hex string into a 64 unsigned integer
/// The hexstring must *NOT* contain 16 chars of hexdigits, but
/// 16 chars at most.
///
/// * `hex_str` - string to convert can be prepended with "0x"
/// * `ctx` - Error context string in case of an error
/// ```rust
/// # use std::error::Error;
/// # use pv::misc::try_parse_u64;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let hex = "1234567890abcdef";
/// try_parse_u64(&hex, "The test")?;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
/// If `hex_string` is not a 32 byte hex string an Error appears
pub fn try_parse_u64(hex_str: &str, ctx: &str) -> Result<u64> {
let hex_str = if hex_str.starts_with("0x") {
hex_str.split_at(2).1
} else {
hex_str
};
if hex_str.len() > 16 {
bail_spec!(format!(
"{ctx} hexstring {hex_str} must be max 16 chars long"
));
}
Ok(u64::from_str_radix(hex_str, 16)?)
}
/// Read exactly COUNT bytes into the buffer.
///
/// * `path` - Path to file
/// * `ctx` - Error context string in case of an error
///
/// # Errors
/// If this function encounters an "end of file" before completely filling
/// the buffer, it returns an error. The contents of `buf` are unspecified in this case.
///
/// If any other read error is encountered then this function immediately
/// returns. The contents of `buf` are unspecified in this case.
///
/// If this function returns an error, it is unspecified how many bytes it
/// has read, but it will never read more than would be necessary to
/// completely fill the buffer.
pub fn read_exact_file<P: AsRef<Path>, const COUNT: usize>(
path: P,
ctx: &str,
) -> Result<[u8; COUNT]> {
let mut f = std::fs::File::open(&path).map_err(|e| Error::FileAccess {
ty: crate::FileAccessErrorType::Open,
path: path_to_str!(path).to_string(),
source: e,
})?;
if f.metadata()?.len() as usize != COUNT {
bail_spec!(format!("{ctx} must be exactly {COUNT} bytes long"));
}
let mut buf = [0; COUNT];
f.read_exact(&mut buf)
.map_err(|e| file_error!(Read, ctx, path_to_str!(path).to_string(), e))?;
Ok(buf)
}
/// Read content from a file and add context in case of an error
///
/// * `path` - Path to file
/// * `ctx` - Error context string in case of an error
///
///
/// # Errors
/// Passes through any kind of error `std::fs::read` produces
pub fn read_file<P: AsRef<Path>>(path: P, ctx: &str) -> Result<Vec<u8>> {
std::fs::read(&path).map_err(|e| {
file_error!(
Read,
ctx,
path.as_ref().to_str().unwrap_or("no UTF-8 path"),
e
)
})
}
/// Reads all content from a [`std::io::Read`] and add context in case of an error
///
/// * `path` - Path to file
/// * `ctx` - Error context string in case of an error
///
///
/// # Errors
/// Passes through any kind of error `std::fs::write` produces
pub fn read<R: Read>(rd: &mut R, path: &str, ctx: &str) -> Result<Vec<u8>> {
let mut buf = vec![];
rd.read_to_end(&mut buf).map_err(|e| Error::FileIo {
ty: FileIoErrorType::Write,
ctx: ctx.to_string(),
path: path.to_string(),
source: e,
})?;
Ok(buf)
}
/// write content to a file and add context in case of an error
///
/// * `path` - Path to file
/// * `ctx` - Error context string in case of an error
///
///
/// # Errors
/// Passes through any kind of error `std::fs::write` produces
pub fn write_file<D: AsRef<[u8]>>(path: &str, data: D, ctx: &str) -> Result<()> {
std::fs::write(path, data.as_ref()).map_err(|e| Error::FileIo {
ty: FileIoErrorType::Write,
ctx: ctx.to_string(),
path: path.to_string(),
source: e,
})
}
/// Write content to a [`std::io::Write`] and add context in case of an error
///
/// * `path` - Path to file
/// * `ctx` - Error context string in case of an error
///
///
/// # Errors
/// Passes through any kind of error `std::fs::write` produces
pub fn write<D: AsRef<[u8]>, W: Write>(wr: &mut W, data: D, path: &str, ctx: &str) -> Result<()> {
wr.write_all(data.as_ref()).map_err(|e| Error::FileIo {
ty: FileIoErrorType::Write,
ctx: ctx.to_string(),
path: path.to_string(),
source: e,
})
}
/// Read all CRLs from the buffer and parse them into a vector.
///
/// # Errors
///
/// This function will return an error if the underlying openssl implementation cannot parse `buf`
/// This function will return an error if the underlying OpenSSL implementation cannot parse `buf`
/// as `DER` or `PEM`.
///
/// Requires the `request` feature.
#[cfg(feature = "request")]
pub fn read_crls(buf: &[u8]) -> Result<Vec<X509Crl>> {
use openssl_extensions::crl::StackableX509Crl;
X509Crl::from_der(buf)
@@ -343,11 +25,8 @@ pub fn read_crls(buf: &[u8]) -> Result<Vec<X509Crl>> {
///
/// # Errors
///
/// This function will return an error if the underlying openssl implementation cannot parse `buf`
/// as `DER` or `PEM`.
///
/// Requires the `request` feature.
#[cfg(feature = "request")]
/// This function will return an error if the underlying OpenSSL implementation cannot parse `buf`
pub fn read_certs(buf: &[u8]) -> Result<Vec<X509>> {
X509::from_der(buf)
.map(|crt| vec![crt])
@@ -355,191 +34,23 @@ pub fn read_certs(buf: &[u8]) -> Result<Vec<X509>> {
.map_err(Error::Crypto)
}
macro_rules! usize_to_ui {
($(#[$attr:meta])* => $t: ident, $name:ident) => {
///Converts an [`usize`] to an [`
$(#[$attr])*
///`] if possible
pub fn $name(u: usize) -> Option<$t> {
if u > $t::MAX as usize {
None
} else {
Some(u as $t)
}
}
}
}
usize_to_ui! {
#[doc = r"u32"]
=> u32, to_u32}
usize_to_ui! {
#[doc = r"u16"]
=> u16, to_u16}
/// Test if both slices contain the exact same bytes.
/// Read+parse the first key from the buffer.
///
/// Do not use this to compare cryptographic values (i.e. hashes)
pub fn memeq(lhs: &[u8], rhs: &[u8]) -> bool {
let size = lhs.len();
size == rhs.len()
&& unsafe {
let l = lhs as *const _ as _;
let r = rhs as *const _ as _;
(l as usize) == (r as usize) || libc::memcmp(l, r, size) == 0
}
}
/// Converts the hexstring into a byte vector.
/// # Errors
///
/// Stops if the end or until a non hex chat is found
pub fn parse_hex(hex_str: &str) -> Vec<u8> {
let mut hex_bytes = hex_str.as_bytes().iter().map_while(|b| match b {
b'0'..=b'9' => Some(b - b'0'),
b'a'..=b'f' => Some(b - b'a' + 10),
b'A'..=b'F' => Some(b - b'A' + 10),
_ => None,
});
let mut bytes = Vec::new();
while let (Some(h), Some(l)) = (hex_bytes.next(), hex_bytes.next()) {
bytes.push(h << 4 | l)
}
bytes
}
/// Report if the `prot_virt_guest` sysfs entry is one.
///
/// If the entry does not exist returns false.
///
/// for non-s390-architectures:
/// Returns always false
/// A non-s390 system cannot be a secure execution guest.
#[allow(unreachable_code)]
pub fn pv_guest_bit_set() -> bool {
#[cfg(not(target_arch = "s390x"))]
return false;
//s390 branch
let v = std::fs::read("/sys/firmware/uv/prot_virt_guest").unwrap_or_else(|_| vec![0]);
let v: u8 = String::from_utf8_lossy(&v[..1]).parse().unwrap_or(0);
v == 1
/// This function will return an error if the underlying OpenSSL implementation cannot parse `buf`
/// as `DER` or `PEM`.
pub fn read_private_key(buf: &[u8]) -> Result<PKey<Private>> {
PKey::private_key_from_der(buf)
.or_else(|_| PKey::private_key_from_pem(buf))
.map_err(Error::Crypto)
}
#[cfg(test)]
mod tests {
use std::usize;
use super::*;
#[cfg(feature = "request")]
use crate::test_utils::*;
use crate::{get_test_asset, test_utils::*};
#[test]
fn msb_flags() {
let v = 17;
let v_flag: Msb0Flags64 = v.into();
assert_eq!(v, v_flag.0.get());
let mut v: Msb0Flags64 = 4.into();
v.unset_bit(61);
assert_eq!(v.0.get(), 0);
v.set_bit(61);
assert_eq!(4, v.0.get());
let mut v = Msb0Flags64::default();
v.set_bit(0);
assert_eq!(&[0x80, 0, 0, 0, 0, 0, 0, 0], v.as_bytes());
v.set_bit(0);
assert_eq!(&[0x80, 0, 0, 0, 0, 0, 0, 0], v.as_bytes());
v.set_bit(1);
assert_eq!(&[0xc0, 0, 0, 0, 0, 0, 0, 0], v.as_bytes());
v.set_bit(2);
assert_eq!(&[0xe0, 0, 0, 0, 0, 0, 0, 0], v.as_bytes());
v.set_bit(3);
assert_eq!(&[0xf0, 0, 0, 0, 0, 0, 0, 0], v.as_bytes());
v.unset_bit(3);
assert_eq!(&[0xe0, 0, 0, 0, 0, 0, 0, 0], v.as_bytes());
v.unset_bit(3);
assert_eq!(&[0xe0, 0, 0, 0, 0, 0, 0, 0], v.as_bytes());
v.set_bit(16);
assert_eq!(&[0xe0, 0, 0x80, 0, 0, 0, 0, 0], v.as_bytes());
}
#[test]
#[should_panic]
fn msb_flags_set_panic() {
Msb0Flags64::default().set_bit(64)
}
#[test]
#[should_panic]
fn msb_flags_unset_panic() {
Msb0Flags64::default().unset_bit(64)
}
#[test]
fn lsb_flags() {
let v = 17;
let v_flag: Lsb0Flags64 = v.into();
assert_eq!(v, v_flag.0.get());
let mut v: Lsb0Flags64 = 4.into();
v.unset_bit(2);
assert_eq!(v.0.get(), 0);
v.set_bit(2);
assert_eq!(4, v.0.get());
let mut v = Lsb0Flags64::default();
v.set_bit(0);
assert_eq!(&[0, 0, 0, 0, 0, 0, 0, 1], v.as_bytes());
v.set_bit(0);
assert_eq!(&[0, 0, 0, 0, 0, 0, 0, 1], v.as_bytes());
v.set_bit(1);
assert_eq!(&[0, 0, 0, 0, 0, 0, 0, 3], v.as_bytes());
v.set_bit(2);
assert_eq!(&[0, 0, 0, 0, 0, 0, 0, 7], v.as_bytes());
v.set_bit(3);
assert_eq!(&[0, 0, 0, 0, 0, 0, 0, 0xf], v.as_bytes());
v.unset_bit(3);
assert_eq!(&[0, 0, 0, 0, 0, 0, 0, 7], v.as_bytes());
v.unset_bit(3);
assert_eq!(&[0, 0, 0, 0, 0, 0, 0, 7], v.as_bytes());
v.set_bit(16);
assert_eq!(&[0, 0, 0, 0, 0, 1, 0, 7], v.as_bytes());
}
#[test]
#[should_panic]
fn lsb_flags_set_panic() {
Lsb0Flags64::default().set_bit(64)
}
#[test]
#[should_panic]
fn lsb_flags_unset_panic() {
Lsb0Flags64::default().unset_bit(64)
}
#[test]
fn parse_hex() {
let s = "123456acbef0";
let exp = vec![0x12, 0x34, 0x56, 0xac, 0xbe, 0xf0];
assert_eq!(super::parse_hex(s), exp);
let s = "00123456acbef0";
let exp = vec![0, 0x12, 0x34, 0x56, 0xac, 0xbe, 0xf0];
assert_eq!(super::parse_hex(s), exp);
let s = "00123456acbef0ii90";
let exp = vec![0, 0x12, 0x34, 0x56, 0xac, 0xbe, 0xf0];
assert_eq!(super::parse_hex(s), exp);
}
#[test]
#[cfg(feature = "request")]
fn read_crls() {
let crl = get_cert_asset("ibm.crl");
let crl_der = get_cert_asset("der.crl");
@@ -550,7 +61,6 @@ mod tests {
}
#[test]
#[cfg(feature = "request")]
fn read_certs() {
let crt = get_cert_asset("ibm.crt");
let crt_der = get_cert_asset("der.crt");
@@ -561,98 +71,16 @@ mod tests {
}
#[test]
fn to_u32() {
assert_eq!(Some(17), super::to_u32(17));
assert_eq!(Some(0), super::to_u32(0));
assert_eq!(Some(u32::MAX), super::to_u32(u32::MAX as usize));
assert_eq!(None, super::to_u32(u32::MAX as usize + 1));
assert_eq!(None, super::to_u32(usize::MAX));
fn read_private_key() {
let key = get_test_asset!("keys/rsa3072key.pem");
let key = super::read_private_key(key).unwrap();
assert_eq!(key.rsa().unwrap().size(), 384);
}
#[test]
fn parse_u128() {
assert!(matches!(
try_parse_u128("123456", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("-1234", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("0011223344556677889900aabbccddeeff", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("dd11223344556677889900aabbccddeeff", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("-1223344556677889900aabbccddeeff", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("0x123456", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("-0x1234", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("0x0011223344556677889900aabbccddeeff", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("0xdd11223344556677889900aabbccddeeff", ""),
Err(Error::Specification(_))
));
assert!(matches!(
try_parse_u128("0x-1223344556677889900aabbccddeeff", ""),
Err(Error::Specification(_))
));
assert_eq!(
[
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff
],
try_parse_u128("11223344556677889900aabbccddeeff", "").unwrap()
);
assert_eq!(
[
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff
],
try_parse_u128("0x11223344556677889900aabbccddeeff", "").unwrap()
);
assert_eq!(
[
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff
],
try_parse_u128("00112233445566778899aabbccddeeff", "").unwrap()
);
assert_eq!(
[
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff
],
try_parse_u128("00112233445566778899aabbccddeeff", "").unwrap()
);
}
#[test]
fn memeq() {
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
let b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1];
let c = [0, 0, 1, 2, 3, 4];
assert!(super::memeq(&a, &a));
assert!(super::memeq(&a, &a.clone()));
assert!(!super::memeq(&b, &a));
assert!(!super::memeq(&b, &c));
assert!(!super::memeq(&b, &[]));
fn read_private_key_fail() {
let key = get_test_asset!("exp/secure_guest.hdr");
let key = super::read_private_key(key);
assert!(key.is_err());
}
}

View File

@@ -2,79 +2,12 @@
//
// Copyright IBM Corp. 2023
#![cfg(feature = "uvsecret")]
//! Provides functionality to manage the UV secret store.
//!
//! Provides functionality to build `add-secret` requests.
//! Also provides interfaces, to dispatch `Add Secret`, `Lock Secret Store`,
//! and `List Secrets` requests,
#[cfg(feature = "request")]
pub mod asrcb;
#[cfg(feature = "request")]
pub mod ext_secret;
#[cfg(feature = "request")]
pub mod guest_secret;
pub mod secret_list;
pub mod uvc;
use crate::request::MagicValue;
use crate::requires_feat;
#[allow(unused_imports)] //used for more convenient docstring
use asrcb::AddSecretRequest;
/// Types of (non architectured) user data for [`AddSecretRequest`]
///
#[doc = requires_feat!(uvsecret)]
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, zerocopy::AsBytes)]
pub enum UserDataType {
/// Marker that the request does not contain any user data
Null = 0x0000,
}
/// The magic value used to identify an [`AddSecretRequest`]
///
/// The magic value is ASCII:
/// ```rust
/// # use pv::request::uvsecret::AddSecretMagic;
/// # use pv::request::MagicValue;
/// # fn main() {
/// # let magic =
/// # b"asrcbM"
/// # ;
/// # assert!(AddSecretMagic::starts_with_magic(magic));
/// # }
///```
///
#[doc = requires_feat!(uvsecret)]
#[repr(C)]
#[derive(Debug, Clone, Copy, zerocopy::AsBytes)]
pub struct AddSecretMagic {
magic: [u8; 6], // [0x61, 0x73, 0x72, 0x63, 0x62, 0x4D]
tp: UserDataType,
}
impl MagicValue<6> for AddSecretMagic {
// "asrcbM"
const MAGIC: [u8; 6] = [0x61, 0x73, 0x72, 0x63, 0x62, 0x4D];
}
impl From<UserDataType> for AddSecretMagic {
fn from(tp: UserDataType) -> Self {
Self {
magic: Self::MAGIC,
tp,
}
}
}
const SECRET_ID_SIZE: usize = 32;
fn ser_gsid<S>(id: &[u8; SECRET_ID_SIZE], ser: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut s = String::with_capacity(32 * 2 + 2);
s.push_str("0x");
let s = id.iter().fold(s, |acc, e| acc + &format!("{e:02x}"));
ser.serialize_str(&s)
}
pub mod user_data;

View File

@@ -2,23 +2,23 @@
//
// Copyright IBM Corp. 2023
use super::{AddSecretMagic, UserDataType};
use crate::requires_feat;
use super::user_data::UserData;
use crate::{
assert_size,
misc::Flags,
request::{
hkdf_rfc_5869,
openssl::{
pkey::{PKey, Public},
pkey::{PKey, Private, Public},
Md,
},
uvsecret::{ExtSecret, GuestSecret},
Aad, BootHdrTags, Keyslot, ReqEncrCtx, Request, RequestVersion, Secret,
Aad, BootHdrTags, Keyslot, ReqEncrCtx, Request, Secret,
},
uv::{ConfigUid, UvFlags},
Result,
};
use pv_core::request::RequestVersion;
use zerocopy::AsBytes;
/// Internal wrapper for Guest Secret, so that we can dump it in the form the UV wants it to be
@@ -52,6 +52,7 @@ impl From<GuestSecret> for BinGuestSecret {
}
}
/// Authenticated data w/o user data
#[repr(C)]
#[derive(Debug, Clone, Copy, AsBytes)]
struct ReqAuthData {
@@ -59,9 +60,8 @@ struct ReqAuthData {
boot_tags: BootHdrTags,
cuid: ConfigUid,
reserved90: [u8; 0x100],
prog_res190: [u8; 0x200],
}
assert_size!(ReqAuthData, 0x3e8);
assert_size!(ReqAuthData, 0x1e8);
impl ReqAuthData {
fn new<F: Into<UvFlags>>(boot_tags: BootHdrTags, flags: F) -> Self {
@@ -70,7 +70,6 @@ impl ReqAuthData {
boot_tags,
cuid: [0; 0x10],
reserved90: [0; 0x100],
prog_res190: [0; 0x200],
}
}
}
@@ -96,8 +95,6 @@ impl ReqConfData {
}
/// Flags for [`AddSecretRequest`]
///
#[doc = requires_feat!(reqsecret)]
#[derive(Default, Clone, Copy, Debug)]
pub struct AddSecretFlags(UvFlags);
impl AddSecretFlags {
@@ -123,8 +120,6 @@ impl From<AddSecretFlags> for UvFlags {
}
/// Versions for [`AddSecretRequest`]
///
#[doc = requires_feat!(reqsecret)]
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AddSecretVersion {
@@ -143,12 +138,6 @@ impl From<AddSecretVersion> for RequestVersion {
}
}
impl AddSecretMagic {
fn get(&self) -> crate::request::RequestMagic {
self.as_bytes().try_into().unwrap()
}
}
/// Add-secret request Control Block
///
/// An ASRCB wraps a secret to transport it securely to the Ultravisor.
@@ -158,6 +147,7 @@ impl AddSecretMagic {
/// _______________________________________________________________
/// | generic header (48)
/// | --------------------------------------------------- |
/// | Plaintext Add-Secret flags (8) |
/// | SE header tags: PLD(64) ALD(64) TLD(64) HeaderTag(16) |
/// | Configuration unique ID(16) (Attestation) |
/// | Optional, defaults to 0 |
@@ -173,18 +163,19 @@ impl AddSecretMagic {
/// | AES GCM Tag (16) |
/// |_____________________________________________________________|
///```
///
#[doc = requires_feat!(reqsecret)]
#[derive(Clone, Debug)]
pub struct AddSecretRequest {
magic: AddSecretMagic,
version: AddSecretVersion,
aad: ReqAuthData,
keyslots: Vec<Keyslot>,
conf: ReqConfData,
user_data: UserData,
}
impl AddSecretRequest {
/// Offset of the user-data in the add-secret request in bytes
pub(super) const V1_USER_DATA_OFFS: usize = 0x218;
/// Create a new add-secret request.
///
/// The request has no extension secret, no configuration UID, no host-keys,
@@ -204,7 +195,7 @@ impl AddSecretRequest {
aad: ReqAuthData::new(boot_tags, flags),
keyslots: vec![],
version,
magic: UserDataType::Null.into(),
user_data: UserData::Null,
}
}
@@ -238,18 +229,41 @@ impl AddSecretRequest {
&self.conf.secret.0
}
/// Add user-data to the Add-Secret request
///
/// (Signed) user-data is a non-architectual feature. It allows to add arbitrary
/// data (message) to the request, that is signed optionally with an user defined key.
/// Allowed keys are:
/// - no key (up to 512 bytes of message)
/// - EC SECP521R1 (up to 256 byte message)
/// - RSA 2048 bit (up to 256 byte message)
/// - RSA 3072 bit (up to 128 byte message)
///
/// The signature can be verified during the verification of the secret-request on the target machine.
pub fn set_user_data(&mut self, msg: Vec<u8>, skey: Option<PKey<Private>>) -> Result<()> {
self.user_data = UserData::new(skey, msg)?;
Ok(())
}
/// compiles the authenticated area of this request
fn aad(&self, ctx: &ReqEncrCtx, conf_len: usize) -> Result<Vec<u8>> {
let cust_pub_key = ctx.key_coords()?;
let secr_auth = self.conf.secret.dump_auth();
let user_data = self.user_data.data();
let mut aad: Vec<Aad> = Vec::with_capacity(3 + self.keyslots.len());
let mut aad: Vec<Aad> = Vec::with_capacity(5 + self.keyslots.len());
aad.push(Aad::Plain(self.aad.as_bytes()));
if let Some(data) = user_data.0 {
aad.push(Aad::Plain(data));
}
if let Some(data) = &user_data.1 {
aad.push(Aad::Plain(data));
}
aad.push(Aad::Plain(cust_pub_key.as_ref()));
self.keyslots.iter().for_each(|k| aad.push(Aad::Ks(k)));
aad.push(Aad::Plain(&secr_auth));
ctx.build_aad(self.version.into(), &aad, conf_len, self.magic.get())
ctx.build_aad(self.version.into(), &aad, conf_len, self.user_data.magic())
}
#[doc(hidden)]
@@ -268,13 +282,41 @@ impl AddSecretRequest {
res.append(&mut vec![0x24; 32]);
Ok(res)
}
/// encrypt data, sign request with user-provided signing key, insert signature into aad,
/// calculate request tag
fn encrypt_with_signed_user_data(&self, ctx: &ReqEncrCtx) -> Result<Vec<u8>> {
//encrypt data w/o aead
let conf = self.conf.to_bytes();
let aad = self.aad(ctx, conf.value().len())?;
let (mut buf, aad_range, encr_range, _) = ctx.encrypt_aead(&aad, conf.value())?;
drop(aad);
// sign aad+encrypted data (w/o tag) with user signning key
// add signature to authenticated data starting with USER_DATA_OFFS
self.user_data.sign(
&mut buf[aad_range.start..encr_range.end],
Self::V1_USER_DATA_OFFS,
)?;
// encrypt again with signed data
buf[encr_range.clone()].copy_from_slice(conf.value());
ctx.encrypt_aead(&buf[aad_range], &buf[encr_range])
.map(|(buf, ..)| buf)
}
}
impl Request for AddSecretRequest {
fn encrypt(&self, ctx: &ReqEncrCtx) -> Result<Vec<u8>> {
let conf = self.conf.to_bytes();
let aad = self.aad(ctx, conf.value().len())?;
ctx.encrypt_aead(&aad, conf.value())
match self.user_data {
UserData::Null | UserData::Unsigned(_) => {
let conf = self.conf.to_bytes();
let aad = self.aad(ctx, conf.value().len())?;
ctx.encrypt_aead(&aad, conf.value()).map(|(buf, ..)| buf)
}
_ => self.encrypt_with_signed_user_data(ctx),
}
}
fn add_hostkey(&mut self, hostkey: PKey<Public>) {

View File

@@ -2,11 +2,9 @@
//
// Copyright IBM Corp. 2023
use crate::{request::Secret, requires_feat};
use crate::request::Secret;
/// Extension Secret for [`crate::request::uvsecret::AddSecretRequest`]
///
#[doc = requires_feat!(reqsecret)]
#[derive(Debug, Clone)]
pub enum ExtSecret {
/// A bytepattern that must be equal for each request targeting the same SE-guest instance

View File

@@ -4,18 +4,16 @@
#[allow(unused_imports)] //used for more convenient docstring
use super::asrcb::AddSecretRequest;
use super::{ser_gsid, SECRET_ID_SIZE};
use crate::{
request::{hash, openssl::MessageDigest, random_array, Secret},
requires_feat, Result,
Result,
};
use pv_core::for_pv::{ser_gsid, SECRET_ID_SIZE};
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
const SECRET_SIZE: usize = 32;
/// A Secret to be added in [`AddSecretRequest`]
///
#[doc = requires_feat!(reqsecret)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum GuestSecret {
/// No guest secret
@@ -105,7 +103,7 @@ mod test {
0xef, 0xc7, 0x3c, 0x62,
];
let name = "association secret".to_string();
let secret = GuestSecret::association("association secret", secret_value.clone()).unwrap();
let secret = GuestSecret::association("association secret", secret_value).unwrap();
let exp = GuestSecret::Association {
name,
id: exp_id,

View File

@@ -1,224 +0,0 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp. 2023
use crate::{misc::to_u16, uv::ListCmd, uvdevice::UvCmd, Error, Result};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use serde::{Serialize, Serializer};
use std::usize;
use std::{
fmt::Display,
io::{Cursor, Read, Seek, Write},
};
use zerocopy::{AsBytes, FromBytes, U16, U32};
use super::ser_gsid;
/// List of secrets used to parse the [`crate::uv::ListCmd`] result
///
/// Requires the `uvsecret` feature.
#[derive(Debug, PartialEq, Eq, Serialize)]
pub struct SecretList {
total_num_secrets: u16,
secrets: Vec<SecretEntry>,
}
impl SecretList {
/// Encodes the list in the same binary format the UV would do
pub fn encode<T: Write>(&self, w: &mut T) -> Result<()> {
let num_s = to_u16(self.secrets.len()).ok_or(Error::ManySecrets)?;
w.write_u16::<BigEndian>(num_s)?;
w.write_u16::<BigEndian>(self.total_num_secrets)?;
w.write_all(&[0u8; 12])?;
for secret in &self.secrets {
w.write_all(secret.as_bytes())?;
}
w.flush().map_err(Error::Io)
}
/// Decodes the list from the binary format of the UV into this internal representation
pub fn decode<R: Read + Seek>(r: &mut R) -> std::io::Result<Self> {
let num_s = r.read_u16::<BigEndian>()?;
let total_num_secrets = r.read_u16::<BigEndian>()?;
let mut v: Vec<SecretEntry> = Vec::with_capacity(num_s as usize);
r.seek(std::io::SeekFrom::Current(12))?; //skip reserved bytes
let mut buf = [0u8; SECRET_ENTRY_SIZE];
for _ in 0..num_s {
r.read_exact(&mut buf)?;
//cannot fail. buffer has the same size as the secret entry
let secr = SecretEntry::read_from(buf.as_slice()).unwrap();
v.push(secr);
}
Ok(Self {
total_num_secrets,
secrets: v,
})
}
}
impl TryFrom<ListCmd> for SecretList {
type Error = Error;
fn try_from(mut list: ListCmd) -> Result<SecretList> {
SecretList::decode(&mut Cursor::new(list.data().unwrap())).map_err(Error::InvSecretList)
}
}
impl Display for SecretList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Total number of secrets: {}", self.total_num_secrets)?;
if !self.secrets.is_empty() {
writeln!(f)?;
}
for s in &self.secrets {
writeln!(f, "{s}")?;
}
Ok(())
}
}
fn ser_u32<S: Serializer>(v: &U32<BigEndian>, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_u32(v.get())
}
fn ser_u16<S: Serializer>(v: &U16<BigEndian>, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_u16(v.get())
}
/// A secret in a [`SecretList`]
///
/// Fields are in big endian
#[repr(C)]
#[derive(Debug, PartialEq, Eq, AsBytes, FromBytes, Serialize)]
pub struct SecretEntry {
#[serde(serialize_with = "ser_u16")]
index: U16<BigEndian>,
#[serde(serialize_with = "ser_u16")]
stype: U16<BigEndian>,
#[serde(serialize_with = "ser_u32")]
len: U32<BigEndian>,
#[serde(skip)]
res_8: u64,
#[serde(serialize_with = "ser_gsid")]
id: [u8; 32],
}
const SECRET_ENTRY_SIZE: usize = 0x30;
fn stype_str(stype: u16) -> String {
match stype {
// should never match (not incl in list), but here for completeness
1 => "Null".to_string(),
2 => "Association".to_string(),
n => format!("Unknown {n}"),
}
}
impl Display for SecretEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{} {}:", self.index, stype_str(self.stype.get()))?;
write!(f, " ")?;
for b in self.id {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use std::io::{BufReader, BufWriter, Cursor};
#[test]
fn secret_entry_size() {
assert_eq!(::std::mem::size_of::<SecretEntry>(), SECRET_ENTRY_SIZE);
}
#[test]
fn dump_secret_entry() {
const EXP: &[u8] = &[
0x00, 0x01, 0x00, 0x02, //idx + type
0x00, 0x00, 0x00, 0x20, //len
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
// id
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
];
let s = SecretEntry {
index: 1.into(),
stype: 2.into(),
len: 32.into(),
res_8: 0,
id: [0; 32],
};
assert_eq!(s.as_bytes(), EXP);
}
#[test]
fn secret_list_dec() {
let buf = [
0x00u8, 0x01, // num secr stored
0x01, 0x12, // total num secrets
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //reserved
// secret
0x00, 0x01, 0x00, 0x02, //idx + type
0x00, 0x00, 0x00, 0x20, //len
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
// id
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
];
let exp = SecretList {
total_num_secrets: 0x112,
secrets: vec![SecretEntry {
index: 1.into(),
stype: 2.into(),
len: 32.into(),
res_8: 0,
id: [0; 32],
}],
};
let mut br = BufReader::new(Cursor::new(buf));
let sl = SecretList::decode(&mut br).unwrap();
assert_eq!(sl, exp);
}
#[test]
fn secret_list_enc() {
const EXP: &[u8] = &[
0x00, 0x01, // num secr stored
0x01, 0x12, // total num secrets
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //reserved
// secret
0x00, 0x01, 0x00, 0x02, //idx + type
0x00, 0x00, 0x00, 0x20, //len
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
// id
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
];
let sl = SecretList {
total_num_secrets: 0x112,
secrets: vec![SecretEntry {
index: 1.into(),
stype: 2.into(),
len: 32.into(),
res_8: 0,
id: [0; 32],
}],
};
let mut buf = [0u8; 0x40];
{
let mut bw = BufWriter::new(&mut buf[..]);
sl.encode(&mut bw).unwrap();
}
println!("list: {sl:?}");
assert_eq!(buf, EXP);
}
}

View File

@@ -0,0 +1,611 @@
use crate::{
crypto::{sign_msg, verify_signature},
req::BinReqValues,
request::{
openssl::{
pkey::{PKey, Private},
MessageDigest,
},
uvsecret::{AddSecretRequest, AddSecretVersion},
RequestMagic,
},
Error, Result,
};
use openssl::{
nid::Nid,
pkey::{HasParams, HasPublic, Id, PKeyRef, Public},
};
use pv_core::request::uvsecret::AddSecretMagic;
use pv_core::request::uvsecret::UserDataType;
use utils::assert_size;
use zerocopy::{AsBytes, BigEndian, FromBytes, FromZeroes, U16};
/// User data.
///
/// User defined data can be:
/// - 512 bytes arbitrary data
/// - 256 bytes arbitrary data + EC(secp521r1) signature
/// ```none
/// LAYOUT
/// |------------------------|
/// | user-data (256) |
/// | ec signature (139) |
/// | reserved (5) |
/// | signature size (2) (BE)|
/// | reserved (110) |
/// |------------------------|
/// ```
/// - 256 bytes arbitrary data + RSA2048 signature
/// ```none
/// LAYOUT
/// |---------------------|
/// | user-data (256) |
/// | rsa signature (256) |
/// |---------------------|
/// ```
/// - 128 bytes arbitrary data + RSA3072 signature
/// ```none
/// LAYOUT
/// |---------------------|
/// | user-data (128) |
/// | rsa signature (384) |
/// |---------------------|
/// ```
///
/// Ensures that the data+signature fits into 512 bytes
/// must be created via functions!
#[derive(Debug, Clone)]
pub(super) enum UserData {
Null,
Unsigned(Vec<u8>),
Signed(SignedUserData),
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
struct EcUserData {
data: [u8; 256],
signature: [u8; EC_SIGN_MAX_SIZE],
res_18b: [u8; 5],
sgn_size: U16<BigEndian>,
res_192: [u8; 110],
}
assert_size!(EcUserData, USER_DATA_SIZE);
const USER_DATA_SIZE: usize = 0x200;
const EC_SIGN_MAX_SIZE: usize = 139;
impl EcUserData {
// Sets the signature to this data.
//
//# Panic
// Panics if `sgn` is longer than 139 bytes
fn set_signature(&mut self, sgn: &[u8]) {
debug_assert!(sgn.len() <= EC_SIGN_MAX_SIZE);
self.signature.fill(0);
self.signature[..sgn.len()].copy_from_slice(sgn);
self.res_18b.fill(0);
self.sgn_size = (sgn.len() as u16).into();
self.res_192.fill(0);
}
}
#[derive(Debug, Clone)]
pub(super) struct SignedUserData {
sign_key: PKey<Private>,
data: Vec<u8>,
}
impl UserData {
const USER_DATA_SIZE: usize = 0x200;
fn user_data_type<P: HasPublic>(sign_key: &PKeyRef<P>) -> Result<UserDataType> {
fn check_curve<P: HasParams>(pkey: &PKeyRef<P>) -> Result<bool> {
let nid = pkey.ec_key()?.group().curve_name();
match nid {
Some(nid) => Ok(nid == Nid::SECP521R1),
None => Ok(false),
}
}
match sign_key.id() {
Id::EC if check_curve(sign_key)? => Ok(UserDataType::SgnEcSECP521R1),
Id::RSA if sign_key.rsa()?.size() == 2048 / 8 => Ok(UserDataType::SgnRsa2048),
Id::RSA if sign_key.rsa()?.size() == 3072 / 8 => Ok(UserDataType::SgnRsa3072),
_ => Err(Error::BinAsrcbUnsupportedUserDataSgnKey),
}
}
pub(super) fn magic(&self) -> RequestMagic {
let magic: AddSecretMagic = self.data_type().into();
magic.get()
}
/// Creates new user data
///
/// Verifies that the provided data + signature fits into 512 bytes
///
/// #Error
/// An error is reported if the provided data and the signature would not fit into 512 bytes
/// An error is reported if the key is not of type RSA (2048|3072) or EC(specp521r1)
pub(super) fn new(sign_key: Option<PKey<Private>>, data: Vec<u8>) -> Result<Self> {
let sign_key = match sign_key {
None => {
return match data.len() > UserDataType::Unsigned.max() {
true => Err(Error::AsrcbInvSgnUserData(UserDataType::Unsigned)),
false => Ok(Self::Unsigned(data)),
};
}
Some(skey) => skey,
};
let kind = Self::user_data_type(&sign_key)?;
// does the data fit into the arbitrary buffer?
if data.len() > kind.max() {
return Err(Error::AsrcbInvSgnUserData(kind));
}
Ok(Self::Signed(SignedUserData { sign_key, data }))
}
/// Signs data in buf, writes signature to buf+user_data_offset+sign_offset if applicable.
///
/// Uses [`MessageDigest::sha512`] as digest. Does not modify the abritary user data buffer.
///
/// * buf: user data buffer, must be at least 512 bytes long
///
/// # Panic
/// panics if `buf` is smaller than 512 bytes
///
/// # Errors
/// Returns an error if signature could not be calculated.
/// It is considered no error if no signature is required by user data type
pub(super) fn sign(&self, buf: &mut [u8], user_data_offset: usize) -> Result<()> {
// get signing info or return if no signature is required
let signed_data = match self {
UserData::Null | UserData::Unsigned(_) => return Ok(()),
UserData::Signed(s) => s,
};
debug_assert!(buf.len() >= USER_DATA_SIZE);
// clear the signature area
let sgn_offset = user_data_offset + self.data_type().max();
buf[sgn_offset..user_data_offset + USER_DATA_SIZE].fill(0);
// calculate signature
let sgn = sign_msg(&signed_data.sign_key, MessageDigest::sha512(), buf)?;
// insert signature
if let UserDataType::SgnEcSECP521R1 = self.data_type() {
// Panic: will not panic buffer is 512+ bytes long
let buf_ec = EcUserData::mut_from_prefix(&mut buf[user_data_offset..]).unwrap();
buf_ec.set_signature(&sgn);
} else {
// Panic: will not panic buffer is 512+ bytes long
buf[sgn_offset..sgn_offset + sgn.len()].copy_from_slice(&sgn);
}
Ok(())
}
fn data_type(&self) -> UserDataType {
match self {
Self::Null => UserDataType::Null,
Self::Unsigned(_) => UserDataType::Unsigned,
Self::Signed(data) => Self::user_data_type(&data.sign_key).unwrap(),
}
}
/// returns a slice for the abitraty user data as first tuple part if User data is available
/// the second part contains a vector, created on the fly, which contains enough zeros to fill
/// the missing bytes to fill 512 bytes of space or None if the first slice already contains
/// 512 bytes
pub(super) fn data(&self) -> (Option<&[u8]>, Option<Vec<u8>>) {
let buf = match self {
UserData::Null => None,
UserData::Unsigned(d) => Some(d),
UserData::Signed(SignedUserData { data, .. }) => Some(data),
};
let remaining_size = Self::USER_DATA_SIZE - buf.map(|b| b.len()).unwrap_or(0);
let remaining = match remaining_size > 0 {
true => Some(vec![0; remaining_size]),
false => None,
};
(buf.map(|b| b.as_ref()), remaining)
}
}
fn format_vrfy_key(key: &PKeyRef<Public>) -> String {
let id = key.id();
match key.rsa() {
Ok(key) => format!("RSA {}", key.size() * 8),
Err(_) if id == Id::EC => "EC".to_string(),
Err(_) => "Unknown".to_string(),
}
}
fn check_key_format(kind: UserDataType, key: &PKeyRef<Public>) -> Result<()> {
let other_kind =
UserData::user_data_type(key).map_err(|_| Error::AsrcbUserDataKeyMismatch {
key: format_vrfy_key(key),
kind,
})?;
if other_kind == kind {
Ok(())
} else {
Err(Error::AsrcbUserDataKeyMismatch {
key: format_vrfy_key(key),
kind,
})
}
}
/// Verify the user data contained in the add-secret request.
///
/// First checks that the provided data contains a sound add-secret request.
/// Then performs the inverse action that happened during the add-secret generation with user-data
/// signature:
/// - extract and replace the signature with zeros
/// - verify the signature of the request until, but not including the request tag
///
/// # Returns
///
/// Extracrted user-data if available
///
/// #Errors
///
/// returns an error if
/// - No sound add-secret request presented
/// - Sinned user-data indicated, but no key provided
/// - Another keytype provided than indicated in the request
/// - Signature could not be verified by the provided key
/// - any OpenSSL error that might happen during the verification process
pub fn verify_asrcb_and_get_user_data(
mut asrcb: Vec<u8>,
key: Option<PKey<Public>>,
) -> Result<Option<Vec<u8>>> {
// check that the provided buffer contains an Add Secret request
let magic = AddSecretMagic::try_from_bytes(&asrcb)?;
let req = BinReqValues::get(&asrcb)?;
if req.version() != AddSecretVersion::One as u32 {
return Err(Error::BinAsrcbInvVersion);
}
//preventing the two lines after the truncate from panicking
let req_len = req.len();
if asrcb.len() < req_len
|| req_len < AddSecretRequest::V1_USER_DATA_OFFS + UserData::USER_DATA_SIZE
{
return Err(pv_core::Error::NoAsrcb.into());
}
// forget the tag (and all additional data that might be behind the tag)
asrcb.truncate(req_len - BinReqValues::TAG_LEN);
// get a mutable refrenence on the 512 bytes of user data
let (_, user_data) = asrcb.split_at_mut(AddSecretRequest::V1_USER_DATA_OFFS);
let user_data = &mut user_data[..UserData::USER_DATA_SIZE];
// depending on the user_data_type do:
// Null -> exit w/o user data
// Unsigned -> exit return all user data
// Signed ->
// - check that provided key matches user data keytype
// - extract user data& signature
let (key, user_data) = match (key, magic.kind()) {
(_, UserDataType::Null) => return Ok(None),
(None, UserDataType::Unsigned) => return Ok(Some(user_data.to_vec())),
(Some(key), UserDataType::Unsigned) => {
return Err(Error::AsrcbUserDataKeyMismatch {
key: format_vrfy_key(&key),
kind: UserDataType::Unsigned,
})
}
(Some(key), _) => {
check_key_format(magic.kind(), &key)?;
(key, VerifiedUserData::new(user_data, magic.kind()))
}
(None, _) => return Err(Error::BinAsrcbNoUserDataSgnKey),
};
match verify_signature(&key, MessageDigest::sha512(), &asrcb, user_data.signature())? {
false => Err(Error::AsrcbUserDataSgnFail),
true => Ok(Some(user_data.into())),
}
}
// Internal representation of the 512 bytes of user-data, signing-algorithm agnostic
struct VerifiedUserData {
data: Vec<u8>,
signature: Vec<u8>,
}
impl VerifiedUserData {
/// Reads user-data from buf depending on the indicated user data type.
/// Overwrites the signature in the buf with zeros.
///
/// #Panics
/// Panics it provided buffer is smaller that 512 bytes or kind is Null or Unsigned
fn new(buf: &mut [u8], kind: UserDataType) -> Self {
assert!(buf.len() >= 0x200);
let (ret, sgn) = match kind {
UserDataType::SgnEcSECP521R1 => {
let EcUserData {
data,
signature,
sgn_size,
..
} = EcUserData::mut_from_prefix(buf).unwrap();
let data_len: usize = data.len();
let data = data.to_vec();
let mut signature = signature.to_vec();
signature.truncate(sgn_size.get() as usize);
(Self { data, signature }, &mut buf[data_len..])
}
UserDataType::SgnRsa2048 => (
Self {
data: buf[..0x100].to_vec(),
signature: buf[0x100..].to_vec(),
},
&mut buf[0x100..],
),
UserDataType::SgnRsa3072 => (
Self {
data: buf[..0x80].to_vec(),
signature: buf[0x80..].to_vec(),
},
&mut buf[0x80..],
),
UserDataType::Null => unreachable!(),
UserDataType::Unsigned => unreachable!(),
};
//overwrite signature field with zeros
sgn.fill(0);
ret
}
fn signature(&self) -> &[u8] {
self.signature.as_ref()
}
}
impl From<VerifiedUserData> for Vec<u8> {
fn from(value: VerifiedUserData) -> Self {
value.data
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{get_test_asset, test_utils::get_test_keys};
#[test]
fn sign_null() {
let mut buf = vec![17; 0x200];
let user_data = UserData::Null;
let (data, _) = user_data.data();
assert!(data.is_none());
user_data.sign(&mut buf, 0).unwrap();
// sign should not touch the buffer
assert_eq!(buf, vec![17; 0x200]);
}
#[test]
fn sign_unsigned() {
let user_data = UserData::Unsigned(vec![0x11; 0x200]);
let (data, _) = user_data.data();
assert_eq!(data.unwrap(), &[0x11; 0x200]);
let mut buf = vec![17; 0x200];
user_data.sign(&mut buf, 0).unwrap();
// sign should not touch the buffer
assert_eq!(buf, vec![17; 0x200]);
}
#[test]
fn sign_rsa2048() {
let rsa = get_test_asset!("keys/rsa2048key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let mut buf = vec![0x17; 0x200];
let user_data = UserData::new(Some(rsa.clone()), vec![0x11; 0x100]).unwrap();
let (data, _) = user_data.data();
let data = data.unwrap();
buf[..0x100].copy_from_slice(data);
user_data.sign(&mut buf, 0).unwrap();
let vrf_user_data = VerifiedUserData::new(&mut buf, UserDataType::SgnRsa2048);
let res = verify_signature(
&rsa,
MessageDigest::sha512(),
&buf,
vrf_user_data.signature(),
)
.unwrap();
assert!(res);
}
#[test]
fn sign_rsa3072() {
let rsa = get_test_asset!("keys/rsa3072key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let mut buf = vec![0x17; 0x200];
let user_data = UserData::new(Some(rsa.clone()), vec![0x11; 0x80]).unwrap();
let (data, _) = user_data.data();
let data = data.unwrap();
buf[..0x80].copy_from_slice(data);
user_data.sign(&mut buf, 0).unwrap();
let vrf_user_data = VerifiedUserData::new(&mut buf, UserDataType::SgnRsa3072);
let res = verify_signature(
&rsa,
MessageDigest::sha512(),
&buf,
vrf_user_data.signature(),
)
.unwrap();
assert!(res);
}
#[test]
fn sign_rsa4096_fail() {
let rsa = get_test_asset!("keys/rsa4096key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let user_data = UserData::new(Some(rsa.clone()), vec![]);
assert!(matches!(
user_data.unwrap_err(),
Error::BinAsrcbUnsupportedUserDataSgnKey
));
}
#[test]
fn sign_ec() {
let (ec, _) = get_test_keys();
let mut buf = vec![0x11; 0x200];
let user_data = UserData::new(Some(ec.clone()), vec![0x11; 0x80]).unwrap();
let (data, _) = user_data.data();
let data = data.unwrap();
buf[..0x80].copy_from_slice(data);
user_data.sign(&mut buf, 0).unwrap();
let buf_ec = EcUserData::mut_from(&mut buf).unwrap();
let EcUserData {
data,
signature,
res_18b,
sgn_size,
res_192,
} = buf_ec;
assert_eq!(data, &[0x11u8; 256]);
assert_ne!(signature, &[0x11u8; 139]);
assert_eq!(res_18b, &[0u8; 5]);
assert!(sgn_size.get() <= 139);
assert_eq!(res_192, &[0u8; 110]);
let vrf_user_data = VerifiedUserData::new(&mut buf, UserDataType::SgnEcSECP521R1);
let res = verify_signature(
&ec,
MessageDigest::sha512(),
&buf,
vrf_user_data.signature(),
)
.unwrap();
assert!(res);
}
#[test]
fn sign_ec_fail() {
let ec = get_test_asset!("keys/ecsecp256k1.pem");
let ec = PKey::private_key_from_pem(ec).unwrap();
let user_data = UserData::new(Some(ec.clone()), vec![]);
assert!(matches!(
user_data.unwrap_err(),
Error::BinAsrcbUnsupportedUserDataSgnKey
));
}
#[test]
fn check_format() {
let (_, ec) = get_test_keys();
check_key_format(UserDataType::SgnEcSECP521R1, &ec).unwrap();
let res = check_key_format(UserDataType::SgnRsa2048, &ec);
assert!(matches!(res, Err(Error::AsrcbUserDataKeyMismatch { .. })));
let rsa = get_test_asset!("keys/rsa2048key.pub.pem");
let rsa = PKey::public_key_from_pem(rsa).unwrap();
check_key_format(UserDataType::SgnRsa2048, &rsa).unwrap();
let rsa = get_test_asset!("keys/rsa3072key.pub.pem");
let rsa = PKey::public_key_from_pem(rsa).unwrap();
check_key_format(UserDataType::SgnRsa3072, &rsa).unwrap();
let res = check_key_format(UserDataType::SgnRsa2048, &rsa);
assert!(matches!(res, Err(Error::AsrcbUserDataKeyMismatch { .. })));
let rsa = get_test_asset!("keys/rsa4096key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let rsa = PKey::public_key_from_pem(&rsa.public_key_to_pem().unwrap()).unwrap();
let res = check_key_format(UserDataType::SgnRsa2048, &rsa);
assert!(matches!(res, Err(Error::AsrcbUserDataKeyMismatch { .. })));
}
#[test]
fn kind() {
let (ec, _) = get_test_keys();
let kind = UserData::user_data_type(&ec).unwrap();
assert_eq!(kind, UserDataType::SgnEcSECP521R1);
let rsa = get_test_asset!("keys/rsa2048key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let kind = UserData::user_data_type(&rsa).unwrap();
assert_eq!(kind, UserDataType::SgnRsa2048);
let rsa = get_test_asset!("keys/rsa3072key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let kind = UserData::user_data_type(&rsa).unwrap();
assert_eq!(kind, UserDataType::SgnRsa3072);
let rsa = get_test_asset!("keys/rsa4096key.pem");
let rsa = PKey::private_key_from_pem(rsa).unwrap();
let kind = UserData::user_data_type(&rsa).unwrap_err();
assert!(matches!(kind, Error::BinAsrcbUnsupportedUserDataSgnKey));
}
#[test]
fn new() {
let (ec, _) = get_test_keys();
let user_data = UserData::new(
Some(ec.clone()),
vec![1; UserDataType::SgnEcSECP521R1.max()],
)
.unwrap();
assert!(matches!(user_data, UserData::Signed(_)));
let user_data = UserData::new(Some(ec), vec![1; UserDataType::SgnEcSECP521R1.max() + 1]);
assert!(matches!(
user_data,
Err(Error::AsrcbInvSgnUserData(UserDataType::SgnEcSECP521R1))
));
let user_data = UserData::new(None, vec![1; UserDataType::Unsigned.max()]).unwrap();
assert!(matches!(user_data, UserData::Unsigned(_)));
let user_data = UserData::new(None, vec![1; UserDataType::Unsigned.max() + 1]);
assert!(matches!(
user_data,
Err(Error::AsrcbInvSgnUserData(UserDataType::Unsigned))
));
}
#[test]
fn data() {
let (ec, _) = get_test_keys();
let data_in = vec![1; UserDataType::SgnEcSECP521R1.max()];
let user_data = UserData::new(Some(ec.clone()), data_in.clone()).unwrap();
let exp_pad = Some(vec![0; UserData::USER_DATA_SIZE - data_in.len()]);
let (data_out, pad) = user_data.data();
assert_eq!(data_out, Some(data_in.as_ref()));
assert_eq!(pad, exp_pad);
let data_in = vec![1; UserDataType::SgnEcSECP521R1.max() - 1];
let user_data = UserData::new(Some(ec.clone()), data_in.clone()).unwrap();
let exp_pad = Some(vec![0; UserData::USER_DATA_SIZE - data_in.len()]);
let (data_out, pad) = user_data.data();
assert_eq!(data_out, Some(data_in.as_ref()));
assert_eq!(pad, exp_pad);
}
}

View File

@@ -2,13 +2,12 @@
//
// Copyright IBM Corp. 2023
use super::AddSecretMagic;
use crate::{
request::MagicValue,
requires_feat,
uv::{uv_ioctl, UvCmd, UvDevice},
Error, Result, PAGESIZE,
};
use pv_core::request::{uvsecret::AddSecretMagic, MagicValue};
use std::io::Read;
use std::usize;
@@ -64,7 +63,7 @@ impl AddCmd {
let mut data = Vec::with_capacity(PAGESIZE);
bin_add_secret_req.read_to_end(&mut data)?;
if !AddSecretMagic::starts_with_magic(&data[..6]) {
if !AddSecretMagic::starts_with_magic(&data) {
return Err(Error::NoAsrcb);
}
Ok(Self(data))

View File

@@ -3,12 +3,17 @@
// Copyright IBM Corp. 2023
use core::slice;
use log::debug;
use log::{debug, trace};
use openssl::error::ErrorStack;
use openssl::stack::Stack;
use openssl::x509::store::X509Store;
use openssl::x509::{CrlStatus, X509Ref, X509StoreContext, X509};
use openssl_extensions::crl::StackableX509Crl;
use openssl_extensions::crl::X509StoreContextExtension;
use openssl::x509::{CrlStatus, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, X509};
use openssl_extensions::crl::{StackableX509Crl, X509StoreContextExtension, X509StoreExtension};
#[cfg(not(test))]
use helper::download_first_crl_from_x509;
#[cfg(test)]
use test::download_first_crl_from_x509;
use crate::error::bail_hkd_verify;
use crate::misc::{read_certs, read_file};
@@ -45,6 +50,12 @@ pub struct CertVerifier {
offline: bool,
}
impl std::fmt::Debug for CertVerifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("CertVerifier")
}
}
impl HkdVerifier for CertVerifier {
/// This function verifies a host-key
/// document. To do so multiple steps are required:
@@ -76,8 +87,8 @@ impl HkdVerifier for CertVerifier {
if verified_crls.is_empty() {
bail_hkd_verify!(NoCrl);
}
for crl in &verified_crls {
match crl.get_by_cert(&hkd.to_owned()) {
for crl in verified_crls {
match crl.get_by_serial(hkd.serial_number()) {
CrlStatus::NotRevoked => (),
_ => bail_hkd_verify!(HdkRevoked),
}
@@ -88,26 +99,59 @@ impl HkdVerifier for CertVerifier {
}
impl CertVerifier {
fn quirk_crls(
ctx: &mut X509StoreContextRef,
subject: &X509NameRef,
) -> Result<Stack<StackableX509Crl>, ErrorStack> {
match ctx.crls(subject) {
Ok(ret) if !ret.is_empty() => return Ok(ret),
_ => (),
}
// Armonk/Poughkeepsie fixup
trace!("quirk_crls: Try Locality");
if let Some(locality_subject) = helper::armonk_locality_fixup(subject) {
match ctx.crls(&locality_subject) {
Ok(ret) if !ret.is_empty() => return Ok(ret),
_ => (),
}
// reorder
trace!("quirk_crls: Try Locality+Reorder");
if let Ok(locality_ordered_subject) = helper::reorder_x509_names(&locality_subject) {
match ctx.crls(&locality_ordered_subject) {
Ok(ret) if !ret.is_empty() => return Ok(ret),
_ => (),
}
}
}
// reorder unchanged loaciliy subject
trace!("quirk_crls: Try Reorder");
if let Ok(ordered_subject) = helper::reorder_x509_names(subject) {
match ctx.crls(&ordered_subject) {
Ok(ret) if !ret.is_empty() => return Ok(ret),
_ => (),
}
}
// nothing found, return empty stack
Stack::new()
}
///Download the CLRs that a HKD refers to.
pub fn hkd_crls(&self, hkd: &X509Ref) -> Result<Stack<StackableX509Crl>> {
let mut ctx = X509StoreContext::new()?;
// Unfortunately we cannot use a dedicated function here and have to use a closure (E0434)
// Otherwise, we cannot refer to self
// Search for local CRLs
let mut crls = ctx.init_opt(&self.store, None, None, |ctx| {
let subject = self.ibm_z_sign_key.subject_name();
match ctx.crls(subject) {
Ok(crls) => Ok(crls),
_ => {
// reorder the name and try again
let broken_subj = helper::reorder_x509_names(subject)?;
ctx.crls(&broken_subj).or_else(helper::stack_err_hlp)
}
}
Self::quirk_crls(ctx, subject)
})?;
if !self.offline {
// Try to download a CRL if defined in the HKD
if let Some(crl) = helper::download_first_crl_from_x509(hkd)? {
if let Some(crl) = download_first_crl_from_x509(hkd)? {
crl.into_iter().try_for_each(|c| crls.push(c.into()))?;
}
}
@@ -137,7 +181,11 @@ impl CertVerifier {
for path in cert_paths {
let mut crt = read_certs(&read_file(path, "certificate")?)?;
if !offline {
helper::download_crls_into_store(&mut store, &crt)?;
for c in &crt {
if let Some(crl) = download_first_crl_from_x509(c)? {
crl.iter().try_for_each(|c| store.add_crl(c))?;
}
}
}
untr_certs.append(&mut crt);
}

View File

@@ -3,32 +3,25 @@
// Copyright IBM Corp. 2023
use crate::error::bail_hkd_verify;
use crate::misc::{memeq, read_crls};
use crate::HkdVerifyErrorType::*;
use crate::{Error, Result};
use curl::easy::{Easy2, Handler, WriteError};
use libc::c_int;
use log::debug;
use openssl::{
asn1::{Asn1Time, Asn1TimeRef},
error::ErrorStack,
nid::Nid,
ssl::SslFiletype,
stack::{Stack, Stackable},
stack::Stack,
x509::{
store::{File, X509Lookup, X509StoreBuilder, X509StoreBuilderRef, X509StoreRef},
store::{File, X509Lookup, X509StoreBuilder, X509StoreRef},
verify::{X509VerifyFlags, X509VerifyParam},
X509Crl, X509CrlRef, X509Name, X509NameRef, X509PurposeId, X509Ref, X509StoreContext,
X509CrlRef, X509Name, X509NameRef, X509PurposeId, X509Ref, X509StoreContext,
X509StoreContextRef, X509VerifyResult, X509,
},
};
use openssl_extensions::{
akid::{AkidCheckResult, AkidExtension},
crl::X509StoreExtension,
};
use std::cmp::Ordering;
use std::time::Duration;
use std::usize;
use openssl_extensions::akid::{AkidCheckResult, AkidExtension};
use std::str::from_utf8;
use std::{cmp::Ordering, ffi::c_int, usize};
/// Minimum security level for the keys/certificates used to establish a chain of
/// trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
@@ -42,7 +35,6 @@ const SECURITY_CHAIN_MAX_LEN: c_int = 2;
/// verifies that the HKD
/// * has enough security bits
/// * is inside its validity period
/// * issuer name is the subject name of the [`sign_key`]
/// * the Authority Key ID matches the Signing Key ID of the [`sign_key`]
pub fn verify_hkd_options(hkd: &X509Ref, sign_key: &X509Ref) -> Result<()> {
let hk_pkey = hkd.public_key()?;
@@ -56,9 +48,6 @@ pub fn verify_hkd_options(hkd: &X509Ref, sign_key: &X509Ref) -> Result<()> {
// verify that the hkd is still valid
check_validity_period(hkd.not_before(), hkd.not_after())?;
// check if hkd.issuer_name == issuer.subject
check_x509_name_equal(sign_key.subject_name(), hkd.issuer_name())?;
// verify that the AKID of the hkd matches the SKID of the issuer
if let Some(akid) = hkd.akid() {
if akid.check(sign_key) != AkidCheckResult::OK {
@@ -78,9 +67,6 @@ pub fn verify_crl(crl: &X509CrlRef, issuer: &X509Ref) -> Option<()> {
return None;
}
}
check_x509_name_equal(crl.issuer_name(), issuer.subject_name()).ok()?;
match crl.verify(issuer.public_key().ok()?.as_ref()).ok()? {
true => Some(()),
false => None,
@@ -195,22 +181,12 @@ pub fn extract_ibm_sign_key(certs: Vec<X509>) -> Result<(X509, Stack<X509>)> {
Ok((ibm_z_sign_key, chain))
}
/// for all certs load the first CRL specified into our store
pub fn download_crls_into_store(store: &mut X509StoreBuilderRef, crts: &[X509]) -> Result<()> {
for crt in crts {
debug!("Download crls for {crt:?}");
if let Some(crl) = download_first_crl_from_x509(crt)? {
crl.iter().try_for_each(|c| store.add_crl(c))?;
}
}
Ok(())
}
// Name Entry values of an IBM Z key signing cert
//Asn1StringRef::as_slice aka ASN1_STRING_get0_data gives a string without \0 delimiter
const IBM_Z_COMMON_NAME: &[u8; 43usize] = b"International Business Machines Corporation";
const IBM_Z_COUNTRY_NAME: &[u8; 2usize] = b"US";
const IBM_Z_LOCALITY_NAME: &[u8; 12usize] = b"Poughkeepsie";
const IBM_Z_LOCALITY_NAME_POUGHKEEPSIE: &[u8; 12usize] = b"Poughkeepsie";
const IBM_Z_LOCALITY_NAME_ARMONK: &[u8; 6usize] = b"Armonk";
const IBM_Z_ORGANIZATIONAL_UNIT_NAME_SUFFIX: &str = "Key Signing Service";
const IBM_Z_ORGANIZATION_NAME: &[u8; 43usize] = b"International Business Machines Corporation";
const IBM_Z_STATE: &[u8; 8usize] = b"New York";
@@ -219,7 +195,7 @@ fn name_data_eq(entries: &X509NameRef, nid: Nid, rhs: &[u8]) -> bool {
let mut it = entries.entries_by_nid(nid);
match it.next() {
None => false,
Some(entry) => memeq(entry.data().as_slice(), rhs),
Some(entry) => entry.data().as_slice() == rhs,
}
}
@@ -229,7 +205,8 @@ fn is_ibm_signing_cert(cert: &X509) -> bool {
if subj.entries().count() != IMB_Z_ENTRY_COUNT
|| !name_data_eq(subj, Nid::COUNTRYNAME, IBM_Z_COUNTRY_NAME)
|| !name_data_eq(subj, Nid::STATEORPROVINCENAME, IBM_Z_STATE)
|| !name_data_eq(subj, Nid::LOCALITYNAME, IBM_Z_LOCALITY_NAME)
|| !(name_data_eq(subj, Nid::LOCALITYNAME, IBM_Z_LOCALITY_NAME_POUGHKEEPSIE)
|| name_data_eq(subj, Nid::LOCALITYNAME, IBM_Z_LOCALITY_NAME_ARMONK))
|| !name_data_eq(subj, Nid::ORGANIZATIONNAME, IBM_Z_ORGANIZATION_NAME)
|| !name_data_eq(subj, Nid::COMMONNAME, IBM_Z_COMMON_NAME)
{
@@ -322,14 +299,17 @@ pub fn x509_dist_points(cert: &X509Ref) -> Vec<String> {
res
}
const CRL_TIMEOUT_MAX: Duration = Duration::from_secs(3);
/// Searches for CRL Distribution points and downloads the CRL. Stops after the first successful
/// download.
///
/// Error if sth bad(=unexpected) happens (not bad: crl not available at link, unexpected format)
/// Other issues are mapped to Ok(None)
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<X509Crl>>> {
#[cfg(not(test))]
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<openssl::x509::X509Crl>>> {
use crate::misc::read_crls;
use curl::easy::{Easy2, Handler, WriteError};
use std::time::Duration;
const CRL_TIMEOUT_MAX: Duration = Duration::from_secs(3);
struct Buf(Vec<u8>);
impl Handler for Buf {
@@ -370,23 +350,6 @@ fn check_validity_period(not_before: &Asn1TimeRef, not_after: &Asn1TimeRef) -> R
}
}
fn check_x509_name_equal(lhs: &X509NameRef, rhs: &X509NameRef) -> Result<()> {
if lhs.entries().count() != rhs.entries().count() {
bail_hkd_verify!(IssuerMismatch);
}
for l in lhs.entries() {
let ldata = l.data().as_slice();
// search for the matching value in the rhs names
// found none? -> names are not equal
if !rhs.entries().any(|r| memeq(ldata, r.data().as_slice())) {
bail_hkd_verify!(IssuerMismatch);
}
}
Ok(())
}
const NIDS_CORRECT_ORDER: [Nid; 6] = [
Nid::COUNTRYNAME,
Nid::ORGANIZATIONNAME,
@@ -409,21 +372,34 @@ pub fn reorder_x509_names(subject: &X509NameRef) -> std::result::Result<X509Name
Ok(correct_subj.build())
}
pub fn stack_err_hlp<T: Stackable>(
e: ErrorStack,
) -> std::result::Result<Stack<T>, openssl::error::ErrorStack> {
match e.errors().len() {
0 => Stack::<T>::new(),
_ => Err(e),
/**
* Workaround for potential locality mismatches between CRLs and Certs
* # Return
* fixed subject or none if locality was not Armonk or any OpenSSL error
*/
pub fn armonk_locality_fixup(subject: &X509NameRef) -> Option<X509Name> {
if !name_data_eq(subject, Nid::LOCALITYNAME, IBM_Z_LOCALITY_NAME_ARMONK) {
return None;
}
let mut ret = X509Name::builder().ok()?;
for entry in subject.entries() {
match entry.object().nid() {
nid @ Nid::LOCALITYNAME => ret
.append_entry_by_nid(nid, from_utf8(IBM_Z_LOCALITY_NAME_POUGHKEEPSIE).ok()?)
.ok()?,
_ => {
ret.append_entry(entry).ok()?;
}
}
}
Some(ret.build())
}
#[cfg(test)]
/// tests for some private functions
mod test {
use openssl_extensions::x509_crl_eq;
use super::*;
use crate::test_utils::*;
use std::time::{Duration, SystemTime};
@@ -453,20 +429,6 @@ mod test {
));
}
#[test]
fn x509_name_equal() {
let sign_crt = load_gen_cert("ibm.crt");
let hkd = load_gen_cert("host.crt");
let other = load_gen_cert("inter_ca.crt");
assert!(super::check_x509_name_equal(sign_crt.subject_name(), hkd.issuer_name()).is_ok(),);
assert!(matches!(
super::check_x509_name_equal(other.subject_name(), hkd.subject_name()),
Err(Error::HkdVerify(IssuerMismatch))
));
}
#[test]
fn is_ibm_z_sign_key() {
let ibm_crt = load_gen_cert("ibm.crt");
@@ -484,35 +446,19 @@ mod test {
let ibm_wrong_subj = load_gen_cert("ibm_wrong_subject.crt");
let no_sign_crt = load_gen_cert("inter_ca.crt");
assert!(super::get_ibm_z_sign_key(&vec!(ibm_crt.clone())).is_ok());
assert!(super::get_ibm_z_sign_key(&[ibm_crt.clone()]).is_ok());
assert!(matches!(
super::get_ibm_z_sign_key(&vec!(ibm_crt.clone(), ibm_crt.clone())),
super::get_ibm_z_sign_key(&[ibm_crt.clone(), ibm_crt.clone()]),
Err(Error::HkdVerify(ManyIbmSignKeys))
));
assert!(matches!(
super::get_ibm_z_sign_key(&vec!(ibm_wrong_subj)),
super::get_ibm_z_sign_key(&[ibm_wrong_subj]),
Err(Error::HkdVerify(NoIbmSignKey))
));
assert!(matches!(
super::get_ibm_z_sign_key(&vec!(no_sign_crt.clone())),
super::get_ibm_z_sign_key(&[no_sign_crt.clone()]),
Err(Error::HkdVerify(NoIbmSignKey))
));
assert!(super::get_ibm_z_sign_key(&vec!(ibm_crt.clone(), no_sign_crt.clone())).is_ok(),);
}
#[test]
fn download_first_crl_from_x509() {
let ibm_crt = load_gen_cert("ibm.crt");
let inter_crl = load_gen_crl("inter_ca.crl");
let _m_inter = super::super::test::mock_endpt("inter_ca.crl");
let crl_d = super::download_first_crl_from_x509(&ibm_crt)
.unwrap()
.unwrap();
assert_eq!(crl_d.len(), 1);
assert!(x509_crl_eq(
crl_d.first().unwrap().as_ref(),
inter_crl.as_ref()
));
assert!(super::get_ibm_z_sign_key(&[ibm_crt, no_sign_crt]).is_ok(),);
}
}

View File

@@ -5,45 +5,30 @@
#![cfg(test)]
use super::{helper, helper::*, *};
use crate::{Error, HkdVerifyErrorType::*};
use core::slice;
use openssl::stack::Stack;
use crate::{misc::read_crls, Error, HkdVerifyErrorType::*};
use openssl::{stack::Stack, x509::X509Crl};
use std::path::Path;
use crate::test_utils::*;
pub fn mock_endpt(res: &str) -> mockito::Mock {
let res_path = get_cert_asset_path(res);
mockito::mock("GET", format!("/crl/{res}").as_str())
.with_header("content-type", "application/pkix-crl")
.with_body_from_file(res_path)
.create()
}
#[track_caller]
fn verify_sign_error(exp_raw: libc::c_int, obs: Error) {
verify_sign_error_slice(&[exp_raw], obs)
}
fn verify_sign_error_slice(exp_raw: &[libc::c_int], obs: Error) {
if exp_raw
.into_iter()
.filter(|e| match &obs {
Error::HkdVerify(ty) => match ty {
IbmSignInvalid(err, _d) => &&err.as_raw() == e,
_ => false,
},
e => panic!("Unexpected error type: {e:?}"),
})
.count()
== 0
{
panic!("Error {obs:?} did not match one of the expected {exp_raw:?}");
//mock function
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<X509Crl>>> {
fn mock_download<P: AsRef<Path>>(path: P) -> Result<Vec<X509Crl>> {
read_crls(&std::fs::read(path)?)
}
}
impl std::fmt::Debug for CertVerifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("CertVerifier")
for dist_point in x509_dist_points(cert) {
{
let path = get_cert_asset_path(&dist_point);
let crls = if let Ok(buf) = mock_download(&path) {
buf
} else {
continue;
};
return Ok(Some(crls));
}
}
Ok(None)
}
#[test]
@@ -51,28 +36,18 @@ fn store_setup() {
let ibm_str = get_cert_asset_path_string("ibm.crt");
let inter_str = get_cert_asset_path_string("inter.crt");
let store = helper::store_setup(&None, &vec![], &vec![ibm_str, inter_str]);
let store = helper::store_setup(&None, &[], &[ibm_str, inter_str]);
assert!(store.is_ok());
}
#[test]
fn verify_chain_online() {
let ibm_crt = load_gen_cert("ibm.crt");
let inter_crt = load_gen_cert("inter_ca.crt");
let ibm_crt = get_cert_asset_path_string("ibm.crt");
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
let mock_inter = mock_endpt("inter_ca.crl");
let mut store = helper::store_setup(&Some(root_crt), &vec![], &vec![]).unwrap();
download_crls_into_store(&mut store, slice::from_ref(&ibm_crt)).unwrap();
let store = store.build();
mock_inter.assert();
let mut sk = Stack::<X509>::new().unwrap();
sk.push(inter_crt).unwrap();
verify_chain(&store, &sk, &vec![ibm_crt.clone()]).unwrap();
assert!(verify_chain(&store, &sk, &vec!(ibm_crt)).is_ok());
let ret = CertVerifier::new(&[ibm_crt, inter_crt], &[], &root_crt.into(), false);
assert!(ret.is_ok(), "CertVerifier::new failed: {ret:?}");
}
#[test]
@@ -82,201 +57,92 @@ fn verify_chain_offline() {
let inter_crt = load_gen_cert("inter_ca.crt");
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
let store = helper::store_setup(&Some(root_crt), &vec![inter_crl], &vec![])
let store = helper::store_setup(&Some(root_crt), &[inter_crl], &[])
.unwrap()
.build();
let mut sk = Stack::<X509>::new().unwrap();
sk.push(inter_crt).unwrap();
assert!(verify_chain(&store, &sk, &vec![ibm_crt]).is_ok());
}
#[test]
fn verify_online() {
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
let ibm_crt = get_cert_asset_path_string("ibm.crt");
let hkd_revoked = load_gen_cert("host_rev.crt");
let hkd_inv = load_gen_cert("host_invalid_signing_key.crt");
let hkd_exp = load_gen_cert("host_crt_expired.crt");
let hkd = load_gen_cert("host.crt");
let mock_inter = mock_endpt("inter_ca.crl");
let mock_ibm = mock_endpt("ibm.crl");
let inter_crl = get_cert_asset_path_string("inter_ca.crl");
let ibm_crl = get_cert_asset_path_string("ibm.crl");
let verifier = CertVerifier::new(
&vec![ibm_crt, inter_crt],
&vec![ibm_crl, inter_crl],
&Some(root_crt),
false,
)
.unwrap();
mock_inter.assert();
verifier.verify(&hkd).unwrap();
mock_ibm.assert();
assert!(matches!(
verifier.verify(&hkd_revoked),
Err(Error::HkdVerify(HdkRevoked))
));
assert!(matches!(
verifier.verify(&hkd_inv),
Err(Error::HkdVerify(IssuerMismatch))
));
assert!(matches!(
verifier.verify(&hkd_exp),
Err(Error::HkdVerify(AfterValidity))
));
}
#[test]
fn verify_offline() {
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
let inter_crl = get_cert_asset_path_string("inter_ca.crl");
let ibm_crt = get_cert_asset_path_string("ibm.crt");
let ibm_crl = get_cert_asset_path_string("ibm.crl");
let hkd_revoked = load_gen_cert("host_rev.crt");
let hkd_inv = load_gen_cert("host_invalid_signing_key.crt");
let hkd_exp = load_gen_cert("host_crt_expired.crt");
let hkd = load_gen_cert("host.crt");
let verifier = CertVerifier::new(
&vec![ibm_crt, inter_crt],
&vec![ibm_crl, inter_crl],
&Some(root_crt),
true,
)
.unwrap();
verifier.verify(&hkd).unwrap();
assert!(matches!(
verifier.verify(&hkd_revoked),
Err(Error::HkdVerify(HdkRevoked))
));
assert!(matches!(
verifier.verify(&hkd_inv),
Err(Error::HkdVerify(IssuerMismatch))
));
assert!(matches!(
verifier.verify(&hkd_exp),
Err(Error::HkdVerify(AfterValidity))
));
}
#[test]
fn verifier_new() {
let root_chn_crt = get_cert_asset_path_string("root_ca.chained.crt");
let root_crt = get_cert_asset_path_string("root_ca.crt");
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
let inter_fake_crt = get_cert_asset_path_string("fake_inter_ca.crt");
let inter_fake_crl = get_cert_asset_path_string("fake_inter_ca.crl");
let inter_crl = get_cert_asset_path_string("inter_ca.crl");
let ibm_crt = get_cert_asset_path_string("ibm.crt");
let ibm_early_crt = get_cert_asset_path_string("ibm_outdated_early.crl");
let ibm_late_crt = get_cert_asset_path_string("ibm_outdated_late.crl");
let ibm_rev_crt = get_cert_asset_path_string("ibm_rev.crt");
// To many signing keys
let verifier = CertVerifier::new(
&vec![ibm_crt.clone(), ibm_rev_crt.clone()],
&vec![],
&None,
true,
);
assert!(matches!(verifier, Err(Error::HkdVerify(ManyIbmSignKeys))));
// no CRL for each X509
let verifier = CertVerifier::new(
&vec![inter_crt.clone(), ibm_crt.clone()],
&vec![inter_crl.clone()],
&Some(root_crt.clone()),
false,
);
verify_sign_error(3, verifier.unwrap_err());
let verifier = CertVerifier::new(
&vec![inter_crt.clone(), ibm_crt.clone()],
&vec![],
&Some(root_chn_crt.clone()),
false,
);
verify_sign_error(3, verifier.unwrap_err());
// wrong intermediate (or ibm key)
let verifier = CertVerifier::new(
&vec![inter_fake_crt, ibm_crt.clone()],
&vec![inter_fake_crl],
&Some(root_chn_crt.clone()),
true,
);
//Depending on the OpenSSL version different error codes can appear
verify_sign_error_slice(&[20, 30], verifier.unwrap_err());
//wrong root ca
let verifier = CertVerifier::new(
&vec![inter_crt.clone(), ibm_crt.clone()],
&vec![inter_crl.clone()],
&None,
true,
);
verify_sign_error(20, verifier.unwrap_err());
//correct signing key + intermediate cert
let _verifier = CertVerifier::new(
&vec![inter_crt.clone(), ibm_crt.clone()],
&vec![inter_crl.clone()],
&Some(root_chn_crt.clone()),
false,
)
.unwrap();
// no intermediate key
let verifier = CertVerifier::new(
&vec![ibm_crt.clone()],
&vec![],
&Some(root_chn_crt.clone()),
false,
);
verify_sign_error(20, verifier.unwrap_err());
//Ibm Sign outdated
let verifier = CertVerifier::new(
&vec![inter_crt.clone(), ibm_early_crt.clone()],
&vec![inter_crl.clone()],
&Some(root_chn_crt.clone()),
false,
);
assert!(matches!(verifier, Err(Error::HkdVerify(NoIbmSignKey))));
let verifier = CertVerifier::new(
&vec![inter_crt.clone(), ibm_late_crt.clone()],
&vec![inter_crl.clone()],
&Some(root_chn_crt.clone()),
false,
);
assert!(matches!(verifier, Err(Error::HkdVerify(NoIbmSignKey))));
// revoked
let verifier = CertVerifier::new(
&vec![inter_crt.clone(), ibm_rev_crt.clone()],
&vec![inter_crl.clone()],
&Some(root_chn_crt.clone()),
false,
);
verify_sign_error(23, verifier.unwrap_err());
assert!(verify_chain(&store, &sk, &[ibm_crt]).is_ok());
}
#[test]
fn dist_points() {
let crt = load_gen_cert("ibm.crt");
let res = x509_dist_points(&crt);
let exp = vec!["http://127.0.0.1:1234/crl/inter_ca.crl"];
let exp = vec!["inter_ca.crl"];
assert_eq!(res, exp);
}
fn verify(offline: bool, ibm_crt: &'static str, ibm_crl: &'static str, hkd: &'static str) {
let root_crt = get_cert_asset_path_string("root_ca.chained.crt");
let inter_crt = get_cert_asset_path_string("inter_ca.crt");
let inter_crl = get_cert_asset_path_string("inter_ca.crl");
let ibm_crt = get_cert_asset_path_string(ibm_crt);
let ibm_crl = get_cert_asset_path_string(ibm_crl);
let hkd_revoked = load_gen_cert("host_rev.crt");
let hkd_exp = load_gen_cert("host_crt_expired.crt");
let hkd = load_gen_cert(hkd);
let crls = &[ibm_crl, inter_crl];
let verifier = CertVerifier::new(
&[ibm_crt, inter_crt],
if offline { crls } else { &[] },
&Some(root_crt),
offline,
)
.unwrap();
let res = verifier.verify(&hkd);
assert!(res.is_ok(), "Verify failed: res: {res:?}");
assert!(matches!(
verifier.verify(&hkd_revoked),
Err(Error::HkdVerify(HdkRevoked))
));
assert!(matches!(
verifier.verify(&hkd_exp),
Err(Error::HkdVerify(AfterValidity))
));
}
#[test]
fn verify_online() {
verify(false, "ibm.crt", "ibm.crl", "host.crt")
}
#[test]
fn verify_offline() {
verify(true, "ibm.crt", "ibm.crl", "host.crt")
}
#[test]
fn verify_armonk_crt_online() {
verify(false, "ibm_armonk.crt", "ibm.crl", "host.crt")
}
#[test]
fn verify_armonk_crt_offline() {
verify(true, "ibm_armonk.crt", "ibm.crl", "host.crt")
}
#[test]
fn verify_armonk_crl_online() {
verify(false, "ibm_armonk.crt", "ibm_armonk.crl", "host.crt")
}
#[test]
fn verify_armonk_crl_offline() {
verify(true, "ibm_armonk.crt", "ibm_armonk.crl", "host.crt")
}
#[test]
fn verify_armonk_hkd_online() {
verify(false, "ibm_armonk.crt", "ibm_armonk.crl", "host_armonk.crt")
}
#[test]
fn verify_armonk_hkd_offline() {
verify(true, "ibm_armonk.crt", "ibm_armonk.crl", "host_armonk.crt")
}

View File

@@ -1,13 +1,19 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp. 2023
#![cfg(all(feature = "request", feature = "uvsecret"))]
use openssl::{
ec::{EcGroup, EcKey},
nid::Nid,
pkey::Private,
};
use pv::{
get_test_asset,
request::{
openssl::pkey::{PKey, Public},
uvsecret::{AddSecretFlags, AddSecretRequest, AddSecretVersion, ExtSecret, GuestSecret},
uvsecret::{
verify_asrcb_and_get_user_data, AddSecretFlags, AddSecretRequest, AddSecretVersion,
ExtSecret, GuestSecret,
},
BootHdrTags, ReqEncrCtx, Request, SymKey,
},
test_utils::get_test_keys,
@@ -18,7 +24,7 @@ use pv::{
const TAGS: BootHdrTags = BootHdrTags::new([1; 64], [2; 64], [3; 64], [4; 16]);
const CUID: ConfigUid = [0x42u8; 16];
const ASSOC_SECRET: [u8; 32] = [0x11; 32];
const ASSOC_ID: &'static str = "add_secret_request";
const ASSOC_ID: &str = "add_secret_request";
fn create_asrcb(
guest_secret: GuestSecret,
@@ -38,7 +44,7 @@ fn create_asrcb(
};
asrcb.add_hostkey(hkd);
Ok(asrcb.encrypt(ctx)?)
asrcb.encrypt(ctx)
}
fn get_crypto() -> (PKey<Public>, ReqEncrCtx) {
@@ -63,17 +69,10 @@ where
{
let (host_key, ctx) = get_crypto();
let cuid = match cuid {
true => Some(CUID.into()),
true => Some(CUID),
false => None,
};
create_asrcb(
guest_secret,
ext_secret.into(),
flags,
cuid.into(),
host_key,
&ctx,
)
create_asrcb(guest_secret, ext_secret.into(), flags, cuid, host_key, &ctx)
}
fn association() -> GuestSecret {
@@ -92,6 +91,93 @@ fn no_flag() -> AddSecretFlags {
AddSecretFlags::default()
}
fn create_signed_asrcb(skey: PKey<Private>, user_data: Vec<u8>) -> Vec<u8> {
let (host_key, ctx) = get_crypto();
let mut asrcb =
AddSecretRequest::new(AddSecretVersion::One, GuestSecret::Null, TAGS, no_flag());
asrcb.add_hostkey(host_key);
asrcb.set_user_data(user_data, Some(skey)).unwrap();
asrcb.encrypt(&ctx).unwrap()
}
#[test]
fn null_none_default_ncuid_one_user_unsgn() {
let user_data_orig = vec![0x56; 0x183];
let (host_key, ctx) = get_crypto();
let mut asrcb =
AddSecretRequest::new(AddSecretVersion::One, GuestSecret::Null, TAGS, no_flag());
asrcb.add_hostkey(host_key);
asrcb.set_user_data(user_data_orig.clone(), None).unwrap();
let asrcb = asrcb.encrypt(&ctx).unwrap();
let user_data = verify_asrcb_and_get_user_data(asrcb, None).unwrap();
assert_eq!(
user_data_orig.as_slice(),
&user_data.as_ref().unwrap()[..user_data_orig.len()]
);
}
#[test]
fn null_none_default_ncuid_one_user_ec() {
let (usr_sgn_key, _) = get_test_keys();
let usr_vrfy_key = usr_sgn_key.ec_key().unwrap();
let usr_vrfy_key = usr_vrfy_key.public_key();
let usr_vrfy_key = PKey::from_ec_key(
EcKey::from_public_key(
&EcGroup::from_curve_name(Nid::SECP521R1).unwrap(),
usr_vrfy_key,
)
.unwrap(),
)
.unwrap();
let user_data_orig = vec![0x56; 0x100];
let asrcb = create_signed_asrcb(usr_sgn_key, user_data_orig.clone());
let user_data = verify_asrcb_and_get_user_data(asrcb, Some(usr_vrfy_key)).unwrap();
assert_eq!(
user_data_orig.as_slice(),
&user_data.as_ref().unwrap()[..user_data_orig.len()]
);
}
#[test]
fn null_none_default_ncuid_one_user_rsa2048() {
let usr_sgn_key = get_test_asset!("keys/rsa2048key.pem");
let usr_sgn_key = PKey::private_key_from_pem(usr_sgn_key).unwrap();
let user_data_orig = vec![0x56; 0x100];
let asrcb = create_signed_asrcb(usr_sgn_key, user_data_orig.clone());
let usr_vrfy_key = get_test_asset!("keys/rsa2048key.pub.pem");
let usr_vrfy_key = PKey::public_key_from_pem(usr_vrfy_key).unwrap();
let user_data = verify_asrcb_and_get_user_data(asrcb, Some(usr_vrfy_key)).unwrap();
assert_eq!(
user_data_orig.as_slice(),
&user_data.as_ref().unwrap()[..user_data_orig.len()]
);
}
#[test]
fn null_none_default_ncuid_one_user_rsa3072() {
let usr_sgn_key = get_test_asset!("keys/rsa3072key.pem");
let usr_sgn_key = PKey::private_key_from_pem(usr_sgn_key).unwrap();
let user_data_orig = vec![0x56; 0x80];
let asrcb = create_signed_asrcb(usr_sgn_key, user_data_orig.clone());
let usr_vrfy_key = get_test_asset!("keys/rsa3072key.pub.pem");
let usr_vrfy_key = PKey::public_key_from_pem(usr_vrfy_key).unwrap();
let user_data = verify_asrcb_and_get_user_data(asrcb, Some(usr_vrfy_key)).unwrap();
assert_eq!(
user_data_orig.as_slice(),
&user_data.as_ref().unwrap()[..user_data_orig.len()]
);
}
#[test]
fn null_none_default_cuid_one() {
let asrcb = gen_asrcb(GuestSecret::Null, None, no_flag(), true).unwrap();
@@ -156,9 +242,18 @@ fn null_none_default_cuid_seven() {
let mut asrcb =
AddSecretRequest::new(AddSecretVersion::One, GuestSecret::Null, TAGS, no_flag());
(0..7).for_each(|_| asrcb.add_hostkey(hkd.clone()));
asrcb.set_cuid(CUID.into());
asrcb.set_cuid(CUID);
let asrcb = asrcb.encrypt(&ctx).unwrap();
let exp = get_test_asset!("exp/asrcb/null_none_default_cuid_seven");
assert_eq!(asrcb, exp);
}
#[test]
fn verify_no_user_data() {
let req = get_test_asset!("exp/asrcb/null_none_default_ncuid_one");
assert!(matches!(
verify_asrcb_and_get_user_data(req.to_vec(), None),
Ok(None)
))
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIE/TCCAuWgAwIBAgIUWT/F3gP9fOTTq3yOMVskcXM8vOAwDQYJKoZIhvcNAQEN
BQAwgcwxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
azEVMBMGA1UEBwwMUG91Z2hrZWVwc2llMScwJQYDVQQLDB5JQk0gWiBIb3N0IEtl
eSBTaWduaW5nIFNlcnZpY2UwIBcNMjQwMzIxMTQ1MjM5WhgPMjM4ODEyMjMxNDUy
MzlaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp
bmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrSW50ZXJuYXRpb25h
bCBCdXNpbmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjERMA8GA1UECAwITmV3IFlv
cmsxDzANBgNVBAcMBkFybW9uazEXMBUGA1UECwwOSUJNIFogSG9zdCBLZXkwgZsw
EAYHKoZIzj0CAQYFK4EEACMDgYYABAAT1zpBNemPCT0tEx2S9qnlPxyBgxKl6BSX
ghqf3MfOqQKIUdKEbxP0nr2QtIR/MwvBp4YhjxZ9AZtzVtXbQrULTAGlKK4qcf1I
W1rYZ5S0b4dmvh2HbIv9wZLWKaZ/ovnvAJk949WDCbBzC3Dy1E3zCaYPefLHHNve
dWX8RtFUhnTqm6NxMG8wHQYDVR0fBBYwFDASoBCgDoYMZmFrZV9pYm0uY3J0MA4G
A1UdDwEB/wQEAwIDCDAfBgNVHSMEGDAWgBSQCOxEmGwiupA2ER7srMBydGO1aTAd
BgNVHQ4EFgQUUl5SPIEseFNeneyuOidsw06L7gQwDQYJKoZIhvcNAQENBQADggIB
AFAg/hFlaBT+WNlUmVJlAd6FYr6vvRjJiKxcNBZ5wElzxA5OjuGX6pLYiNkzXSy2
N/4nQ3a8fr04IB9Uhx5ncMzSKVkG+4mbN3xmR7f6zZuFWV/T9Aom3LIbQ5KYR2wW
EvX8b2xbvd74rKAgavq/iuFRn8skQJGgQk9J2YEApOW9wkoFQRgziuu55Cw5GT+f
w9rKgAFTN33ZwfWs86ELJlDOY0aX5373WGccuEKm8y+l2UVLlly125eezz84RSh7
5j0VUTjK4ZqpSD8yiPxN+vocV+nY52cgWxrVf7g7wlPunxXWX4rxR0z/mEVDDBAC
y7cAxsa4HtmJexuZbjEh8TEgDZXDA24BuFXqtkwqnUpv8KghyKb0KgTQecP9rRhL
b2iHdQrALnddMzJzp7Tn+jsR2A2G0lLLsIuIRFR/1eAxecgTMoxXV8N0SJHn6emH
Uwif1Qr5JVw4UOFSLW3MT3f70hY5hMzrxowOapcYhyR0vbhGFrF1YI8YmAuk2m4P
Dfd5Za5cnfVJiAdNBnNPtV/5wiViX1VJGCrIxgDN6B2VE0VQLp2gKwpsSmhqN4CA
qHzAi3Yj3F8vQ2mWQeuABWLAJrIoxXpVYQvTf4uij0ARZRbajQXx+LZnAUsCi5eZ
LaYrTVn8NzHlGQocUWljG06GaLY8GNqKPQrZD/+6hIYK
-----END CERTIFICATE-----

View File

@@ -0,0 +1,8 @@
-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAXR6FCIgd+fjhO/WJ
KwLTP01mBDtYkWbVE71jshjLLpZHunRpsYKbQKCwaDmMYLRrQnTxPgZH1PVKzguI
7M7n9zyhgYkDgYYABAAT1zpBNemPCT0tEx2S9qnlPxyBgxKl6BSXghqf3MfOqQKI
UdKEbxP0nr2QtIR/MwvBp4YhjxZ9AZtzVtXbQrULTAGlKK4qcf1IW1rYZ5S0b4dm
vh2HbIv9wZLWKaZ/ovnvAJk949WDCbBzC3Dy1E3zCaYPefLHHNvedWX8RtFUhnTq
mw==
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,20 @@
-----BEGIN X509 CRL-----
MIIDVTCCAT0CAQEwDQYJKoZIhvcNAQENBQAwgcwxCzAJBgNVBAYTAlVTMTQwMgYD
VQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9u
MTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBv
cmF0aW9uMREwDwYDVQQIDAhOZXcgWW9yazEVMBMGA1UEBwwMUG91Z2hrZWVwc2ll
MScwJQYDVQQLDB5JQk0gWiBIb3N0IEtleSBTaWduaW5nIFNlcnZpY2UXDTI0MDMx
MTE1NTIzOVoYDzIzODgxMjIzMTU1MjM5WjAVMBMCAgIrFw0yNDAzMjAxNTUyMzla
oCMwITAfBgNVHSMEGDAWgBSQCOxEmGwiupA2ER7srMBydGO1aTANBgkqhkiG9w0B
AQ0FAAOCAgEAsRE3oW/VAx2JPESuWDZVbKIX9n26BZUZ2mdmUocRmn7KQ6CAi0Ac
L5YRUvYt7kmGo6BSA6rUa0TMoMBtFzfIJ6HQZzEoA/LOkIKMfNHsFFzpIJxghPYJ
PfPkXoLpAOBcLDrYWr1bJ3mkvrd6Tuyx02wJEhVmTcF8W/18AFRPuEVg/u3vJmeQ
yMdwQZG42kEslvhCTO688vozYeX+dXO1/AXamzYQZyEWk2cBQ28DIc5eg39Tq77N
89xqWNK/FWKkF4USn9psiBJQpKEjq+P1jTgdpuN3IGv618hlxS455eGyJrbiTxjD
osWGShI+ZVznnqw98aX558hnNWHic+5JVvdJAwNaMMuNNkApFdz328z9dPtcUAZT
7mNcKAuY1NcqdxKTPwkGWfmZm+WndGwKLwpshBhF/ImiAb/UiDrLh0jGbQ/FDE3j
DtWs4k8eXIibtzGhgjfewdXO66jw5Z55FajcOPgja3uw2g2KEhJ+/VP1YtCvCpkm
NX0liKgKLzUGDCbzyrH7QD16T633ebLbak3CtNMMlxZRQO8DQDbDsEKybCG62f/w
OmM+QmL7lRFcXDbtVNxBSQKaDBDlNaEGEjM8phz166g+UMD7M6xJjmwJx/G/QvUd
98YQfMEIt8IlrIbIfHXnAlj4SJwWNfOw+SN0dCqD5CDEYzYVtZgrNXY=
-----END X509 CRL-----

View File

@@ -0,0 +1,38 @@
-----BEGIN CERTIFICATE-----
MIIGrTCCBJWgAwIBAgIUMCRfNPXX7mCzJea1P3mCUDqZdB0wDQYJKoZIhvcNAQEL
BQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI0
MDMyMTE0NTIzOVoYDzIzODgxMjIzMTQ1MjM5WjCBzDELMAkGA1UEBhMCVVMxNDAy
BgNVBAoMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29ycG9yYXRp
b24xNDAyBgNVBAMMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29y
cG9yYXRpb24xETAPBgNVBAgMCE5ldyBZb3JrMRUwEwYDVQQHDAxQb3VnaGtlZXBz
aWUxJzAlBgNVBAsMHklCTSBaIEhvc3QgS2V5IFNpZ25pbmcgU2VydmljZTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALIvcLAKt2DM5rTc1nOhyVT2EbNy
CA1Sy+l1mSloBRVqjyk464mvlqq9p/CDO1e6tWiFhdEFChuTYzzDOxHazLjPc2Y5
U+r0QYYY8KK6jLQDj4crChPMJoJ0HZbmlWe/3uMl7lmrVMyHgqqOftQ52etBCGDn
d/RV7U4OC+MJ01ePYUcABxPh3APA+DDV5eZ2b1k74JzLvXa+SGA82MPDQYc70Waf
CcsfCw04Adnc968CEUbNQYxdfXZfL0Uvi44bohuaB5b07KY4cCetdMaBIuowgVsa
d3Zo3pI/vaj8nlAIVmYNbG4aVmItG2q+3K8Zt11A1WXMCfVBfzg4aHAmEPJzVD+s
u0maCTrRwRfKudHU+FFI36x4aqauNj0jAoQtuACYLS+69z6G0MKHd50jQXYiGwKP
LaTI+mWJ2+GBPMZpRFKyFlAXTFBFCIpZopAdfhgCMkbb212cARGD9N55xjx0F5u5
kuXWhyF/0Zq7IdXdBlR9/0uc2I0z2P2RpQ1x1TExjqZoEt6WrpYuWPHtKqeLV1zu
PonIPZFsKXJDtxoJhvhk/Aivv0329faKxqtIlH1W7b2BrrkC1UYh4+w9f/CVG2tD
FRkXDEdgyknFsGarHSIGtrIr4vRGAh2p6a+7lNnb9GgpGshFIaOnXf1SXFLgdBwb
mEPx8pjT7Fnu01HxAgMBAAGjgZkwgZYwIQYDVR0fBBowGDAWoBSgEoYQZmFrZV9y
b290X2NhLmNybDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUE
DDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBQsIzqwsaKXaQyBeov7u8c7q8IEdzAd
BgNVHQ4EFgQUkAjsRJhsIrqQNhEe7KzAcnRjtWkwDQYJKoZIhvcNAQELBQADggIB
AL+JmoykUGjMygjv23qdStop7VI2ekieYBKJANlq1eEoICLW0yIw9B57pxR6iFpS
ClulV5vU4GvXlOAP7mTJJQWeuU5Z+sn9s+nLMkwZQj6QBpYwVru3SWx7H4XojRkk
bVhN7hTrfXfQAkTLuol9PHNrGiTNGKRultBg6votpMSyd2wWgli7nt0QUydhquEL
2kROaUlHRLo9cKttyy6MIypWlneGx9KC3X/UMoZgxCygpCDQycIp1oU53ZlHO4AZ
7WeJ/FjEM2PIy6EiBnhrfmRimDjghPM8c8OIMx7fVjc5yS7KnryZ8HuzIeO6CPL+
/9+bJASuSAHmAZN3qKmiVUVfYhcbU+hKuCS2HRNkRhE/fZidp3K02OqSiRegiPRC
TIcIXJ/SZ8M345yjGekAJ/M7RGIoirbdLYmpOpvHDg0qMlKFsCdpqasivPFjtLpX
M1hvu9Ahz2HteKhm7WV9tOQ2lzMdqFDNTbxhhGzy7NJf+20zooTZCDwlNlo5JmKl
Bg/Tns0rE5ZN2j5iVvv32Bp5CrY8oy8Xq8NJitaEb4JQKSLIya++rot+OTnX7inc
LzsAwru4YgT+jGnHxEQslPcLMjuLdgZZGyXlKit+8KyslwaAb5Yv5e2rP90gYFFG
5ZxgKxI1NfJZXgPXjrnDv/FPJZe+agqlTJ0RYCJeSmCu
-----END CERTIFICATE-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCyL3CwCrdgzOa0
3NZzoclU9hGzcggNUsvpdZkpaAUVao8pOOuJr5aqvafwgztXurVohYXRBQobk2M8
wzsR2sy4z3NmOVPq9EGGGPCiuoy0A4+HKwoTzCaCdB2W5pVnv97jJe5Zq1TMh4Kq
jn7UOdnrQQhg53f0Ve1ODgvjCdNXj2FHAAcT4dwDwPgw1eXmdm9ZO+Ccy712vkhg
PNjDw0GHO9FmnwnLHwsNOAHZ3PevAhFGzUGMXX12Xy9FL4uOG6IbmgeW9OymOHAn
rXTGgSLqMIFbGnd2aN6SP72o/J5QCFZmDWxuGlZiLRtqvtyvGbddQNVlzAn1QX84
OGhwJhDyc1Q/rLtJmgk60cEXyrnR1PhRSN+seGqmrjY9IwKELbgAmC0vuvc+htDC
h3edI0F2IhsCjy2kyPplidvhgTzGaURSshZQF0xQRQiKWaKQHX4YAjJG29tdnAER
g/TeecY8dBebuZLl1ochf9GauyHV3QZUff9LnNiNM9j9kaUNcdUxMY6maBLelq6W
Lljx7Sqni1dc7j6JyD2RbClyQ7caCYb4ZPwIr79N9vX2isarSJR9Vu29ga65AtVG
IePsPX/wlRtrQxUZFwxHYMpJxbBmqx0iBrayK+L0RgIdqemvu5TZ2/RoKRrIRSGj
p139UlxS4HQcG5hD8fKY0+xZ7tNR8QIDAQABAoICAA3bS5edFbqk5JIPFGxEmhwN
0L2UMhUbKblbiFAkgzSxpzVs9EAuU/iuLAezpONDJUVeENR64FjZot+ATTErwzzi
ARbjgWelnAzaFqiI+lUra7d2vN9iQmJltkFcaCT70lD2y6zUepE3Po2V7D4Dy7MU
SRsEFRt+rSgjRoBe7L0D7OwxD9vXdh0ingpqL+k2r50QX3zCCVdZH9bAFJlQr2Fd
YQDqgD/4B4t9HgO7v9Uvw3kukBji0lVovIvUUTV5Z6de2JVAMcERZYNoZUrkkvsE
T6LukXi3WgukglLIZmVR6KoiBBsh2DLlUBsCgbXqOYy6dH3omqOkdsi/9js2cp3O
6waEBmtrH4qmOzXOnmdchg5zNs5eKVwpsrMc04sS74Xr/CWlUPlMsbL4lV3sdAsW
jL/iJO/3VSUwPHPfIbQgt7AJrkP31ESDSGNN5ac4er/ltcmB1r2MI5kuPgWL2psh
ILNFViwarwzPFHLJyiAYSW44p7kzvltoPyOfNyO5ekgeJKuYUfZiNyKYRwrStO4X
FsukIbYLnPa3ZIb3C0RVBx+lTUU+eyGd/rt/rWFA3Lnvbx4r3FdcYj2DnRM1ukgK
1QnmqUbWpRQ2wFZsdOPtMva2AUOurzv7Fze83ZyaijAmLnphnpUjqPbj2RYVWzwv
R7FUHThkc+uzcWhcOnVbAoIBAQDXRKxscm8eurBSQwPx64Td7tmPqvkzANFG9Flv
GC1FnwP/UpKXkEQe2cMu4hvVAnS3awVAfPkRvyPZDJbL5jjvDdLtXbCtbnZEEriI
TqT2UU0cnRxUybVesU+cT95PAWiEEvxFTHxOlv2rtKx0fZrd/ft530V3U7UeH7fk
lZbpEGqmbZn3hGt2UNAXItwi6FT1OjGmOXfBVZUOUSOTDeEX8Dtx+H81ReXTRslA
QXRruHDZX7x8Tw8YWL5Cq0eCPv5+Bm2DxLkzk616C7icv3qrJQS7u/nijg+qGec4
aKqFGy+Gvc12cGUt6FoWG+6zS+NAihawxind+V/JYnIt1ulLAoIBAQDT5oPaWE1b
Vkm2RqVscq5dnKT+ImmIyUfM7lC6Ff6tf7CyxPumHwrMRnqfas8L5KnvgVQi33rn
OJ5SXoTSJDvU42eqFXD4fAKpsIwbxYi+pY2RPH+PxYNtMvWTMmKZnrqVowFAUHyG
f6yTIHqIZcy4Ll8wrq+Z2ZNQZAMtllXHLgdlFxDcReGmWvhtEtF2yc36DalQPWuS
XvC4Zf1ja37Mslst42MdYNBi9QxE4CKVIaDWnF1Yh5xq8i0DIbJt37xpweXtkT9R
Z6Fefc+hx7A/A5i8bSK6QQsrdL3CokZHY2dbYqDSNlD+21QgEI7wK6ivkS7XkUD/
fSVIRD7SWYgzAoIBAAoI4ny/rNxi2XtMMm/hibUKwEuJLcqp3BeRpmWeW+Xl7rrF
L54vFG3XutiBo8h/L8+pBnqmGLoyDcq9Yn4owjiqjU2RU34SKyMrODzqZZgx3AVc
cYimSnUakNp5gqRuLWASvn3Aff7v3O1XI77eaAy3HTTmKofQeB3qXpkiPAGrST1u
2IGIQ7YlOD4L2vUpnWQ9DTlxblqt0Z/0OlNNj1OdWDgM3GkwU/FQWGtNYc7vrxsC
8ndc/Bgnct8Kuu+gXh6j0BEXZ4a2+Jw61aVA68f0ls7liVV9R8+nG3cusdw4kzOV
v3Eo9h54uVJUhQEIpZRJm5sr8aGuUT/C/g2S+hcCggEAW91HtFUr1DkoY7lk5gsh
xLuwW+yXTBHW6uU2YjY+3wDInfgAERjMGZtEdfBcKo/LjGXJEAVKxwsouBT6CBBl
T/n2ayo4e8FndiFv3GpayiwDn79WngHG5IR/Kn1hea/yvASa+kLqeXTIYFBoTtGz
WvXflr9kqZJF50g0iILwVRWDZzQEvzochX5SzRancJQ0k/9wM7Us+ZvnSEoO/BcS
NbPtC4vU4FukfAI4e3OgCn81t1S6szK3gTXUhdMKA9BHYqIJCGE7zhLbRpfMeBqW
MfthL+8wawbfzMsjqUmopjJWEKxFhFy/6H01j2EeVsjWrKaIZDQ4tYqPqzDK+26N
OQKCAQAV5336ahvQ504soqkNpOiVplH0Ksl3r3/WuO1xr/Hq4A8YXbPFeSFkztxg
kjZABH6c7rV3/8NHJx86MAxXCAlLTIkR5aXmPrBI+EYm/fle9q/AbK+ppq3IUHVF
KXpost8YysCRlel2QrhkTln5PJd4oN2xoMWKPHEuc+mhxBMQdq30JtmlVRfm9JaN
ba3PoW9ecZG5eLP7pZi+AW+KfsaSg9U54jZToYVWeTnTzd7LD70hstun9E+FZAyh
lrTkZuq578ltOuUWwDgKOly0bCAO+q6KMdb7pbPxbtqtdNGbFpXaChLcKB8lwa+8
vpiaRjhZtk5MLPJs9mTHq1STrzL9
-----END PRIVATE KEY-----

View File

@@ -1,19 +1,20 @@
-----BEGIN X509 CRL-----
MIIDITCCAQkCAQEwDQYJKoZIhvcNAQELBQAwgb0xCzAJBgNVBAYTAlVTMTQwMgYD
MIIDRjCCAS4CAQEwDQYJKoZIhvcNAQENBQAwgb0xCzAJBgNVBAYTAlVTMTQwMgYD
VQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9u
MTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBv
cmF0aW9uMREwDwYDVQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMR4wHAYD
VQQLDBVJQk0gWiBJbnRlcm1lZGlhdGUgQ0EXDTIzMDMxOTExMDQ0N1oYDzIzODcx
MjMxMTEwNDQ3WjAVMBMCAgG8Fw0yMzAzMjgxMTA0NDdaMA0GCSqGSIb3DQEBCwUA
A4ICAQA+KQrjx/6nKzPggDpKEAzH6XxhUU4CZmyUKFirUdenQBjYLag2Nono75o8
9DVK3vuK7aeg4tIkUYOBcOEgYx0wEPU6PEE+yOO6KErn7qilN9gRnDHOTrfT0iNY
Rabyeat256gyfrsS84ZB7MnbhecWwC6sP2NiH18VCprH865X6sm5SxAfez1zITV3
YVtudX4UczqbfpDgP4BU5ERMI71tqj4gKjaHFkC0TGizSphiINDKPmUMbd1w7FHg
Ilj+7pNZS377GCX9JzoTaKLuMBiblkwSTUJic7Z2BJZlTgm18hhfT3AZQDVvkq0A
AEPxQzm3be3ZUb+zJvueTeizVHkd3Eufnk69p7w4wNRQMwfj/icm27RZa3bBpF2o
esr2Ptik9ZBN81oMAakONZ4Wxuf0n/KBd6VBjy6WkbalKGVoZn70Nke3+9HGWSIh
bgbuHt7XAlvsgVChtZWsGsyxYw4p2ku4T2ajUfpxqQY1DDCAThweuHl2FND87Kr1
5sblLLhA3QdjQ0EavsCV1646xorvoyw7YdHkqCPjRb1FsPWm/IePbtu+w9/VjDRF
KcHgBZBWmmQHj/9ykSI9pA5J7R7Nij6sX6Iu1g2yKiPnXeRQFiwhgsxslNk8eJfq
cK4c4HhnNtXa/c8jHcbymwqkF8Qltz0cbEW1usxZ2u6153pyPQ==
VQQLDBVJQk0gWiBJbnRlcm1lZGlhdGUgQ0EXDTI0MDMxMTE1NTIzOFoYDzIzODgx
MjIzMTU1MjM4WjAVMBMCAgG8Fw0yNDAzMjAxNTUyMzhaoCMwITAfBgNVHSMEGDAW
gBSMe9JFoed6PvsUVY3z4MU6KhnKCjANBgkqhkiG9w0BAQ0FAAOCAgEATjy3crOb
zDvF2CiBxmDMvOK8E/fhQ1BSUOB2qc/OiqK6zb1Q2MFvni945+Q+TwbHJqWBfU2z
QHuhOQHUQQNnIvMPXgjJuT32eF2Y7J4weaQOHNjrt1dwE6TPC1DLNUzibbjKr5x1
/scmCiXWYxjeLvS7aTACNaD1UmUxyroK6h4oc968ofdPURK54sAiddY+VBA4KW4B
WlAjxGSErZk0DIg5SXakSQbTkz8+pLnrqqtmvwQXk92lyfrwsSiZhHlcfBrJ6+mp
1Mho9H5r97mO/LRRV+2CRShqTElxVORbW3Q2ku6RGJHEUB7AssIeKBtEma8yfUff
S2bX0P82ETUCT3CPZK29QJ8eaxxH+PaRnyiT/W8vWuo+BRw8XqQ2AsM22vVCPP61
mg6VNsPJkJ8UaUF/S41aGMS21HNGk4Ik0iv0wiuu3q2rcFwGuuWB/gRUfSuPfFSO
K5sEf47dBPB5kMZCSEkX1RvHPWAYwd6g8GgVdlQEt/IIX4ChoASES5JNhDFar7tg
6h72VhfTtwEkGqg/z8vI1zP1Qzl2bZ773B/k/TAJ3j6N1JXiHUKioL1hAnA9glrj
3hnZQEQSewPf8opPe/l7UEQNXGlamYic5WRsm8xbN1KL6HARLqxkiC7K8SS6U99s
T7L2jh4egE5kyM4lLOFYfEugj4s6Soq6XuU=
-----END X509 CRL-----

View File

@@ -1,38 +1,37 @@
-----BEGIN CERTIFICATE-----
MIIGpjCCBI6gAwIBAgIUMp+RLATMshrQnbOfPkwKoDNyYhcwDQYJKoZIhvcNAQEL
MIIGjDCCBHSgAwIBAgIUKp3mjstxJ9gXt3S7lpKjri2dEUwwDQYJKoZIhvcNAQEL
BQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTIz
MDMyOTA5MDQ0N1oYDzIzODcxMjMxMDkwNDQ3WjCBvTELMAkGA1UEBhMCVVMxNDAy
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI0
MDMyMTE0NTIzOFoYDzIzODgxMjIzMTQ1MjM4WjCBvTELMAkGA1UEBhMCVVMxNDAy
BgNVBAoMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29ycG9yYXRp
b24xNDAyBgNVBAMMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29y
cG9yYXRpb24xETAPBgNVBAgMCE5ldyBZb3JrMQ8wDQYDVQQHDAZBcm1vbmsxHjAc
BgNVBAsMFUlCTSBaIEludGVybWVkaWF0ZSBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAK75zkJO8mpqPrD9vlSsfJgW7hbioQpuphSo1+3q9cAAWKFg
TYUcGBUNR/lUVdYqgzo3AglUwldWfeO9mBCIGNSN/heLFt1KzNutBsnE3YEeGKpM
7nHhMzh41otFdpZEZfrsGXGok07dy2mEV0mx72e9ALWbXFhxYsdWdSSVTlBH8xcd
38rAzfAiTbjgAUnTIdCPjAJKbXSDBXGXZ3+iuhFxNtSWyJr1AsxPzESErCPzUQjr
m8TM24lKq69zimTEkN4uwP5U8s2JPzbKosg2k24RbpDgkjO8iNK7RL9SMRUE8daP
+eru5EwN4BlZfsNpZDFbILxbt/2sxqmdsx/Nupa5ZAfcHRs88p4l1D3QIiZzaSEc
nCotM/kmnHWbgeJbkGbC9fD23dNJ29uqZU0fbRnG4HpSutrYD6lPg7PXnMt5tT+f
0+wQds38woXT9qW/kN/2WtkVYDhyVjxCgD8iHOZpz2LUmvJfi7Gz9B/DeW1dzgbo
cGxz9ee+R+T5KcKg+XvHD6slk82GrSM21b7zJeK92bJtjkqxBtQf+YgcKtOO7QX7
37C1XvSHFnKvyyRJrldJFGEKfK2C66hdASHRdbUhWHFo1AA7VqzKB1fU9M2+ltUZ
zRpYD7X36OtRY1KsHHn+SVvsn404hWwgPblZ04nsMPanj+jsN//6M9r5lMezAgMB
AAGjgaEwgZ4wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovLzEyNy4wLjAuMToxMjM0
L2NybC9mYWtlX3Jvb3RfY2EuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
BAQDAgEGMB8GA1UdIwQYMBaAFNnX872GsEyiVMz7up1p/Nq/K+0VMB0GA1UdDgQW
BBT2zEtzeetYaOXAVw0Z9Pda1V9n1DANBgkqhkiG9w0BAQsFAAOCAgEAb7xPI93b
gqpXi4E/hAl7Vh354kKV+1smd1Omf7mQZbTrKBo6o1s0ZpXCbC9+WzK47R21VPNe
EgZ3uzTkURu4AX+5OnAMiWDFAGRSDt8ZXk6ZukWP7OmHsnLCu2strdhrvC4EhMF5
G9VPIQsTx16CpprrVjzVzJg4i/X+U9dypvnAQeneyz4Ul/kPr6di8bOB3FiBeEDu
dOkVTbnlDa+wMQlCvqlFroFjEHZBKK/+PVIx9cJYj1grmzgqzm2FGUs5Wvcixpgb
uSHCQY9JP8Hy0xl3wx58VaymUK4EMfs612CfzOMClaiooDYuZgzVfhalU6g268nc
PQ9RCRJtJuda4mJ2H3Rag79sIiCVV31tE6tLXjOGebuO0vEB8wOjJc4YW1gtrZFy
GltT+HMdFgjO2c6HynpkmtqS8axQAw2hVaOpdJbDW+R0jHihO98FAgXR27TqTFp9
sjBacfITeYRXGjQTDU1qxuEfoLnTZRIct1TjRTI1HBT8fl1exxgKUyEawH3MUCo7
LsTPSNASKkJH3Rp29be9xTejUx2HUUwOE/DIF0HKaN+aAc8TR31/4HvC3bf5VPyD
wIwazpjVDZlQ2w+Wry1zNezNCPKiWtkfkj+TkT32h4ZfQEX8t0MUpKnL1LOSV/8h
PV357EenQb+f9DeC4BIbmipovLaUWmml10c=
ggIPADCCAgoCggIBAK+kNJHAUL4dcMnjElivyuzkO2UwTUlJcKQCBmWRHYQjRbP5
akJx8SZ+wI0Spo00hG4sV2BxA83J+Yrked53DEzlR+RxojA16vXzlUO8c9KH2dJQ
E17PgZnu7/hECmQcT69ZJAOh78ILEXRYk+2ixSTaZRTtchJdzfXIQ0633O2Mi/7z
z5idQmQeXbitC3QIZeNzwitl2FLXPIw6MUnktOKNjQSNxMr9AU8q1cfOoICJQs0J
wYVpby0dv1z0f2N21JJywaeAImHa2h58sSX6uqwOXtzdwcPlr2+iJ09YwHM8uO0D
rtPx3bLHfkvbpMd5cCKjSeFozP1nVnlKJUmAZ8UXk4MAFKCtuLv2/InA8MkclZmX
1IzBbvYDOw7AnsAN2VQYZSgM8vCmnRCzpTmtvb3ysSo32sTUjGW44giuRtGqh5Ct
LeRpZZVm6zDFY6cjpr34+3Vc4pys81d3Dq+Sos4YVPXhTKW3I1VtFIdCeNyey7hv
epjna6/JvOzQuwK90+t9VmZk7jTY2WOUNXJhzDTeDku/aTMIeXUZrAxg3pOvl/wf
SN5i4Gauhl7URDx3nI0jc4Y2u9NGFi0TYJMCRVVLknAcre5cDKFyf9ts1gDyxTDc
+orszCE3ZQzXZeEY6aiQPihhL1YDk5SkkTI6XHmUqLW3HFlfg2aFH/oI+VGBAgMB
AAGjgYcwgYQwIQYDVR0fBBowGDAWoBSgEoYQZmFrZV9yb290X2NhLmNybDAPBgNV
HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQsIzqwsaKX
aQyBeov7u8c7q8IEdzAdBgNVHQ4EFgQUjHvSRaHnej77FFWN8+DFOioZygowDQYJ
KoZIhvcNAQELBQADggIBAD4GmfmI5R6cy/Sp37buyO53azgw4RvVclIy/2qSPHVX
Os0pPPIIXLsbJMy7M6rDvKx/thZ27BDwms5dNuDynZ494XjqTmwzbBr+qEIzCNpa
QiX0MHf9JqFq5hkcZihfJ8PZL9JWIjiRfMI6AERd1pU1QJI/G8ha1vAkPfcA7GvH
NBBwKBm63iHYhp+zmnEEh85lpj4pEq+hOLK+mJxu55BodbNiBlBGu4EbalZlwXFp
7lGHLPkxuXZndrlrm8Lk+hi558NgNFxqz6qYtUc7txajViU2xFjEkTcQ0FKNiFpV
eHn5TNjwh4QucnWc7wI9hcDoADrekTEr8mUKrJXgxaBLIXEShC0ZDBnJsEwW4xbg
GQD9qXyo0h8cYx2NngvL+9Ee3rzdYAaSfAnZOU0xxrqZt+2dstNqi3pLKdS6RpA/
3Dt3cAnf0mQQSUP6oZQpfdSEJ9uggT9h+kgJz5RGOQfEELKA5RxHtTe7249J3vDv
hoy0Uy6+w3Ji5AQdn3G5uUGxLsBh/uS1dl8hq4gihrpPbKVJHVxqPL0HCx7DyhRw
hx53GXhGIgZN7QSGTrB5iz9YyzejsnysS0Um+figkxtC1atqhVkqzMDZBHUwRPfy
wq8PREXoRITJHfSkg01bInRFMMNWDQuPwSHDX9OYNqpkXzlV8/ao9Rx6JOtiG0a8
-----END CERTIFICATE-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCvpDSRwFC+HXDJ
4xJYr8rs5DtlME1JSXCkAgZlkR2EI0Wz+WpCcfEmfsCNEqaNNIRuLFdgcQPNyfmK
5HnedwxM5UfkcaIwNer185VDvHPSh9nSUBNez4GZ7u/4RApkHE+vWSQDoe/CCxF0
WJPtosUk2mUU7XISXc31yENOt9ztjIv+88+YnUJkHl24rQt0CGXjc8IrZdhS1zyM
OjFJ5LTijY0EjcTK/QFPKtXHzqCAiULNCcGFaW8tHb9c9H9jdtSScsGngCJh2toe
fLEl+rqsDl7c3cHD5a9voidPWMBzPLjtA67T8d2yx35L26THeXAio0nhaMz9Z1Z5
SiVJgGfFF5ODABSgrbi79vyJwPDJHJWZl9SMwW72AzsOwJ7ADdlUGGUoDPLwpp0Q
s6U5rb298rEqN9rE1IxluOIIrkbRqoeQrS3kaWWVZuswxWOnI6a9+Pt1XOKcrPNX
dw6vkqLOGFT14UyltyNVbRSHQnjcnsu4b3qY52uvybzs0LsCvdPrfVZmZO402Nlj
lDVyYcw03g5Lv2kzCHl1GawMYN6Tr5f8H0jeYuBmroZe1EQ8d5yNI3OGNrvTRhYt
E2CTAkVVS5JwHK3uXAyhcn/bbNYA8sUw3PqK7MwhN2UM12XhGOmokD4oYS9WA5OU
pJEyOlx5lKi1txxZX4NmhR/6CPlRgQIDAQABAoICAAzvUnVE5NVZaPHfPH3GRXMc
bEDblad+5nIXmZW/gf1WFScnyDLoPf6MIV1KSTR3MIUGFDG8pO9x70QSpyRyXzgm
/vxEf5GeGOV/yKduQJfZrBmMTt7huH1H/slpZlwAx0AGOCwhz/y58LFBKDS9Ethv
0nef9HGEkbtG4ikRCo6+dd1i4nAObcIeh9+ms8QZ7bn6T4t/YrbYFcQMcY6L7qPM
EZ1rHNnnl8H3KTr/nSuWIDKmJCexb+/yQ8JiWaLPMKCv3ZHasn2DHuLVozylKjvr
S4JnvOIyvzChEBTMeBDMgSBoT+bZJi7pOOR4gpozl+XfIVzdqVIEmxZP1u7iq1GV
0jS/NwIAiZyp0e4YC+joS81AaskqoiTnk59inipWgtXaqz9peSd5hDA2u4mfSCVY
aKHEDv3dUYyc++JTr0qjAlxuu0SJjPZMTeIbMoVX+7RTwEHyQoiHzNLzBXo5yGm8
b29oOqA4DePMt9+J/h3xuiUH9SmYxTkSX6oGZAJC2qEELGFbpN61zLSjJOlv+wfC
Nmpd8O88q6dSG9Tk2o2xeLRXAEulEtmIwjr0x8S10pieJ+ZhoaHAyIRWnbVfwj78
pKLdpd8MPToTS4f98nkkVfbmc7ymVdz4JhnYTco4aqmtai/8yVUzzIjOLfJ6bp1s
N9okI+1fKgTVlyNj40opAoIBAQDeZqJLT9DTAhxZqa+ZUYc/ztoKiT1JLXDZDWhO
J2MVqFdTs7sAw/NhVx7Buf2VBmRBZ8jW/izrING228bCkpIvF8Kf5Fz5busJcJB5
E2xhnIKRVrnw30JCxF0dGCqpfA79GyhfSsAdcx8ou0TUAgznvYHz6BvdYL8VuGuB
YQ5uJNSykrtHsZBwsk143VrwmUyL/HEiq/btVJ5vRLKtbR59+KOzqgZKTgjDZDm9
8HwA8Nw45GqFdXUIHJwCwbK0+YE9qW/QCLDtx3wct+E1fs0C6TuMfLrh5khHUa6P
EZKLzkTRm7VHYrFFSGQBQBQ9mMalEttkrHmnHwfd5PAgCGH5AoIBAQDKLSVff0GB
5uadXXcRMRrhA+crUud8RUi9BEXdcUJR4fLosJl6dEBkhrC9pxVpfczAL5zXaqFg
Z4R3AinWB7trIGC1MaVc1CZenBtiVsPHNzOkqeZdcpK/WZcqJ/6AiDrXWYDu5N2n
hsff3Wtp2QqqhrrsP9pZnyrikAYeBvtuys28wpe4L8fZhwyRNry2jziIlmomtHyX
vr1xjfwQyVNno0RpppgAdul3RqBUV1HCpL7pndhfwWRCnW7fVDawYqSpIXUHjW8E
3+RgpHh0/YtLNinRKe2cDYorgxF02B1YCcSignh1msIbuJcH1MI7N2C0C2atiGYE
eSK+R12HcM3JAoIBAHaHXJemwjSzO0jOFrgvq1VmeO6ElhUaErqbWqvMchJo1aHW
eCPAS0XlmI7HAU8bSPNSzMdIT8hAhYRfPV8VnrNahm+Q1bxaUQmG5Hii0XB0aWHs
Rs0JL9dFsBqBdrs9Uv+yKaIfxKPtZv3eUKBtN1OKvGexnKgvl6eL0j/x6i7pkjJZ
4VYkXEazwHZaAs2X5iP1Npaz77YtEwNaKaAkN8wLZ7OpOhD/5cu87sk8Edqug7AO
jHb0UpswJDWT5hptn2OtmdnVx/XyC0OC/JP2MG0MwJ/vGeqrQHpCHjZBt0irdiIA
SmzxPGkgW6wO6rqpYbU4h5TwFyXqc9be3Ns1nIECggEAYZUIxN8XLyvTg4DpR1L8
Nj88BJ0vPbvzL8gwMIHKENuN8uHKMmCJ8/tOsztCCni9qsVQXmkJGw7b0NUqfDOf
MkWeZ9Zeij+bhW6ziPN361+pfYDDv7bdPZ5wZ9iF7mPSgr6gjK3KjmFvd43Xmm83
xrbg4cawDTHV8SSyzytvkDoyszj5Id1uCIA2gKB61WKrVsHC2oui11so9PYjA7co
mo0jKBtQomjCpt9f41WCEQCTZQ7asN0XF1AFg6WR//CcqUWMxuhs/V1TTZIU0eLO
qK6r4FjsZrXiSr4oXs0w3J1aW1W97oWTyu19eDooxYwlEMGv/XIoS2BsdIrdidHY
gQKCAQBrA0X+AwT9xgEwYaXnA9RINBPSnzruv1giHHAmY9iS0V6BNJUzlJDyASdT
7drV0YRY7bKCguZYNVZh3o259OXNsAOStd9yiyFzZr6bAVvTVXIkrB040Rd1xptC
yl+kxYEfDeENkCR6h8JkFDupG4xF0PT70sE1sUGgFg3585nWzhN/s6xC9vxtBNHc
R+a1UmoH8pYSONttldtW7g2kB5uuQTU0lZVSHDj9B8z0Twj3b6+kQlXt0ielrVV2
TSVZcmbIyyEYBDcAxOCvHN+rzKbP7H+7JqHVgnbe12pnVoN7WVMbR2v3F4pK+0aA
M9Wd2js5nPPh0AN3Px1643vFYcAQ
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,20 @@
-----BEGIN X509 CRL-----
MIIDPjCCASYCAQEwDQYJKoZIhvcNAQENBQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYD
VQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9u
MTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBv
cmF0aW9uMREwDwYDVQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMRYwFAYD
VQQLDA1JQk0gWiBSb290IENBFw0yNDAzMTExNTUyMzhaGA8yMzg4MTIyMzE1NTIz
OFowFTATAgIBTRcNMjQwMzIwMTU1MjM4WqAjMCEwHwYDVR0jBBgwFoAULCM6sLGi
l2kMgXqL+7vHO6vCBHcwDQYJKoZIhvcNAQENBQADggIBAJB5ERfMQEZ5Pdc3A8+d
gDiY53VEdA0Zd8MDv+j+Mgu1qn7IW2rpE313yVHieclZ65ReEtb825St8UBJtjiZ
9Vd4lK9FUQKKCblCYNrEbu9cvqNeHDGxldQPUkEoz+z5kielcEwD6RUsK5fSYe3Y
6E3jc9mMHw7xWCSiolvNr5y6AUymfu22v41qgfaB0yNe5uz6vRgRoiy+OTP3Z7oc
ls7o73F9O4k6QYdba8us4v0TSwZAAPO16TsHhmyHcBe3w23UIusTU/c+6A++hGdU
TNUW3OZl+hv+4BcnClrVBDfWiExOMNzIhH9hzlXQ2qNPNqz2ymlH8Wgpf1TBYJ8m
xe8EuGGrDFuewa45kA8uxuHCiSLCsBowDEXXkswaSF4E4yzYZqcNDcLOedK7vG9G
+zXYHOpLsZMyfgauxjuWtwR/ma+ub85CHy+eUC2waI+Mk0Uk0Lr5y0Jdp8ztxakp
UlVHYNU/Q+kwHfmKztkOsedomOf1/8IvzE930ZB8rv0G8ok2HXYvA3+r3lcDSG/V
7+yq3HcJezw0XCDtc5mv8dWI6pUv8siWFKok+hlkZpeSXgtqRhF2rzI8yz+lk5Cr
5yCWroPI0T44o2RzjfGZAViRH0nnYF1GoBORSZORppubcjmiTy46OFG/fiWKGKV1
sngAoQ4TCDQzId0zwGLtUCHu
-----END X509 CRL-----

View File

@@ -0,0 +1,37 @@
-----BEGIN CERTIFICATE-----
MIIGXzCCBEegAwIBAgIUC2OH79tloDOfMBeyDBA84epTMKYwDQYJKoZIhvcNAQEL
BQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI0
MDMyMTE0NTIzOFoYDzIzODgxMjIzMTQ1MjM4WjCBtTELMAkGA1UEBhMCVVMxNDAy
BgNVBAoMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29ycG9yYXRp
b24xNDAyBgNVBAMMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29y
cG9yYXRpb24xETAPBgNVBAgMCE5ldyBZb3JrMQ8wDQYDVQQHDAZBcm1vbmsxFjAU
BgNVBAsMDUlCTSBaIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQDK+jIoIZVYyEq7ZrxfKv/TQQWCgI5C8BewYkB+/rt8NY0fn/aAZbvJdnDX
cQCLpCeETDi7C2hGujnZQN68otr2GpJVQ/kgKnM8yU/p9yBSUan9Zo/195a9YytF
6Ys/Yc0HApoPtB3t85NHNjAvhzdcBKWMb+/2FiJ61gdnrO/zORnxp/BejxTMyB6r
0mhhVX4wwdl5vfkX/qS3TL0rajEz0V+SwneDiIomoVJCnco40Km1M20qU5L7EpNH
IMEP00hcj40zO0jJ8cGDNoKgTHsZPovYfFmWITVOFvaPcKaloUU67dYEg0fv3ypX
aYHRszcd794VOWQ85r/mlFSSELwoUrVH7G0t6wnzOawW2kk7ZYndbo+Z1ZFb1Ul+
iVwUAHzx/ylmOORJNM4JGiYyC5+1481MLeB+37+V3TJaBe4IoKqVo/OCBsaPt7x1
rMpZLw4gXj3A0Hh8gi0z5HDkKolMSawuU8dpFeI0GN+4hJN9DNQh0OTGLEfzeo+1
lNzsF+jGT9B0tApWhBq/QTyHXvJREVx32hPd/1X6bVbd9mik0bexg6bVpZVNG1sn
7GsVO2wq5OWKe3UtSh8wJcjGdW38fPAB46oIBQ7x0HGdp/KFiBTWxrexLThMFvYL
wPtWedj8ntgOBoH5MJgL1XkVYP+1EQYaBJNfswvF4CrvPRCtCwIDAQABo2MwYTAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQsIzqw
saKXaQyBeov7u8c7q8IEdzAdBgNVHQ4EFgQULCM6sLGil2kMgXqL+7vHO6vCBHcw
DQYJKoZIhvcNAQELBQADggIBALZNLMgm7RqIKY++Blc2qeIDrwlx1U/PPN/PsZsN
cQR48Bq+vQ4cV9hOcZC3jfRbkkDho8jxVTXdEOcpDyU4zNSLG1+b1FNRvqjq2L+d
ow190dYqvfgbdNFo8V6kLdRFe5aCLhHTWGLTbl0vvkc99h1Lt9ZXr6LzhFwbXSGr
Q/qJoLZFVBwJZmfZY3VmL661sBcTmzDDGJxg00fg+1jCIk2Ot3dn+7jQ8g6HYMQv
8GrqGKcFia8fXcTTmcH+Swr8rps1MYypjkpX/zVHsFuENdqZNkqU+OLTaifkrBuO
6evTTjEOcDzMFs5Uipjvq7XOBg5rz9BKRXrjDMdI4CmUzMR272lToNw7lHqqNDKi
nxAzPjPWVwXQTu2LFY3NwubWkPAVsd6FsHKzQHlq97N4sj+vp6vctaEUgFS4pUlL
tbjw6AtQA72z4uIpcAzE2ctTj831QeQSZGKBUpeNPjuK/NjytXQm8MvW7LI2OgaI
H5B9+KE9KjqijpNiiOoidYVwFRrZniIQii06qXwQUgz2gGIzYPER9+3PijrtOY+t
K/vS6NohUYb16PhbbvzFktSGBtvp1kUF4fB2NJh0z6OiZXVEHlCYEDTv78RS36iU
PXijR+rALi20P4Sg6picuvmt2epfSMQ4ynNxPhbSG7wMp+Zp5tOrZcmg4jN0Yt56
tACH
-----END CERTIFICATE-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDK+jIoIZVYyEq7
ZrxfKv/TQQWCgI5C8BewYkB+/rt8NY0fn/aAZbvJdnDXcQCLpCeETDi7C2hGujnZ
QN68otr2GpJVQ/kgKnM8yU/p9yBSUan9Zo/195a9YytF6Ys/Yc0HApoPtB3t85NH
NjAvhzdcBKWMb+/2FiJ61gdnrO/zORnxp/BejxTMyB6r0mhhVX4wwdl5vfkX/qS3
TL0rajEz0V+SwneDiIomoVJCnco40Km1M20qU5L7EpNHIMEP00hcj40zO0jJ8cGD
NoKgTHsZPovYfFmWITVOFvaPcKaloUU67dYEg0fv3ypXaYHRszcd794VOWQ85r/m
lFSSELwoUrVH7G0t6wnzOawW2kk7ZYndbo+Z1ZFb1Ul+iVwUAHzx/ylmOORJNM4J
GiYyC5+1481MLeB+37+V3TJaBe4IoKqVo/OCBsaPt7x1rMpZLw4gXj3A0Hh8gi0z
5HDkKolMSawuU8dpFeI0GN+4hJN9DNQh0OTGLEfzeo+1lNzsF+jGT9B0tApWhBq/
QTyHXvJREVx32hPd/1X6bVbd9mik0bexg6bVpZVNG1sn7GsVO2wq5OWKe3UtSh8w
JcjGdW38fPAB46oIBQ7x0HGdp/KFiBTWxrexLThMFvYLwPtWedj8ntgOBoH5MJgL
1XkVYP+1EQYaBJNfswvF4CrvPRCtCwIDAQABAoICABhe0JAvnWYwK4OIouwCQP5f
pjEJt7WjF2pewZj92LY3GnSbmNXIYTL1J43rzBb4D06RIEFE7gY1QdDV5b2xsqct
1Y1V60lzZKv9t7yYUVHQ6vS5JbvF4wa7gMHqIoU/ptrv8wjDpXxLwc52W8ljwL/U
Rv7aScNlhkpH/FJJr0hSqMzHpH1AofdcZ7eq5vbDdF1CSRbsOkYpQCRJ8G86rCGp
QoJfxZ24p8ME8i18EyrzKA0mLuCQHED3n/tARtiG6P9ECmiw9jJY9n+x7HPL+v5d
m3N9//ud4m/ieJlhpdXpIQ4hlDqtJdalGB5aqp2U7kndN5rwwxo/fPb1ru8YAfSB
TK+5ikIn1lfzkiRoTVAmZubXqSSi1xiudqwL28euIDn0f93aiEInHO7Vx2o4vpgQ
MJ3Hg5XaGygUAR+ZSnQ7lcv4kKMpSeqYuZSRRLs/RZ2Kw3jCYpyQyr1Ii8qH3H9S
hUqZqUZK4splagRureExDkFrGvo5cBsmMGZqNfG8Ix9imEC4kRhhraIcmziwY2Ca
mKqGH+sGpcvHX6vmDe7wZb4fo+Mkkacext42t8dtkPT3nEJhsR0xqmcgvyt6yP5t
y4mv2hGeDEsclpWNfuug0DeOwXjClATZVrP4baL4rGrP6AGFDiRz0PbWmaJwMLDZ
D+06rj6nO9Ibu/t5tkWRAoIBAQDw2JSTzLEdrkX4cTaHE7pLWY2BQuiIXdYOdXbW
jkPytSgqHfpTckCDl8UJWMBzo87xDb5Q9Hmsa37Mj5HIz+lGxLPukuhiRUnu/XJQ
AxzLXBBmdIsb0Rha1kChNASPHXo2Ozi9OsWB9UC65P+U1cGmE882A/Y4p5ak7C+q
iQk+IRgSqKrLIIHFG0h6Zi0f+DlXMtsNQ7mjDk62WjWzneS/NPwN99VwGacGqI99
IOhJIKfhpbIXMg2Wo0Xj3HwaHWccK10Va/x8jvjunX9V0px19yCPnMsMWTZ0WN9F
CRbeD8zCuwasjQkBkqiqMyShk/gs4K6J9TMc5tprB2xB7+f3AoIBAQDXv6WWdsRa
NuuMrzJ94ZLESUIHBg/u1uGJgvtckpKAm25SnEB2C4d8u09zey0BsXsxBKLJ/HAp
Nci07/dKkDlmG6+SkVhcIsEAokw2EFWG/+EQJ1Bd2gbX9RXQv3O2sda/2h3QB8Vu
BUmvK8nwpFaD5eqrIeFxBhao4vHon80Bv1L1F+QVfbjOgV5eS146VU7Gl7b/LuMk
yx3I4HwWqNbQUGTnVfC6wprae9G1Tamui+PnCPMdVSP972gxMNfhqkt04BN2j2A5
/Lat2VdL100W2XFzLEQmfD4sAlsJQ/jTcGhDb9Brxlf9kQYt1r+a8igcJQqoz8yr
1wLabN6FKuaNAoIBAHALwit0ad2uCt1HBiAXPG77jYpaL0XpqcD2QsAUVWYfgzz8
z01s9LiDreXoRThHN+oLA8QzyDs/kzDlheQPXa5PqonODJBTPc8SV9EDcazl+rc/
dswNHbB8xnp4cbqG8ykxqfbW1bXc/C02hfSe8UUrKBYwB6dZyAqX2qESuZsO2F0t
3K89Q0IIrFJNIKcj2sFHZoMoQ7+o01OgaiVSym1t3+k7qC9Lr9m4J3EGEyqaJ6Ah
btW9snanJMeZ9p5LmYGQZvClWUQ1W3ffC7NIlQOIYbyOLCRliKDeC5jZXqsWXKMn
UTaLMmpp6U+tFViaNzXhnTGPQiUq/OgX/vQ6AQcCggEBALGJyY+ZyFacnxU0Do68
E3Rm/GifOnlGZm4sVQCGtPwT66MbZYg+UI357ZWQJSchj8h0kik5DGs9ER6j4ZGA
QVufKMmpxVZ8WupUo/ZRVrAy3FfYoi+4/Ky1x+/xvBz5F0jlCmdoHbU9sLbvh8v4
0CDWEFgnF0dUxUzRBFRzO9ZWRMPflxeAT5XPq4JY7v99t8eAjVxMjyp14tqssDBN
XAgsP/yGIgTto1RrU9SoRhuWjkJOgREAQQ/z9H+WO/A9nL5ermV/8qWFKibBlS6Z
y5wj71HheWtaDidVAOkNADOuan4kAxTNMRc+QiFyeFXfM9aFPNJRvZEi6/wmXq6i
8PkCggEBAMK0qSiZ0kBgTqgYhpKqCwEUgEueTC3EloZQ6CHV1vTEfsyM3gEQ2A5r
8+viQf1RD4UloCWfOF1CA9SqgtXAAIQyGVAATjG7sbUNAK7jac9UdZOS8QSkcJMS
UIHXndlct/vijnNe/htGCcu+C2KCJz1lfW07DB8WOoyP/5e7es7e0RGjGgGdRdu2
MyCXJ3lG0heiVUp2d+5R80UAZQdlHuzo9sItxSUbsO639Q1c+Cew/cM6YPxdcTGo
LWnAsG3yJZgR3pipS9/GqISY725c8QJijYMG3GFUBD6pMCdD46Kl/rfjUsYK3Aoe
2lXPecP5/ilaLLUhs7SijqHzcKiNL80=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,20 @@
-----BEGIN X509 CRL-----
MIIDPjCCASYCAQEwDQYJKoZIhvcNAQENBQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYD
VQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9u
MTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBv
cmF0aW9uMREwDwYDVQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMRYwFAYD
VQQLDA1JQk0gWiBSb290IENBFw0yNDAzMTExNTUyMzhaGA8yMzg4MTIyMzE1NTIz
OFowFTATAgIBTRcNMjQwMzIwMTU1MjM4WqAjMCEwHwYDVR0jBBgwFoAU1p7a8iaQ
sGamSdR9585yWIW36CowDQYJKoZIhvcNAQENBQADggIBAMcBN8PztJELdCo6fQvw
C9ZU41AmBZsMdIoacgacupt94gHf8SAO1Ric46j3KERpA0mWKAx6RH1s3OX2qN/C
YSrVPIZ076Cn9EMVdK9w9hqt6SYHoot9CwPutF6BBG5O2uN6eAsEM21B5Tr6xTZ/
SUj3fO3+QsePDL84BRfU5vtZcGj1BkULopWwibG82ayEUlbY3J8OPjK5YKuHtxJd
lI4yfkmrEPwHEm8bwI6lhaIxrtTjoVgoolw+FqtVdVdU6O254AUKwxN88bHoA/sk
BOr13AoHXiKEBaEJhocTLJRfvUZVRYGll43ELsy60XEH51W27/uULnC92vBkp4Q1
5hPwSD0RHKfMwsLKqoJaWX1CxfdttapCfriehMXJlv46GPmq6cLIEbbHzJKsyJhN
4mW8Uiwn1aM5EhMauSLuuwNp8QRo4rmQzUstxwn4O/3HzTcjVWbn0XvBXa2S5HtD
2kyWwN/qck1N9aXYk/sf2A2py2ECDuXc/Kvh1kDi6ZSaKA0VSS1FX62HvdqZKQb5
ZmyoQUpg8yv0hholaZd9Jye0pwww/K8CFddsyUMRYDSj0+qiw4pgx6KK3ElKnHeH
uq+iLxDLWTqrWQw6k0I92B9gSlNKR3Z6Zq2UTxo6hB7IYgZv5nxx3BRxnTm6aH6a
pIoxgnFnbNnyUIRAkOCHbFqy
-----END X509 CRL-----

Some files were not shown because too many files have changed in this diff Show More