mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
172 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9eea78b3ad | ||
|
|
0a3a556879 | ||
|
|
aba8900074 | ||
|
|
f5744b95db | ||
|
|
13d721afd3 | ||
|
|
90a2e6d70e | ||
|
|
bc9f8a8100 | ||
|
|
2b5e7b0491 | ||
|
|
d7c95265cd | ||
|
|
8751cfc409 | ||
|
|
01f96d30f6 | ||
|
|
fffbd93f12 | ||
|
|
ddcfbdc8d2 | ||
|
|
173fd7cdca | ||
|
|
d14e7593cc | ||
|
|
1a3d0b74f7 | ||
|
|
f6c6f0cc71 | ||
|
|
966e67a252 | ||
|
|
1c128c0d11 | ||
|
|
a3199d58db | ||
|
|
659483031e | ||
|
|
7dc2513205 | ||
|
|
0748d365a6 | ||
|
|
94a404ed10 | ||
|
|
ef1799f31f | ||
|
|
47b0960cc7 | ||
|
|
2288331a6f | ||
|
|
23e9156f43 | ||
|
|
8f99e7c4ea | ||
|
|
f3bcd94524 | ||
|
|
a2f8b19c2a | ||
|
|
588d720517 | ||
|
|
cd822cb770 | ||
|
|
b27b8e3cd3 | ||
|
|
7a2c5dc980 | ||
|
|
d9e3763d1c | ||
|
|
6f15ed3264 | ||
|
|
0d2b5af007 | ||
|
|
9e7a8f48e8 | ||
|
|
98f7a0569c | ||
|
|
551f66282e | ||
|
|
3d2ba5aaed | ||
|
|
94942a48ab | ||
|
|
ab8984a7a3 | ||
|
|
4990f643c1 | ||
|
|
34bef977e8 | ||
|
|
f36c34038b | ||
|
|
bfd0e12d22 | ||
|
|
1450f85ada | ||
|
|
2a0f1e6977 | ||
|
|
0f433b1142 | ||
|
|
ab6bcad263 | ||
|
|
e40a3e0621 | ||
|
|
e56acf4f14 | ||
|
|
17977eda30 | ||
|
|
459a257568 | ||
|
|
fb65b53b9b | ||
|
|
c8d4062f73 | ||
|
|
c8e0992814 | ||
|
|
c0a12b29d0 | ||
|
|
02dded11a5 | ||
|
|
b71279cda5 | ||
|
|
c70477f8c6 | ||
|
|
9b51b8b882 | ||
|
|
48539596ef | ||
|
|
cafa99774c | ||
|
|
b5f7ac95d8 | ||
|
|
e984b97db0 | ||
|
|
64d4e02b4f | ||
|
|
90ddef5a41 | ||
|
|
58ef99f76b | ||
|
|
43c34956fb | ||
|
|
d7dee1b9d3 | ||
|
|
94a38ebc3a | ||
|
|
0764460eaf | ||
|
|
6fd02279da | ||
|
|
6274294bc5 | ||
|
|
27708026d4 | ||
|
|
849aa5b105 | ||
|
|
0be83bfbba | ||
|
|
f8592be43d | ||
|
|
647ad51423 | ||
|
|
73f51e45a8 | ||
|
|
bc4f455151 | ||
|
|
b4b5e0b6aa | ||
|
|
9927023680 | ||
|
|
9b2fb1d4d2 | ||
|
|
689b894506 | ||
|
|
06a30ae529 | ||
|
|
ed106d7f28 | ||
|
|
9d08fd8c7e | ||
|
|
7e8126704b | ||
|
|
d96767ee45 | ||
|
|
63f31bf73e | ||
|
|
7ecfe2353f | ||
|
|
7bec672c7e | ||
|
|
5aac5deb75 | ||
|
|
54e016ae71 | ||
|
|
6b53378839 | ||
|
|
1266f86444 | ||
|
|
231c02cdeb | ||
|
|
454a8d9d7b | ||
|
|
bbe92b9cd3 | ||
|
|
7bb41732fb | ||
|
|
c217f6be6a | ||
|
|
21662d38e6 | ||
|
|
19f3842292 | ||
|
|
ae0cbf00b1 | ||
|
|
9019c6864a | ||
|
|
d1b61c37fa | ||
|
|
32b68a5fad | ||
|
|
55fdb17b18 | ||
|
|
af730c79a6 | ||
|
|
041e6131d1 | ||
|
|
5a7d7e05b8 | ||
|
|
71b93d55ef | ||
|
|
d2b5e1e2d6 | ||
|
|
a3cb877c54 | ||
|
|
6895a71cc4 | ||
|
|
d9034b01f1 | ||
|
|
488ac8c3f2 | ||
|
|
ecf36d53c8 | ||
|
|
893ad920c5 | ||
|
|
0695c79f4e | ||
|
|
8837ea24cb | ||
|
|
65222d03b9 | ||
|
|
54937495e2 | ||
|
|
8a783b81a4 | ||
|
|
093da2a5a7 | ||
|
|
b68ea5fc7d | ||
|
|
90c587408f | ||
|
|
90475fbaa5 | ||
|
|
07ff9e1da0 | ||
|
|
5637799c92 | ||
|
|
73c82441e7 | ||
|
|
6d06921276 | ||
|
|
2996b34ddf | ||
|
|
e5821301f6 | ||
|
|
f4d1874ac5 | ||
|
|
f3428929a2 | ||
|
|
263d6950a1 | ||
|
|
8024f8e31a | ||
|
|
3849b29594 | ||
|
|
0e4d4da0e5 | ||
|
|
ca3cd51f91 | ||
|
|
fda1e0d33d | ||
|
|
1a850392bc | ||
|
|
14a79eb142 | ||
|
|
271b809495 | ||
|
|
2363269c1c | ||
|
|
f1db473d11 | ||
|
|
e35d05a5e3 | ||
|
|
c61783546b | ||
|
|
c08794bdfb | ||
|
|
4905975f81 | ||
|
|
d53bfb9201 | ||
|
|
0dac47cb62 | ||
|
|
7b68552359 | ||
|
|
775495c7e7 | ||
|
|
1057f13cdc | ||
|
|
ce59a299cb | ||
|
|
8235e025d4 | ||
|
|
b301381f90 | ||
|
|
c62f930634 | ||
|
|
85eb44ac95 | ||
|
|
d5f8063900 | ||
|
|
ee66929465 | ||
|
|
1b044b8a40 | ||
|
|
f46f6d34d3 | ||
|
|
3a96e8826f | ||
|
|
84738668ca | ||
|
|
dbea311aa8 |
@@ -1,5 +1,3 @@
|
||||
parm
|
||||
parms
|
||||
crate
|
||||
ser
|
||||
deriver
|
||||
|
||||
@@ -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
1
.gitignore
vendored
@@ -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
35
.pre-commit-config.yaml
Normal 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
5
.shellcheckrc
Normal 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
|
||||
@@ -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
|
||||
|
||||
70
CHANGELOG.md
70
CHANGELOG.md
@@ -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
|
||||
|
||||
18
README.md
18
README.md
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
38
common.mak
38
common.mak
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
352
cpumf/lspai.c
Normal 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
80
cpumf/man/lspai.8
Normal 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)
|
||||
@@ -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.
|
||||
|
||||
39
cpumf/pai.c
39
cpumf/pai.c
@@ -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(¶m, 0, sizeof(param));
|
||||
param.sched_priority = strtoul(prio, &endstr, 0);
|
||||
if (*endstr)
|
||||
errno = EINVAL;
|
||||
if (*endstr || sched_setscheduler(0, SCHED_FIFO, ¶m))
|
||||
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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
#
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
145
include/dump/s390_dump.h
Normal 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 */
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 @} */
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
28
libap/ap.c
28
libap/ap.c
@@ -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
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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) \
|
||||
|
||||
148
libpv/cert.c
148
libpv/cert.c
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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
3
rust/.gitignore
vendored
@@ -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
|
||||
|
||||
300
rust/pvsecret/Cargo.lock → rust/Cargo.lock
generated
300
rust/pvsecret/Cargo.lock → rust/Cargo.lock
generated
@@ -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
16
rust/Cargo.toml
Normal 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
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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)?))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))?,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
611
rust/pv/src/uvsecret/user_data.rs
Normal file
611
rust/pv/src/uvsecret/user_data.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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(),);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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.
29
rust/pv/tests/assets/cert/fake_host.crt
Normal file
29
rust/pv/tests/assets/cert/fake_host.crt
Normal 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-----
|
||||
8
rust/pv/tests/assets/cert/fake_host.key
Normal file
8
rust/pv/tests/assets/cert/fake_host.key
Normal file
@@ -0,0 +1,8 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAXR6FCIgd+fjhO/WJ
|
||||
KwLTP01mBDtYkWbVE71jshjLLpZHunRpsYKbQKCwaDmMYLRrQnTxPgZH1PVKzguI
|
||||
7M7n9zyhgYkDgYYABAAT1zpBNemPCT0tEx2S9qnlPxyBgxKl6BSXghqf3MfOqQKI
|
||||
UdKEbxP0nr2QtIR/MwvBp4YhjxZ9AZtzVtXbQrULTAGlKK4qcf1IW1rYZ5S0b4dm
|
||||
vh2HbIv9wZLWKaZ/ovnvAJk949WDCbBzC3Dy1E3zCaYPefLHHNvedWX8RtFUhnTq
|
||||
mw==
|
||||
-----END PRIVATE KEY-----
|
||||
20
rust/pv/tests/assets/cert/fake_ibm.crl
Normal file
20
rust/pv/tests/assets/cert/fake_ibm.crl
Normal 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-----
|
||||
38
rust/pv/tests/assets/cert/fake_ibm.crt
Normal file
38
rust/pv/tests/assets/cert/fake_ibm.crt
Normal 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-----
|
||||
52
rust/pv/tests/assets/cert/fake_ibm.key
Normal file
52
rust/pv/tests/assets/cert/fake_ibm.key
Normal 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-----
|
||||
@@ -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-----
|
||||
|
||||
@@ -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-----
|
||||
|
||||
52
rust/pv/tests/assets/cert/fake_inter_ca.key
Normal file
52
rust/pv/tests/assets/cert/fake_inter_ca.key
Normal 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-----
|
||||
20
rust/pv/tests/assets/cert/fake_root_ca.crl
Normal file
20
rust/pv/tests/assets/cert/fake_root_ca.crl
Normal 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-----
|
||||
37
rust/pv/tests/assets/cert/fake_root_ca.crt
Normal file
37
rust/pv/tests/assets/cert/fake_root_ca.crt
Normal 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-----
|
||||
52
rust/pv/tests/assets/cert/fake_root_ca.key
Normal file
52
rust/pv/tests/assets/cert/fake_root_ca.key
Normal 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-----
|
||||
20
rust/pv/tests/assets/cert/fake_root_ca_valid.crl
Normal file
20
rust/pv/tests/assets/cert/fake_root_ca_valid.crl
Normal 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
Reference in New Issue
Block a user