mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a6657dfd1 | ||
|
|
b3dd05e16d | ||
|
|
f216862052 | ||
|
|
e4aeeef8eb | ||
|
|
c911419121 | ||
|
|
e6de495daa | ||
|
|
419d93bef7 | ||
|
|
2714f1d90e | ||
|
|
10ec3f18fc | ||
|
|
0c771423b4 | ||
|
|
f67fa03581 | ||
|
|
29db9032b3 | ||
|
|
56a55901c1 | ||
|
|
43edafd088 | ||
|
|
b1e3ee255f | ||
|
|
a69a46eafd | ||
|
|
c85b4e54dd | ||
|
|
da4b881eac | ||
|
|
9f03ddf519 | ||
|
|
a05935cca9 | ||
|
|
6f9f846bc0 | ||
|
|
603a2b1762 | ||
|
|
dcece3f980 | ||
|
|
ff19180f03 | ||
|
|
42eba67268 | ||
|
|
3cf95a1d92 | ||
|
|
5e93b53f78 | ||
|
|
360e8d4156 | ||
|
|
a048670bec | ||
|
|
4ca93aa808 | ||
|
|
9a5886c0b3 | ||
|
|
78676df2f0 | ||
|
|
224e35b600 | ||
|
|
bd52e14740 | ||
|
|
dd380942ed | ||
|
|
9ce9ed72a9 | ||
|
|
a8a87779c0 | ||
|
|
cdabf280ac | ||
|
|
33c75584cd | ||
|
|
1f68c1aaf3 | ||
|
|
6c6938d1e2 | ||
|
|
90ad42d814 | ||
|
|
cf7c74b2dc | ||
|
|
4388a6d299 | ||
|
|
44821d0586 | ||
|
|
405b2da3f3 | ||
|
|
d3ac9f3365 | ||
|
|
7535682b1b | ||
|
|
72f1a2e0a9 | ||
|
|
220f51fb98 | ||
|
|
5ab3473442 | ||
|
|
cf51aa1421 | ||
|
|
b1d44876bd | ||
|
|
c006800bd5 | ||
|
|
634095aa24 | ||
|
|
b4f575abc4 | ||
|
|
6c729fba9e | ||
|
|
71503c0e7d | ||
|
|
5c8bd68f6f | ||
|
|
927f901969 | ||
|
|
35cc35894b | ||
|
|
dfaa1791b7 | ||
|
|
52158e73fa | ||
|
|
cc6f1a6d7b | ||
|
|
866324bcd2 | ||
|
|
7fd2421a2c | ||
|
|
66581d57f3 | ||
|
|
de688f350f | ||
|
|
958ccb46c5 | ||
|
|
3ea90a2258 | ||
|
|
7d56dde24a | ||
|
|
c7d0d3c1b9 | ||
|
|
d7648875cc | ||
|
|
5fdeaab3d0 | ||
|
|
f0bf1985c3 | ||
|
|
a3a2d70603 | ||
|
|
226728731c | ||
|
|
94292dac54 | ||
|
|
278f4f6fd5 | ||
|
|
17007ab121 | ||
|
|
4f9e5d7842 | ||
|
|
8a52693acc | ||
|
|
a93146d976 | ||
|
|
187437c6c8 | ||
|
|
cdc787d92d | ||
|
|
5feee12827 | ||
|
|
cf70a27d76 | ||
|
|
5552b476bd | ||
|
|
7510b96238 | ||
|
|
778d9e436a | ||
|
|
692af4058c | ||
|
|
2565a4ca99 | ||
|
|
6d5f4a99de | ||
|
|
a9ed19285a | ||
|
|
4eb18bd6b7 | ||
|
|
cf45a6e108 | ||
|
|
a879036e3f | ||
|
|
5340d11165 | ||
|
|
162a041077 | ||
|
|
b38d5833fa | ||
|
|
ee8897f9db | ||
|
|
4f622325ef | ||
|
|
f2902a1990 | ||
|
|
9882aabe44 | ||
|
|
d06d197522 | ||
|
|
3fd07bb7f2 | ||
|
|
58ede126cc | ||
|
|
e4a03c6f71 | ||
|
|
c66495888d | ||
|
|
f85c8ebba0 | ||
|
|
e4e455630b | ||
|
|
d82beef937 | ||
|
|
c3e61e5e0f | ||
|
|
f04e46baf0 | ||
|
|
e93bd7e61c | ||
|
|
edf40976f0 | ||
|
|
e557f41c6e | ||
|
|
68fe816da9 | ||
|
|
367ca6e16b | ||
|
|
6c67f05ca7 | ||
|
|
4887e80995 | ||
|
|
74a338edfc | ||
|
|
8878ba4fd2 | ||
|
|
e53f5ccfea | ||
|
|
6e7eb62ea1 | ||
|
|
2bb61f96c0 | ||
|
|
a902fd9afe | ||
|
|
dc42460d82 | ||
|
|
6689e25865 | ||
|
|
20f6791fb4 | ||
|
|
f0a148fd0b | ||
|
|
390e48869e | ||
|
|
3635a19462 | ||
|
|
584e785f5c | ||
|
|
7fffdcfe8c | ||
|
|
44d6020774 | ||
|
|
30ce11b8da | ||
|
|
c7ab70df2c | ||
|
|
c953486dec | ||
|
|
610cc581da | ||
|
|
604c34e66b | ||
|
|
e2cd2e78c5 | ||
|
|
d04d331673 | ||
|
|
27f20495a7 | ||
|
|
679ab77b96 | ||
|
|
8bb20be528 | ||
|
|
d04ea8603d | ||
|
|
51d2c92067 | ||
|
|
7e3b8b8c16 | ||
|
|
f8fb9ce32a | ||
|
|
3d5f75d6c3 | ||
|
|
ddc8248b21 |
@@ -1,13 +1,12 @@
|
||||
edition = "2021"
|
||||
newline_style = "Unix"
|
||||
|
||||
# Unstable options that help catching some mistakes in formatting and that we may want to enable
|
||||
# when they become stable.
|
||||
#
|
||||
# They are kept here since they are useful to run from time to time.
|
||||
#comment_width = 100
|
||||
#format_code_in_doc_comments = true
|
||||
#group_imports = "StdExternalCrate"
|
||||
#normalize_comments = true
|
||||
# Unstable options that help catching some mistakes in formatting
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Module"
|
||||
use_field_init_shorthand = true
|
||||
comment_width = 100
|
||||
format_code_in_doc_comments = true
|
||||
normalize_comments = true
|
||||
wrap_comments = true
|
||||
#reorder_impl_items = true
|
||||
#wrap_comments = true
|
||||
|
||||
@@ -77,7 +77,6 @@ List of all individuals having contributed content to s390-tools
|
||||
- Jean-Baptiste Joret
|
||||
- Jens Remus
|
||||
- Jochen Roehrig
|
||||
- Joern Siglen
|
||||
- Juergen Christ
|
||||
- Julian Wiedmann
|
||||
- Jörn Siglen
|
||||
@@ -135,6 +134,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Steffen Eiden
|
||||
- Steffen Maier
|
||||
- Steffen Thoss
|
||||
- Stephen Gallagher
|
||||
- Sumanth Korikkar
|
||||
- Susanne Wintenberger
|
||||
- Sven Schnelle
|
||||
@@ -148,6 +148,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Thomas Spatzier
|
||||
- Thomas Weber
|
||||
- Thorsten Winkler
|
||||
- Timo Keller
|
||||
- Tobias Huschle
|
||||
- Tuan Hoang
|
||||
- Ursula Braun
|
||||
|
||||
50
CHANGELOG.md
50
CHANGELOG.md
@@ -1,6 +1,56 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
|
||||
* __v2.43.1 (2026-07-22)__
|
||||
|
||||
For Linux kernel version: 7.1
|
||||
|
||||
Changes of existing tools:
|
||||
- dasdfmt: Check disk type before prompting for blocksize
|
||||
- iucvterm/ts-shell: Introduce config parameter to specify iucvconn binary
|
||||
- iucvterm/ts-shell: Introduce pager config to replace env variable
|
||||
- pv: Add root CA organization pinning to certificate verification
|
||||
- zdump/ngdump: Use OpenSSL's SHA256 to compute digest of dump image
|
||||
|
||||
Bug Fixes:
|
||||
- 95sel-ebc: Add udev-settle dependency
|
||||
- 95sel-ebc: Add umount to boot service
|
||||
- 95sel-ebc: Harden boot mount service
|
||||
- fdasd: Fix memory leak in yes_no() function
|
||||
- iucvterm/iucvtty: Ensure PTY and server fd's are closed at exec
|
||||
- iucvterm/iucvtty: Prevent connection stalls when receiving TERM env
|
||||
- iucvterm/iucvtty: Validate TERM environment name
|
||||
- libkmipclient: Protect from symlink-following attacks
|
||||
- libkmipclient: Various bugfixes
|
||||
- libseckey: Protect from symlink-following attacks
|
||||
- libseckey: Various bugfixes
|
||||
- mon_procd: Fix possible static buffer overflow
|
||||
- osasnmpd: Fix SNMP non-compliance
|
||||
- zdev: Harden against invalid udev, import, firmware, or hypervisor data
|
||||
- zipl-editenv: Check in-bootmap environment block validity
|
||||
- zipl/boot: Check in-bootmap environment block syntax
|
||||
- zipl: Check keyword duplications in BLS entries
|
||||
- zipl: Fix bugs in mirror support
|
||||
- zkey: Protect from symlink-following attacks
|
||||
|
||||
* __v2.43.0 (2026-06-25)__
|
||||
|
||||
For Linux kernel version: 7.1
|
||||
|
||||
s390-tools: Set Rust MSRV to 1.85.0
|
||||
|
||||
Changes of existing tools:
|
||||
- dbginfo.sh: Add IBM appliance specific files
|
||||
- lshwc: Show explicitly selected unnamed counters with --hide
|
||||
- pvattest: Add firmware check version 2
|
||||
- zipl: Introduce verbosity levels of zipl session (--debug)
|
||||
- zkey: Remove the use of AF_ALG for calculating key verification patterns
|
||||
|
||||
Bug Fixes:
|
||||
- ebc: implement --version option for pvics
|
||||
- pvebc: Log services to journal+console
|
||||
- pvics: Fix virt-resize permission error
|
||||
|
||||
* __v2.42.1 (2026-05-22)__
|
||||
|
||||
For Linux kernel version: 7.0
|
||||
|
||||
@@ -713,7 +713,7 @@ static int readdir_entry(struct fst_entry *fst, off_t addr)
|
||||
*/
|
||||
static inline int strip_right(const char *str, int size)
|
||||
{
|
||||
while (str[size - 1] == 0x20)
|
||||
while (size > 0 && str[size - 1] == 0x20)
|
||||
size--;
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -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 := 42
|
||||
RELEASE := 43
|
||||
PATCHLEVEL := 1
|
||||
DISTRELEASE := build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE := $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
|
||||
@@ -406,6 +406,38 @@ static void output_times(struct time_formats date)
|
||||
}
|
||||
}
|
||||
|
||||
struct ctr_filter_match {
|
||||
bool selected;
|
||||
bool selected_by_id;
|
||||
};
|
||||
|
||||
static struct ctr_filter_match ctr_match(const char *name, const char *list,
|
||||
size_t id)
|
||||
{
|
||||
struct ctr_filter_match match = { .selected = !list };
|
||||
char *copy, *token;
|
||||
char id_str[32];
|
||||
|
||||
if (!list)
|
||||
return match;
|
||||
|
||||
snprintf(id_str, sizeof(id_str), "%zu", id);
|
||||
copy = util_strdup(list);
|
||||
for (token = strtok(copy, ","); token; token = strtok(NULL, ",")) {
|
||||
if (name && strcmp(token, name) == 0) {
|
||||
match.selected = true;
|
||||
break;
|
||||
}
|
||||
if (strcmp(token, id_str) == 0) {
|
||||
match.selected = true;
|
||||
match.selected_by_id = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(copy);
|
||||
return match;
|
||||
}
|
||||
|
||||
static void prepare_counter(size_t id, unsigned long value)
|
||||
{
|
||||
if (output_format == FMT_CSV) {
|
||||
@@ -438,9 +470,14 @@ static void output_per_cpu(struct time_formats date)
|
||||
util_fmt_obj_start(FMT_LIST, "counters");
|
||||
}
|
||||
for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
|
||||
struct ctr_filter_match match;
|
||||
|
||||
if (!ctrname[i].hitcnt)
|
||||
continue;
|
||||
if (hideundef && !ctrname[i].name)
|
||||
match = ctr_match(ctrname[i].name, ctrlist, i);
|
||||
if (!match.selected)
|
||||
continue;
|
||||
if (hideundef && !ctrname[i].name && !match.selected_by_id)
|
||||
continue;
|
||||
prepare_counter(i, ctrname[i].ccv[h]);
|
||||
}
|
||||
@@ -462,9 +499,14 @@ static void output_total(struct time_formats date)
|
||||
util_fmt_obj_start(FMT_LIST, "counters");
|
||||
}
|
||||
for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
|
||||
struct ctr_filter_match match;
|
||||
|
||||
if (!ctrname[i].hitcnt)
|
||||
continue;
|
||||
if (hideundef && !ctrname[i].name)
|
||||
match = ctr_match(ctrname[i].name, ctrlist, i);
|
||||
if (!match.selected)
|
||||
continue;
|
||||
if (hideundef && !ctrname[i].name && !match.selected_by_id)
|
||||
continue;
|
||||
prepare_counter(i, ctrname[i].total);
|
||||
ctrname[i].total = 0;
|
||||
|
||||
@@ -1566,6 +1566,8 @@ int main(int argc, char *argv[])
|
||||
g.ese = dasd_sys_ese(g.dev_node);
|
||||
eval_format_mode();
|
||||
|
||||
check_disk();
|
||||
|
||||
/* Either let the user specify the blksize or get it from the kernel */
|
||||
if (!g.blksize_specified) {
|
||||
if (!(mode == FULL ||
|
||||
@@ -1587,8 +1589,6 @@ int main(int argc, char *argv[])
|
||||
error("VOLSER not found on device %s", g.dev_path);
|
||||
}
|
||||
|
||||
check_disk();
|
||||
|
||||
if (check_param(str, ERR_LENGTH, &format_params) < 0)
|
||||
error("%s", str);
|
||||
|
||||
|
||||
@@ -495,6 +495,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
||||
fprintf(stderr,
|
||||
"Error: Device name was truncated\n");
|
||||
free(path);
|
||||
free(readbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -504,6 +505,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
||||
|
||||
closedir(directory);
|
||||
free(path);
|
||||
free(readbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -387,20 +387,28 @@ static int yes_no(char *question_str)
|
||||
ssize_t bytes_read;
|
||||
char *answer;
|
||||
size_t size;
|
||||
int rc;
|
||||
|
||||
size = 0;
|
||||
answer = NULL;
|
||||
while (1) {
|
||||
printf("%s (y/n): ", question_str);
|
||||
bytes_read = getline(&answer, &size, stdin);
|
||||
if (bytes_read < 0)
|
||||
return -1;
|
||||
if (answer[0] == 'y')
|
||||
return 0;
|
||||
if (answer[0] == 'n')
|
||||
return 1;
|
||||
if (bytes_read < 0) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (answer[0] == 'y') {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
if (answer[0] == 'n') {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(answer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static char *fdasd_partition_type(char *dsname)
|
||||
|
||||
@@ -514,7 +514,7 @@ static int hmcdrv_path_copy(struct hmcdrv_fuse_file *fp, char *dest)
|
||||
char *src = HMCDRV_FUSE_PATH(fp);
|
||||
int len = 0;
|
||||
|
||||
while ((len < (HMCDRV_FUSE_MAXPATH - 1)) &&
|
||||
while ((len < (HMCDRV_FUSE_MAXPATH - 2)) &&
|
||||
(*src != '\0')) {
|
||||
|
||||
*dest = *src;
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
_x > _y ? _x : _y; \
|
||||
})
|
||||
|
||||
#ifdef __SIZEOF_INT128__
|
||||
typedef unsigned __int128 u128 __aligned(16);
|
||||
#endif
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long s64;
|
||||
typedef unsigned int u32;
|
||||
|
||||
@@ -14,14 +14,19 @@ use strict;
|
||||
use warnings;
|
||||
use File::Basename;
|
||||
use Getopt::Long qw(:config no_ignore_case);
|
||||
use Scalar::Util qw(tainted);
|
||||
use Term::ReadLine;
|
||||
use POSIX;
|
||||
|
||||
$ENV{'PERL5LIB'} = "";
|
||||
$ENV{'PERL5OPT'} = "";
|
||||
$ENV{'PERLLIB'} = "";
|
||||
$ENV{'PERL_USE_UNSAFE_INC'} = "";
|
||||
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||
|
||||
$ENV{'PERL_RL'} = " o=0"; # use best avail. readline
|
||||
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
$ENV{'LESSSECURE'} = 1; # let less run in "secure" mode
|
||||
$ENV{'PAGER'} = $ENV{'PAGER'} || "/usr/bin/less";
|
||||
my $ts_shell = fileparse($0, qr/\.[^.]+/);
|
||||
$SIG{__WARN__} = sub { print STDERR "$ts_shell: $_[0]"; };
|
||||
$SIG{__DIE__} = sub { print STDERR "$ts_shell: $_[0]"; exit 255; };
|
||||
@@ -36,6 +41,7 @@ my %config = (
|
||||
'auditdir' => "@var_path@/log/ts-shell",
|
||||
'iucvconn' => "@iucvconn_path@/iucvconn",
|
||||
'prompt' => getpwuid($>) . '@'."$ts_shell> ",
|
||||
'pager' => "/usr/bin/less",
|
||||
# runtime options
|
||||
'rl' => undef, # terminal readline (rl)
|
||||
'user' => getpwuid($>), # user name
|
||||
@@ -65,6 +71,7 @@ sub cmd_list(\%);
|
||||
sub rl_cmd_completion($$$);
|
||||
sub list_regex_match($);
|
||||
sub updateConfiguration(\%$);
|
||||
sub checkConfiguration(\%);
|
||||
sub loadAuthorization(\%);
|
||||
sub readFile($$);
|
||||
sub log_debug($);
|
||||
@@ -103,6 +110,7 @@ sub main()
|
||||
"$config{conffile} failed: $!";
|
||||
exit 3;
|
||||
}
|
||||
checkConfiguration(%config);
|
||||
|
||||
# load list of systems the ts-shell is allowed to use; and
|
||||
# hash the systems names in uppercase
|
||||
@@ -185,11 +193,50 @@ sub updateConfiguration(\%$)
|
||||
{
|
||||
my ($cfg, $line) = @_;
|
||||
my ($option, $value) = split /\s*=\s*/, $line;
|
||||
|
||||
|
||||
$cfg->{sysfile} = $value if $option =~ /^ts-systems$/;
|
||||
$cfg->{authfile} = $value if $option =~ /^ts-authorization$/;
|
||||
$cfg->{auditdir} = $value if $option =~ /^transcript-directory$/;
|
||||
$cfg->{auditfile} = $value if $option =~ /^transcript-systems$/;
|
||||
$cfg->{pager} = $value if $option =~ /^pager$/;
|
||||
$cfg->{iucvconn} = $value if $option =~ /^iucvconn$/;
|
||||
}
|
||||
|
||||
# checkConfiguration() - Validate and untaint configuration values
|
||||
#
|
||||
# Called once after readFile() has finished populating %cfg from
|
||||
# ts-shell.conf. Validates each security-sensitive path and untaints
|
||||
# it via a regex capture so Perl taint mode permits later filesystem use.
|
||||
#
|
||||
# %cfg: Hash reference to terminal server configuration
|
||||
#
|
||||
sub checkConfiguration(\%)
|
||||
{
|
||||
my $cfg = shift;
|
||||
|
||||
# Validate pager to untaint for later use
|
||||
unless ($cfg->{pager} =~ m#^(/[\w./-]+)$#) {
|
||||
log_error "Invalid pager configuration";
|
||||
exit 6;
|
||||
}
|
||||
$cfg->{pager} = $1;
|
||||
|
||||
# Validate iucvconn path to untaint for later use
|
||||
unless ($cfg->{iucvconn} =~ m#^(/[\w./-]+)$#) {
|
||||
log_error "Invalid iucvconn configuration";
|
||||
exit 7;
|
||||
}
|
||||
$cfg->{iucvconn} = $1;
|
||||
|
||||
# Validate transcript-directory to untaint for later use
|
||||
unless ($cfg->{auditdir} =~ m#^(/[\w./-]+)$#) {
|
||||
log_error "Invalid transcript-directory configuration";
|
||||
exit 8;
|
||||
}
|
||||
$cfg->{auditdir} = $1;
|
||||
|
||||
# Untaint user name (tainted by getpwuid) for use in filesystem paths
|
||||
($cfg->{user}) = ($cfg->{user} =~ /^([\w.-]+)$/);
|
||||
}
|
||||
|
||||
# loadAuthorization() - Load system authorizations from file
|
||||
@@ -205,7 +252,7 @@ sub loadAuthorization(\%)
|
||||
{
|
||||
my $cfg = shift();
|
||||
|
||||
return 0 unless open(AUTH, "<$cfg->{authfile}");
|
||||
return 0 unless open(AUTH, "<", $cfg->{authfile});
|
||||
|
||||
AUTH_ENT: while (<AUTH>) {
|
||||
chomp;
|
||||
@@ -217,13 +264,13 @@ sub loadAuthorization(\%)
|
||||
my ($key, $val) = split /\s*=\s*/;
|
||||
|
||||
# read authorization configuration for user and its groups
|
||||
if ($key =~ /^$cfg->{user}$/) {
|
||||
if ($key =~ /^\Q$cfg->{user}\E$/) {
|
||||
$authorized = 1;
|
||||
log_debug "Found user: $key";
|
||||
|
||||
} elsif ($key =~ /^@(\S+)$/) {
|
||||
my $group = $1;
|
||||
$authorized = 1 if grep {/^${group}$/} @{$cfg->{groups}};
|
||||
$authorized = 1 if grep {/^\Q${group}\E$/} @{$cfg->{groups}};
|
||||
log_debug "Found group: $key" if $authorized;
|
||||
}
|
||||
|
||||
@@ -303,7 +350,7 @@ sub readFile($$)
|
||||
{
|
||||
my ($file, $sub) = @_;
|
||||
|
||||
return 0 unless open(CONF, "<$file");
|
||||
return 0 unless open(CONF, "<", "$file");
|
||||
while (<CONF>) {
|
||||
chomp;
|
||||
next if /^#/; # ignore comments
|
||||
@@ -392,7 +439,15 @@ sub get_auditlog_file($$$)
|
||||
}
|
||||
}
|
||||
|
||||
$$filepath = "$cfg->{auditdir}/$cfg->{user}/" . uc $guest . "_";
|
||||
# validate and sanitize guest directory
|
||||
$guest = uc $guest;
|
||||
unless ($guest =~ /^([A-Z0-9@#\$_-]{1,8})$/) {
|
||||
log_error "Creating session file path failed for guest: $guest";
|
||||
return 0; # return error
|
||||
}
|
||||
|
||||
# construct the file path
|
||||
$$filepath = "$cfg->{auditdir}/$cfg->{user}/" . $guest . "_";
|
||||
$$filepath .= strftime '%F-%H%M%S', localtime;
|
||||
|
||||
log_debug "Session transcript file: $$filepath";
|
||||
@@ -416,7 +471,7 @@ sub cmd_connect($\%)
|
||||
}
|
||||
|
||||
my ($guest, $srv) = split /\s+/, $params;
|
||||
$service = $srv if $srv && $srv =~ /\w{1,8}/;
|
||||
$service = $srv if $srv && $srv =~ /^\w{1,8}$/;
|
||||
|
||||
# check authorization:
|
||||
# The auth_func contract is to return a code, that must be one of:
|
||||
@@ -482,7 +537,7 @@ sub cmd_service($\%)
|
||||
return;
|
||||
}
|
||||
|
||||
if ($new =~ /\w{1,8}/) {
|
||||
if ($new =~ /^\w{1,8}$/) {
|
||||
$cfg->{service} = $new;
|
||||
# push new service for cmd completion
|
||||
unless (grep /$new/, @{$cfg->{services}}) {
|
||||
@@ -545,7 +600,7 @@ sub pager($)
|
||||
{
|
||||
my $eval = shift();
|
||||
|
||||
unless (open(PAGER, "|$ENV{'PAGER'}")) {
|
||||
unless (open(PAGER, '|-', "$config{'pager'}")) {
|
||||
eval &$eval;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.\" ts-shell.1
|
||||
.\"
|
||||
.\"
|
||||
.\" Copyright IBM Corp. 2008, 2017
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\" Copyright IBM Corp.
|
||||
.\" ----------------------------------------------------------------------
|
||||
.TH "ts-shell" "1" "March 2009" "s390-tools" "Terminal Server over IUCV"
|
||||
.
|
||||
@@ -269,6 +268,10 @@ session transcripts are saved.
|
||||
|
||||
See section "Configure terminal session transcripts" for details.
|
||||
.
|
||||
.TP
|
||||
.BR pager " = " \fI/usr/bin/less\fP
|
||||
Specifies the path to a pager program to paginate output of ts-shell commands.
|
||||
.
|
||||
.RE
|
||||
.
|
||||
.
|
||||
@@ -542,14 +545,6 @@ Directory for saving terminal session transcripts.
|
||||
.
|
||||
.SH "ENVIRONMENT"
|
||||
.TP
|
||||
.B PAGER
|
||||
The \fBPAGER\fP environment variable designates a program used as pager for the
|
||||
\fBlist\fP command of the terminal server shell.
|
||||
If \fBPAGER\fP is not set or empty,
|
||||
.BR less (1)
|
||||
is used.
|
||||
.
|
||||
.TP
|
||||
.B LESSSECURE
|
||||
\fBts-shell\fP sets this variable to run
|
||||
.BR less (1)
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
#
|
||||
# See ts-shell(1) manual page for file format syntax.
|
||||
|
||||
# Generic settings
|
||||
# ----------------
|
||||
|
||||
# pager
|
||||
# binary to paginate output (default: less)
|
||||
#pager = /usr/bin/less
|
||||
|
||||
# System and authorization settings
|
||||
# ---------------------------------
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
/* Message buffer: message header + 4096 bytes of data */
|
||||
#define MSG_BUFFER_SIZE (MSG_DATA_OFFSET + (4096))
|
||||
|
||||
/* Message data sizes */
|
||||
#define MAX_TERM_SIZE 256
|
||||
|
||||
/* Error macros */
|
||||
#define print_error(s) program_error(PRG_COMPONENT, (s))
|
||||
#define iucvtty_error(m) \
|
||||
@@ -55,13 +58,14 @@ extern int iucvtty_read_data(int, struct iucvtty_msg *, size_t);
|
||||
|
||||
extern int iucvtty_read_msg(int, struct iucvtty_msg *, size_t, size_t *);
|
||||
extern int iucvtty_write_msg(int, struct iucvtty_msg *);
|
||||
extern void iucvtty_skip_msg_residual(int, size_t *);
|
||||
extern void iucvtty_skip_msg_chunk(int, size_t *);
|
||||
|
||||
extern ssize_t __write(int, const void*, size_t);
|
||||
|
||||
extern int strmatch(const char *, const char *);
|
||||
extern int is_regex_valid(const char *);
|
||||
extern int is_client_allowed(const char *, const struct iucvterm_cfg *);
|
||||
extern int is_term_valid(const char *term, size_t len);
|
||||
extern void userid_cpy(char [9], const char [8]);
|
||||
|
||||
extern void iucv_msg_error(const char *, uint32_t);
|
||||
|
||||
@@ -86,7 +86,7 @@ static inline struct iucvtty_msg *msg_alloc(uint8_t type, uint16_t size)
|
||||
{
|
||||
struct iucvtty_msg *m;
|
||||
|
||||
m = malloc(size + MSG_DATA_OFFSET);
|
||||
m = calloc(1, size + MSG_DATA_OFFSET);
|
||||
if (m != NULL) {
|
||||
m->version = MSG_VERSION;
|
||||
m->type = type;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
@@ -36,7 +38,7 @@
|
||||
* @len: Buffer length
|
||||
*
|
||||
* Write @len number of bytes from the buffer @buf to the file
|
||||
* descriptor @fd. The routines handles EINTR and partially writes.
|
||||
* descriptor @fd. The routine handles EINTR and partial writes.
|
||||
* Returns the error code from the underlying write(2) syscall.
|
||||
*/
|
||||
ssize_t __write(int fd, const void *buf, size_t len)
|
||||
@@ -55,6 +57,33 @@ ssize_t __write(int fd, const void *buf, size_t len)
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* __read() - Read data
|
||||
* @fd: File descriptor
|
||||
* @buf: Pointer to data buffer
|
||||
* @len: Buffer size
|
||||
*
|
||||
* Read up to @len number of bytes from file descriptor @fd and stores them
|
||||
* in the buffer to which @buf points.
|
||||
* The routine handles EINTR and partial reads and returns the error code
|
||||
* from the underlying read(2) syscall.
|
||||
*/
|
||||
ssize_t __read(int fd, void *buf, size_t len)
|
||||
{
|
||||
ssize_t rc;
|
||||
size_t count = 0;
|
||||
|
||||
while (count < len) {
|
||||
rc = read(fd, buf + count, len - count);
|
||||
if (rc == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (rc <= 0)
|
||||
return rc;
|
||||
count += rc;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef __DEBUG__
|
||||
static void __dump_msg(int fd, const struct iucvtty_msg *m, char dir)
|
||||
{
|
||||
@@ -116,14 +145,16 @@ int iucvtty_tx_termenv(int dest, char *dflt)
|
||||
|
||||
len = 0;
|
||||
if (term != NULL)
|
||||
len = 1 + strlen(term);
|
||||
len = MIN(1 + strlen(term), (size_t)MAX_TERM_SIZE);
|
||||
|
||||
/* Note: The server console tool waits for terminal environment
|
||||
* information: the message is sent even if it is empty */
|
||||
msg = msg_alloc(MSG_TYPE_TERMENV, len);
|
||||
if (msg == NULL)
|
||||
return -1;
|
||||
msg_cpy_from(msg, term, len);
|
||||
msg->datalen = len;
|
||||
if (msg->datalen)
|
||||
snprintf((char *)msg->data, msg->datalen, "%s", term);
|
||||
rc = iucvtty_write_msg(dest, msg);
|
||||
msg_free(msg);
|
||||
|
||||
@@ -146,12 +177,14 @@ int iucvtty_rx_termenv(int fd, void *buf, size_t len)
|
||||
return -1;
|
||||
skip = 0;
|
||||
rc = iucvtty_read_msg(fd, msg, msg_size(msg), &skip);
|
||||
iucvtty_skip_msg_residual(fd, &skip);
|
||||
iucvtty_skip_msg_chunk(fd, &skip);
|
||||
if (!rc) {
|
||||
if (msg->datalen == 0)
|
||||
if (msg->datalen == 0) {
|
||||
memset(buf, 0, MIN(1u, len));
|
||||
else
|
||||
} else {
|
||||
msg_cpy_to(msg, buf, len);
|
||||
memset(buf + MIN(msg->datalen, len - 1), 0, 1);
|
||||
}
|
||||
}
|
||||
msg_free(msg);
|
||||
return rc;
|
||||
@@ -262,93 +295,175 @@ int iucvtty_copy_data(int dest, struct iucvtty_msg *msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* iucvtty_skip_msg_residual() - Skip (receive & forget) count number of bytes
|
||||
* iucvtty_skip_msg_chunk() - Skip (receive & forget) count number of bytes
|
||||
* @fd: File descriptor
|
||||
* @residual: Residual of an iucv tty message received by iucvtty_read_msg()
|
||||
* @chunk: Remaining chunk from a previous iucvtty_read_msg() call
|
||||
*
|
||||
* See iucvtty_read_msg() for an explanation when to use this routine.
|
||||
* Note: The @residual parameter shall not be NULL.
|
||||
* Note: The @chunk parameter must not be NULL.
|
||||
*/
|
||||
void iucvtty_skip_msg_residual(int fd, size_t *residual)
|
||||
void iucvtty_skip_msg_chunk(int fd, size_t *chunk)
|
||||
{
|
||||
char b;
|
||||
size_t i;
|
||||
int r;
|
||||
char buf[256];
|
||||
|
||||
if (*residual <= 0)
|
||||
if (*chunk <= 0)
|
||||
return;
|
||||
for (i = 0; i < *residual; i++)
|
||||
if (read(fd, &b, 1) <= 0)
|
||||
|
||||
while (*chunk) {
|
||||
r = __read(fd, buf, MIN(sizeof(buf), *chunk));
|
||||
if (r <= 0)
|
||||
break;
|
||||
*residual = 0;
|
||||
*chunk -= r;
|
||||
}
|
||||
|
||||
*chunk = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iucvtty_read_msg_chunk() - Read IUCV message chunk
|
||||
* @fd: File descriptor to read from
|
||||
* @msg: Pointer to IUCV message buffer
|
||||
* @msglen: IUCV message buffer size (including message header)
|
||||
* @chunk: Size of chunk data to read
|
||||
*
|
||||
* Stores new message data and calculates next chunk size if not all data
|
||||
* could be read. Returns zero on success, non-zero otherwise.
|
||||
*/
|
||||
static int iucvtty_read_msg_chunk(int fd, struct iucvtty_msg *msg,
|
||||
size_t msglen, size_t *chunk)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t datalen;
|
||||
|
||||
/* Calculate message data length to read */
|
||||
datalen = MIN(msglen - MSG_DATA_OFFSET, *chunk);
|
||||
|
||||
for (;;) {
|
||||
r = read(fd, msg->data, datalen);
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (r <= 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update message and re-calculate next chunk */
|
||||
msg->datalen = r;
|
||||
*chunk -= r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_msg() - Perform sanity checks on a received message
|
||||
* @msg: IUCV message buffer
|
||||
*
|
||||
* Returns zero if the message is valid; otherwise non-zero
|
||||
*/
|
||||
static int validate_msg(struct iucvtty_msg *msg)
|
||||
{
|
||||
switch (msg->type) {
|
||||
case MSG_TYPE_DATA:
|
||||
/* The datalen ranges from 0 to its maximum of 0xffff
|
||||
* which is the maximum of the type definition of uint16_t.
|
||||
*
|
||||
* Consider the datalen value as valid.
|
||||
*/
|
||||
break;
|
||||
case MSG_TYPE_ERROR:
|
||||
if (msg->datalen != sizeof(uint32_t))
|
||||
return 1;
|
||||
break;
|
||||
case MSG_TYPE_TERMENV:
|
||||
if (msg->datalen > MAX_TERM_SIZE)
|
||||
return 1;
|
||||
break;
|
||||
case MSG_TYPE_TERMIOS: /* ignored */
|
||||
break;
|
||||
case MSG_TYPE_WINSIZE:
|
||||
if (msg->datalen != sizeof(struct winsize))
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
/* Invalid message type */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iucvtty_read_msg() - Read/Receive an IUCV message
|
||||
* @fd: File descriptor to read from
|
||||
* @msg: Pointer to IUCV message buffer
|
||||
* @len: IUCV message data len
|
||||
* @residual: Status to be used by next call
|
||||
* @msglen: IUCV message buffer size (MUST BE > MSG_DATA_OFFSET)
|
||||
* @chunk: Size of remaining data; must be passed on next call
|
||||
*
|
||||
* The function reads up to @len bytes from file descriptor @fd.
|
||||
* If the received message is larger than @len bytes, the @residual value
|
||||
* is set to the number of bytes remaining.
|
||||
* The function shall then be re-called to create a new message and receive
|
||||
* the next chunk of size @residual; or the remaining characters must be
|
||||
* skipped using the iucvtty_skip_msg() routine.
|
||||
* Note: The @len parameter shall be greater than MSG_DATA_OFFSET.
|
||||
* The @residual parameter shall not be NULL.
|
||||
* The function reads up to @len bytes from file descriptor @fd. If the
|
||||
* received message is larger than @len bytes, the @chunk value is set to
|
||||
* the number of remaining bytes. The function shall then be re-called to
|
||||
* create a new message and receive the outstanding data. Alternatively,
|
||||
* call iucvtty_skip_msg_chunk() to discard remaining data.
|
||||
*
|
||||
* NOTE: The @len parameter must be greater than MSG_DATA_OFFSET!
|
||||
* The @chunk parameter must not be NULL.
|
||||
*/
|
||||
int iucvtty_read_msg(int fd, struct iucvtty_msg *msg,
|
||||
size_t len, size_t *residual)
|
||||
size_t msglen, size_t *chunk)
|
||||
{
|
||||
int rc;
|
||||
ssize_t r; /* number of bytes read from fd */
|
||||
|
||||
if (*residual)
|
||||
len = MIN(len - MSG_DATA_OFFSET, *residual);
|
||||
/* Ensure message buffer size can hold data and can be processed */
|
||||
assert(msglen > MSG_DATA_OFFSET);
|
||||
assert(chunk != NULL);
|
||||
|
||||
while (1) {
|
||||
if (*residual) {
|
||||
r = read(fd, msg->data, len);
|
||||
if (r > 0)
|
||||
msg->datalen = r;
|
||||
} else
|
||||
r = read(fd, msg, len);
|
||||
/* Read pending message data */
|
||||
if (*chunk)
|
||||
return iucvtty_read_msg_chunk(fd, msg, msglen, chunk);
|
||||
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (r <= 0) {
|
||||
rc = -1;
|
||||
goto out_read_error;
|
||||
}
|
||||
|
||||
break; /* exit loop for a successful read */
|
||||
/* Read message header of new message */
|
||||
r = __read(fd, msg, MSG_DATA_OFFSET);
|
||||
if (r <= 0) {
|
||||
rc = -1;
|
||||
goto out_read_error;
|
||||
}
|
||||
|
||||
#ifdef __DEBUG__
|
||||
if (!*residual)
|
||||
__dump_msg(fd, msg, 'R');
|
||||
__dump_msg(fd, msg, 'R');
|
||||
#endif
|
||||
|
||||
/* (re)calculate next chunk */
|
||||
if (*residual)
|
||||
*residual -= msg->datalen;
|
||||
else
|
||||
if (msg->datalen > (r - MSG_DATA_OFFSET)) {
|
||||
/* calculate pending msg data and update datalen */
|
||||
*residual = msg->datalen - (r - MSG_DATA_OFFSET);
|
||||
msg->datalen = r - MSG_DATA_OFFSET;
|
||||
}
|
||||
|
||||
/* check for a sane message */
|
||||
/* Check message header */
|
||||
if (msg->version != MSG_VERSION) {
|
||||
fprintf(stderr, _("%s: %s\n"),
|
||||
PRG_COMPONENT, _("The version of the received data "
|
||||
"message is not supported\n"));
|
||||
"message is not supported"));
|
||||
fprintf(stderr, "MSG: msg->version=%u msg->type=%u msg->datalen=%u\n",
|
||||
msg->version, msg->type, msg->datalen);
|
||||
rc = -2;
|
||||
goto out_read_error;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
/* Check for an empty message */
|
||||
if (!msg->datalen)
|
||||
return 0;
|
||||
|
||||
/* Check message type and data length */
|
||||
if (validate_msg(msg)) {
|
||||
fprintf(stderr, _("%s: %s\n"),
|
||||
PRG_COMPONENT, _("The received message is invalid"));
|
||||
fprintf(stderr, "MSG: msg->version=%u msg->type=%u msg->datalen=%u\n",
|
||||
msg->version, msg->type, msg->datalen);
|
||||
rc = -3;
|
||||
goto out_read_error;
|
||||
}
|
||||
|
||||
/* Process the new message as a one chunk */
|
||||
*chunk = msg->datalen;
|
||||
msg->datalen = 0;
|
||||
rc = iucvtty_read_msg_chunk(fd, msg, msglen, chunk);
|
||||
|
||||
out_read_error:
|
||||
return rc;
|
||||
}
|
||||
@@ -501,6 +616,31 @@ int is_client_allowed(const char *client, const struct iucvterm_cfg *cfg)
|
||||
return strmatch(client, cfg->client_re);
|
||||
}
|
||||
|
||||
/**
|
||||
* is_term_valid() - Validate TERM environment value
|
||||
* @term: Terminal environment name to validate
|
||||
* @len: Maximum number of characters to validate
|
||||
*/
|
||||
int is_term_valid(const char *term, size_t len)
|
||||
{
|
||||
const char *c;
|
||||
|
||||
if (term == NULL || *term == '\0')
|
||||
return 0;
|
||||
|
||||
for (c = term; *c != '\0'; c++) {
|
||||
if ((size_t)(c - term) >= len)
|
||||
return 0;
|
||||
if (!isalnum((unsigned char)*c) &&
|
||||
*c != '.' &&
|
||||
*c != '_' &&
|
||||
*c != '-')
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* userid_cpy() - Copy z/VM user ID and skip trailing spaces.
|
||||
* @dest: Destination buffer
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h>
|
||||
@@ -32,7 +33,6 @@
|
||||
|
||||
#define SYSLOG_IDENT "iucvtty"
|
||||
#define PRG_COMPONENT SYSLOG_IDENT
|
||||
#define TERM_BUFSIZE 256
|
||||
#define TERM_DEFAULT "linux"
|
||||
|
||||
|
||||
@@ -63,12 +63,46 @@ static int exec_login_prog(char *cmd[])
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* receive_term_env() - receive terminal environment with timeout
|
||||
* @term: Terminal environment variable
|
||||
* @len: Maximum characters for the terminal environment variable
|
||||
*/
|
||||
static void receive_term_env(int client, char *term, size_t len)
|
||||
{
|
||||
struct timeval tv = { .tv_sec = 0, .tv_usec = 0};
|
||||
|
||||
/* Set a temporary timeout of 10s to time out a stalling
|
||||
* client connection. Use SO_RCVTIMEO to set the timeout.
|
||||
* Using those hard coded values directly is safe as
|
||||
* SO_RCVTIMEO is not being used in other parts of iucvtty.
|
||||
*/
|
||||
tv.tv_sec = 10;
|
||||
setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
|
||||
memset(term, 0, len);
|
||||
if (iucvtty_rx_termenv(client, term, len))
|
||||
snprintf(term, len, "%s", TERM_DEFAULT);
|
||||
|
||||
tv.tv_sec = 0;
|
||||
setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
|
||||
if (!is_term_valid(term, len)) {
|
||||
print_error("Ignoring received TERM env due to invalid character(s)");
|
||||
snprintf(term, len, "%s", TERM_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iucvtty_worker() - Handle an incoming client connection
|
||||
* @client: Client file descriptor
|
||||
* @master: PTY master file descriptor
|
||||
* @slave: PTY slave file descriptor
|
||||
* @cfg: IUCV TTY configuration structure.
|
||||
*
|
||||
* Unlike the HVC IUCV terminal device driver, iucvtty expects to
|
||||
* receive the TERM environment first. This is necessary to correctly
|
||||
* set up the login program.
|
||||
*/
|
||||
static int iucvtty_worker(int client, int master, int slave,
|
||||
const struct iucvterm_cfg *cfg)
|
||||
@@ -78,15 +112,14 @@ static int iucvtty_worker(int client, int master, int slave,
|
||||
pid_t child;
|
||||
fd_set set;
|
||||
size_t chunk;
|
||||
char term_env[TERM_BUFSIZE];
|
||||
char term_env[MAX_TERM_SIZE];
|
||||
|
||||
|
||||
/* flush pending terminal data */
|
||||
tcflush(master, TCIOFLUSH);
|
||||
|
||||
/* read terminal parameters from client */
|
||||
if (iucvtty_rx_termenv(client, term_env, TERM_BUFSIZE))
|
||||
sprintf(term_env, TERM_DEFAULT);
|
||||
/* read and validate terminal parameters from client */
|
||||
receive_term_env(client, term_env, sizeof(term_env));
|
||||
|
||||
/* start login program */
|
||||
child = fork();
|
||||
@@ -113,6 +146,9 @@ static int iucvtty_worker(int client, int master, int slave,
|
||||
exit(3); /* we only reach here if exec has failed */
|
||||
}
|
||||
|
||||
/* Close slave fd to properly handle SIGHUP for the child process */
|
||||
close(slave);
|
||||
|
||||
/* setup buffers */
|
||||
msg = malloc(MSG_BUFFER_SIZE);
|
||||
if (msg == NULL) {
|
||||
@@ -226,8 +262,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* set close-on-exec for file descriptors */
|
||||
fcntl(master, F_SETFD, FD_CLOEXEC);
|
||||
fcntl(server, F_SETFD, FD_CLOEXEC);
|
||||
if (fcntl(master, F_SETFD, FD_CLOEXEC) ||
|
||||
fcntl(server, F_SETFD, FD_CLOEXEC)) {
|
||||
print_error("Setting file controls failed");
|
||||
close(server);
|
||||
rc = 1;
|
||||
goto exit_on_error;
|
||||
}
|
||||
|
||||
/* syslog */
|
||||
openlog(SYSLOG_IDENT, LOG_PID, LOG_AUTHPRIV);
|
||||
@@ -240,6 +281,7 @@ int main(int argc, char *argv[])
|
||||
client = accept(server, (struct sockaddr *) &caddr, &len);
|
||||
if (client == -1) {
|
||||
print_error("An incoming connection could not be accepted");
|
||||
close(server);
|
||||
rc = 2;
|
||||
goto exit_on_error;
|
||||
}
|
||||
@@ -256,10 +298,14 @@ int main(int argc, char *argv[])
|
||||
} else { /* client is allowed to connect */
|
||||
syslog(LOG_INFO, "Accepted client connection from %s",
|
||||
client_host);
|
||||
/* set close-on-exec for client socket */
|
||||
fcntl(client, F_SETFD, FD_CLOEXEC);
|
||||
/* close server socket */
|
||||
close(server);
|
||||
/* set close-on-exec for client socket */
|
||||
if (fcntl(client, F_SETFD, FD_CLOEXEC)) {
|
||||
print_error("Setting file controls failed");
|
||||
rc = 4;
|
||||
goto exit_on_error;
|
||||
}
|
||||
|
||||
/* setup signal handler to notify shutdown signal */
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "iucvterm/functions.h"
|
||||
@@ -114,7 +113,7 @@ static int __testReadWriteMessage_nochunks(int sv[2])
|
||||
if (iucvtty_read_msg(sv[1], msg[1], 6 + MSG_DATA_OFFSET, &residual))
|
||||
return 2;
|
||||
assert(0 == memcmp(msg[1]->data, data, msg[1]->datalen));
|
||||
iucvtty_skip_msg_residual(sv[1], &residual);
|
||||
iucvtty_skip_msg_chunk(sv[1], &residual);
|
||||
assert(0 == residual);
|
||||
/*printf("datalen=%u data='%s'\n",
|
||||
msg[1]->datalen, msg[1]->data);*/
|
||||
@@ -144,7 +143,7 @@ static int __testReadWriteMessage(int sv[2])
|
||||
/* read msg */
|
||||
if (iucvtty_read_msg(sv[1], msg[1], BUF_SIZE, &chunk))
|
||||
return 2;
|
||||
iucvtty_skip_msg_residual(sv[1], &chunk);
|
||||
iucvtty_skip_msg_chunk(sv[1], &chunk);
|
||||
|
||||
/* compare msg */
|
||||
if (__msgcmp(msg[0], msg[1]))
|
||||
|
||||
@@ -43,7 +43,7 @@ detect-openssl-version.dep:
|
||||
echo " #error openssl version 1.1 is required" >> $(TMPFILE)
|
||||
echo "#endif" >> $(TMPFILE)
|
||||
echo "static void __attribute__((unused)) test(void) {" >> $(TMPFILE)
|
||||
echo " EVP_PKEY_meth_remove(NULL);" >> $(TMPFILE)
|
||||
echo " EVP_PKEY_id(NULL);" >> $(TMPFILE)
|
||||
echo "}" >> $(TMPFILE)
|
||||
mv $(TMPFILE) $@
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ static int _ekmf_extract_pubkey(const char *cert, const char *pub_key_pem,
|
||||
goto out;
|
||||
}
|
||||
|
||||
fp = fopen(pub_key_pem, "w");
|
||||
fp = fopen_nofollow(pub_key_pem, "w");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "File '%s': %s", pub_key_pem,
|
||||
@@ -458,7 +458,7 @@ retry:
|
||||
out);
|
||||
|
||||
if (server_cert_pem != NULL) {
|
||||
fp = fopen(server_cert_pem, "w");
|
||||
fp = fopen_nofollow(server_cert_pem, "w");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "File '%s': %s", server_cert_pem,
|
||||
@@ -495,7 +495,7 @@ retry:
|
||||
*/
|
||||
if (ci->num_of_certs > 1 && ca_bundle_pem != NULL &&
|
||||
do_verify == 0) {
|
||||
fp = fopen(ca_bundle_pem, "w");
|
||||
fp = fopen_nofollow(ca_bundle_pem, "w");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "File '%s': %s",
|
||||
@@ -1415,7 +1415,7 @@ int ekmf_login(const struct ekmf_config *config, CURL **curl_handle,
|
||||
while (*tok == ' ')
|
||||
tok++;
|
||||
|
||||
fp = fopen(config->login_token, "w");
|
||||
fp = fopen_nofollow(config->login_token, "w");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
pr_verbose(verbose, "Failed to open file %s: '%s'",
|
||||
@@ -1739,7 +1739,7 @@ int ekmf_get_settings(const struct ekmf_config *config, CURL **curl_handle,
|
||||
if (xts_key2_template != NULL) {
|
||||
*xts_key2_template = _ekmf_find_setting(response_obj,
|
||||
SETTING_ID_XTS_KEY2_TEMPLATE, verbose);
|
||||
if (*identity_template == NULL) {
|
||||
if (*xts_key2_template == NULL) {
|
||||
if (error_msg != NULL) {
|
||||
if (asprintf(error_msg, "The EKMF Web setting "
|
||||
"'XTS Key Template Name (Key 2)' "
|
||||
@@ -1882,8 +1882,9 @@ int ekmf_check_feature(const struct ekmf_config *config, CURL **curl_handle,
|
||||
pr_verbose(verbose, "Feature '%s' is not installed",
|
||||
FEATURE_ID_PERVASIVE_ENCRYPTION);
|
||||
rc = -ENOTSUP;
|
||||
if (asprintf(error_msg, "EKMF Web feature "
|
||||
"'Pervasive Encryption' is not installed.")) {
|
||||
if (error_msg != NULL &&
|
||||
asprintf(error_msg, "EKMF Web feature "
|
||||
"'Pervasive Encryption' is not installed.") < 0) {
|
||||
pr_verbose(verbose, "asprintf failed");
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
@@ -1925,7 +1926,7 @@ static int _ekmf_build_party_info(const char *key_uuid, const char *timestamp,
|
||||
|
||||
if (*party_info_length < (size_t)EVP_MD_size(md)) {
|
||||
pr_verbose(verbose, "Party info buffer is too small");
|
||||
return -ERANGE;
|
||||
rc = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2219,6 +2220,11 @@ static int _ekmf_import_key(unsigned char *req_sess_key,
|
||||
unsigned char *party_info = NULL;
|
||||
int rc;
|
||||
|
||||
if (resp_party_info_length > SIZE_MAX - req_party_info_length) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
party_info_length = req_party_info_length + resp_party_info_length;
|
||||
party_info = malloc(party_info_length);
|
||||
if (party_info == NULL) {
|
||||
@@ -4547,8 +4553,9 @@ out:
|
||||
*/
|
||||
static char *_ekmf_base64_encode(const unsigned char *data, size_t data_size)
|
||||
{
|
||||
int outlen, len;
|
||||
size_t outlen;
|
||||
char *out;
|
||||
int len;
|
||||
|
||||
outlen = (data_size / 3) * 4;
|
||||
if (data_size % 3 > 0)
|
||||
@@ -4559,7 +4566,7 @@ static char *_ekmf_base64_encode(const unsigned char *data, size_t data_size)
|
||||
return NULL;
|
||||
|
||||
len = EVP_EncodeBlock((unsigned char *)out, data, data_size);
|
||||
if (len != outlen) {
|
||||
if (len < 0 || (size_t)len != outlen) {
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
@@ -4596,7 +4603,7 @@ static int _ekmf_build_key_material(const unsigned char *certificate,
|
||||
"JSON object", verbose, out);
|
||||
|
||||
payload = _ekmf_base64_encode(certificate, certificate_size);
|
||||
JSON_CHECK_ERROR(*keymat_obj == NULL, rc, -EIO,
|
||||
JSON_CHECK_ERROR(payload == NULL, rc, -EIO,
|
||||
"Failed to base64 encode the certificate",
|
||||
verbose, out);
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
@@ -104,7 +106,7 @@ int decode_base64url(unsigned char *output, size_t *outlen,
|
||||
|
||||
len = EVP_DecodeBlock((unsigned char *)padded_output,
|
||||
(unsigned char *)padded_input, padded_inlen);
|
||||
if (len != (int)padded_inlen * 3 / 4) {
|
||||
if ((size_t)len != padded_inlen * 3 / 4) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -229,8 +231,9 @@ int parse_json_web_token(const char *token, json_object **header_obj,
|
||||
size_t *signature_len)
|
||||
{
|
||||
json_object *hdr = NULL, *pld = NULL, *b64_obj = NULL;
|
||||
char *ch, *header, *payload, *json = NULL;
|
||||
size_t header_len, payload_len, json_len;
|
||||
const char *ch, *header, *payload;
|
||||
char *json = NULL;
|
||||
bool b64 = true;
|
||||
int rc = 0;
|
||||
|
||||
@@ -254,7 +257,7 @@ int parse_json_web_token(const char *token, json_object **header_obj,
|
||||
* and the following parts (if any) are used for JWS Signature, or JWE
|
||||
* Encryption (not considered here).
|
||||
*/
|
||||
header = (char *)token;
|
||||
header = token;
|
||||
|
||||
ch = strchr(token, '.');
|
||||
if (ch == NULL) {
|
||||
@@ -363,9 +366,9 @@ out:
|
||||
*payload_obj = pld;
|
||||
else
|
||||
json_object_put(pld);
|
||||
if (signature != NULL && rc != 0) {
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
if (signature != NULL && *signature != NULL && rc != 0) {
|
||||
free(*signature);
|
||||
*signature = NULL;
|
||||
*signature_len = 0;
|
||||
}
|
||||
if (json != NULL)
|
||||
@@ -653,7 +656,7 @@ int verify_json_web_signature(const char *jws, const unsigned char *payload,
|
||||
BIGNUM *bn_s = NULL;
|
||||
const char *alg;
|
||||
size_t sig_len;
|
||||
char *ch;
|
||||
const char *ch;
|
||||
|
||||
if (jws == NULL || pkey == NULL)
|
||||
return -EINVAL;
|
||||
@@ -1034,7 +1037,7 @@ int clone_tag_def_list(const struct ekmf_tag_def_list *src,
|
||||
if (src->tag_defs[i].description != NULL) {
|
||||
dest->tag_defs[i].description =
|
||||
strdup(src->tag_defs[i].description);
|
||||
if (dest->tag_defs[i].description != NULL) {
|
||||
if (dest->tag_defs[i].description == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@@ -1930,7 +1933,7 @@ int write_key_blob(const char *filename, unsigned char *key_blob,
|
||||
if (filename == NULL || key_blob == NULL || key_blob_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(filename, "w");
|
||||
fp = fopen_nofollow(filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
@@ -2051,7 +2054,7 @@ int write_x509_certificate(const char *pem_filename, X509 *cert)
|
||||
if (pem_filename == NULL || cert == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(pem_filename, "w");
|
||||
fp = fopen_nofollow(pem_filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
@@ -2085,7 +2088,7 @@ int write_x509_request(const char *pem_filename, X509_REQ *req, bool new_hdr)
|
||||
if (pem_filename == NULL || req == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(pem_filename, "w");
|
||||
fp = fopen_nofollow(pem_filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
@@ -2153,7 +2156,7 @@ int write_public_key(const char *pem_filename, EVP_PKEY *pkey)
|
||||
if (pem_filename == NULL || pkey == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(pem_filename, "w");
|
||||
fp = fopen_nofollow(pem_filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
@@ -2605,3 +2608,33 @@ int json_object_object_add_ex(struct json_object *obj, const char *const key,
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
FILE *fopen_nofollow(const char *path, const char *mode)
|
||||
{
|
||||
int flags = O_NOFOLLOW;
|
||||
int fd;
|
||||
FILE *fp;
|
||||
|
||||
/* Determine flags based on mode */
|
||||
if (mode[0] == 'r')
|
||||
flags |= (mode[1] == '+') ? O_RDWR : O_RDONLY;
|
||||
else if (mode[0] == 'w')
|
||||
flags |= O_CREAT | O_TRUNC |
|
||||
((mode[1] == '+') ? O_RDWR : O_WRONLY);
|
||||
else if (mode[0] == 'a')
|
||||
flags |= O_CREAT | O_APPEND |
|
||||
((mode[1] == '+') ? O_RDWR : O_WRONLY);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
fd = open(path, flags, 0600);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
fp = fdopen(fd, mode);
|
||||
if (fp == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
@@ -124,4 +124,6 @@ int json_object_object_add_ex(struct json_object *obj, const char *const key,
|
||||
const unsigned int opts);
|
||||
#endif
|
||||
|
||||
FILE *fopen_nofollow(const char *path, const char *mode);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,7 +46,7 @@ detect-openssl-version.dep:
|
||||
echo " #error openssl version 1.1 is required" >> $(TMPFILE)
|
||||
echo "#endif" >> $(TMPFILE)
|
||||
echo "static void __attribute__((unused)) test(void) {" >> $(TMPFILE)
|
||||
echo " EVP_PKEY_meth_remove(NULL);" >> $(TMPFILE)
|
||||
echo " EVP_PKEY_id(NULL);" >> $(TMPFILE)
|
||||
echo "}" >> $(TMPFILE)
|
||||
mv $(TMPFILE) $@
|
||||
|
||||
|
||||
@@ -735,7 +735,8 @@ int kmip_connection_https_perform(struct kmip_connection *conn,
|
||||
switch (conn->config.encoding) {
|
||||
case KMIP_ENCODING_TTLV:
|
||||
rc = kmip_decode_ttlv(write_cb.ttlv.resp_mem_bio, NULL,
|
||||
response, debug);
|
||||
response, KMIP_DECODE_MAX_NESTING_LEVEL,
|
||||
debug);
|
||||
if (rc != 0) {
|
||||
kmip_debug(debug, "kmip_decode_ttlv failed");
|
||||
goto out;
|
||||
@@ -750,7 +751,7 @@ int kmip_connection_https_perform(struct kmip_connection *conn,
|
||||
}
|
||||
|
||||
rc = kmip_decode_json(write_cb.json.resp_obj, NULL, response,
|
||||
debug);
|
||||
KMIP_DECODE_MAX_NESTING_LEVEL, debug);
|
||||
if (rc != 0) {
|
||||
kmip_debug(debug, "kmip_decode_json failed");
|
||||
goto out;
|
||||
@@ -768,7 +769,8 @@ int kmip_connection_https_perform(struct kmip_connection *conn,
|
||||
|
||||
rc = kmip_decode_xml(xmlDocGetRootElement(
|
||||
write_cb.xml.ctx->myDoc),
|
||||
NULL, response, debug);
|
||||
NULL, response,
|
||||
KMIP_DECODE_MAX_NESTING_LEVEL, debug);
|
||||
if (rc != 0) {
|
||||
kmip_debug(debug, "kmip_decode_xml failed");
|
||||
goto out;
|
||||
|
||||
@@ -27,12 +27,16 @@
|
||||
* @param parent the parent node or NULL if no parent exists.
|
||||
* @param node On return: the decoded node. The newly allocated
|
||||
* node has a reference count of 1.
|
||||
* @param max_nesting_level the maximum nesting levels of structures within the
|
||||
* KMIP node. If the nesting level is reached, E2BIG
|
||||
* is returned.
|
||||
* @param debug if true, debug messages are printed
|
||||
*
|
||||
* @returns 0 in case of success, or a negative errno value
|
||||
*/
|
||||
int kmip_decode_json(const json_object *obj, struct kmip_node *parent,
|
||||
struct kmip_node **node, bool debug)
|
||||
struct kmip_node **node, size_t max_nesting_level,
|
||||
bool debug)
|
||||
{
|
||||
json_object *tag_obj, *type_obj, *value_obj, *name_obj;
|
||||
enum kmip_tag tag, v1_attr_tag = 0;
|
||||
@@ -42,6 +46,9 @@ int kmip_decode_json(const json_object *obj, struct kmip_node *parent,
|
||||
int rc, num, i;
|
||||
int64_t int64;
|
||||
|
||||
if (max_nesting_level == 0)
|
||||
return -E2BIG;
|
||||
|
||||
if (obj == NULL || node == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -82,7 +89,7 @@ int kmip_decode_json(const json_object *obj, struct kmip_node *parent,
|
||||
rc = -EBADMSG;
|
||||
goto out;
|
||||
}
|
||||
n->name = strdup(json_object_get_string(tag_obj));
|
||||
n->name = strdup(json_object_get_string(name_obj));
|
||||
}
|
||||
|
||||
type_obj = json_object_object_get(obj, KMIP_JSON_TYPE);
|
||||
@@ -138,7 +145,7 @@ int kmip_decode_json(const json_object *obj, struct kmip_node *parent,
|
||||
for (i = 0; i < num; i++) {
|
||||
rc = kmip_decode_json(
|
||||
json_object_array_get_idx(value_obj, i),
|
||||
n, &e, debug);
|
||||
n, &e, max_nesting_level - 1, debug);
|
||||
if (rc != 0) {
|
||||
kmip_debug(debug, "Failed to parse "
|
||||
"array element %d", i);
|
||||
@@ -614,6 +621,10 @@ int kmip_encode_json(const struct kmip_node *node, json_object **obj,
|
||||
|
||||
case KMIP_TYPE_DATE_TIME:
|
||||
tm = gmtime((time_t *)&node->date_time_value);
|
||||
if (tm == NULL) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
strftime(outstr, sizeof(outstr), KMIP_ISO8601_TIMESTAMP_UTC,
|
||||
tm);
|
||||
memb_obj = json_object_new_string(outstr);
|
||||
|
||||
@@ -426,8 +426,14 @@ int kmip_get_key_value(const struct kmip_node *node,
|
||||
/* Must be a KMIP v1.x attribute then */
|
||||
kmip_node_free(attr);
|
||||
|
||||
if (num_attrs != NULL)
|
||||
*num_attrs = kmip_node_get_structure_element_count(node) - 1;
|
||||
if (num_attrs != NULL) {
|
||||
*num_attrs = kmip_node_get_structure_element_count(node);
|
||||
if (*num_attrs == 0) {
|
||||
rc = -EBADMSG;
|
||||
goto error;
|
||||
}
|
||||
(*num_attrs)--;
|
||||
}
|
||||
|
||||
if (v2_attr == NULL)
|
||||
return 0;
|
||||
|
||||
@@ -258,7 +258,7 @@ int kmip_node_add_structure_elements(struct kmip_node *node,
|
||||
*
|
||||
* @param node the KMIP node
|
||||
*
|
||||
* @returns the number of elements, or -1 if the node is not of type structure
|
||||
* @returns the number of elements, or 0 if the node is not of type structure
|
||||
*/
|
||||
unsigned int kmip_node_get_structure_element_count(const struct kmip_node *node)
|
||||
{
|
||||
@@ -266,10 +266,10 @@ unsigned int kmip_node_get_structure_element_count(const struct kmip_node *node)
|
||||
unsigned int i;
|
||||
|
||||
if (node == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
if (node->type != KMIP_TYPE_STRUCTURE)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
element = node->structure_value;
|
||||
for (i = 0; element != NULL; i++)
|
||||
@@ -319,7 +319,7 @@ struct kmip_node *kmip_node_get_structure_element_by_index(
|
||||
* @param node the KMIP node
|
||||
* @param tag the tag to find
|
||||
*
|
||||
* @returns the number of elements, or -1 if the node is not of type structure
|
||||
* @returns the number of elements, or 0 if the node is not of type structure
|
||||
*/
|
||||
unsigned int kmip_node_get_structure_element_by_tag_count(
|
||||
const struct kmip_node *node,
|
||||
@@ -329,10 +329,10 @@ unsigned int kmip_node_get_structure_element_by_tag_count(
|
||||
unsigned int i;
|
||||
|
||||
if (node == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
if (node->type != KMIP_TYPE_STRUCTURE)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
element = node->structure_value;
|
||||
for (i = 0; element != NULL; element = element->next) {
|
||||
@@ -897,7 +897,7 @@ struct kmip_node *kmip_node_clone(const struct kmip_node *node)
|
||||
case KMIP_TYPE_TEXT_STRING:
|
||||
if (node->text_value != NULL) {
|
||||
clone->text_value = strdup(node->text_value);
|
||||
if (node->text_value == NULL)
|
||||
if (clone->text_value == NULL)
|
||||
goto error;
|
||||
clone->length = strlen(clone->text_value);
|
||||
}
|
||||
@@ -1370,7 +1370,8 @@ int kmip_connection_get_server_cert(const char *server,
|
||||
struct kmip_conn_config config = { 0 };
|
||||
struct kmip_connection *conn = NULL;
|
||||
int rc, numcerts, i, port_found = 0;
|
||||
char *hostname = NULL, *tok, *tok2;
|
||||
const char *tok, *tok2;
|
||||
char *hostname = NULL;
|
||||
STACK_OF(X509) *chain;
|
||||
bool do_verify = true;
|
||||
FILE *fp = NULL;
|
||||
@@ -1488,7 +1489,7 @@ retry:
|
||||
}
|
||||
|
||||
if (i == 0 && server_cert_pem != NULL) {
|
||||
fp = fopen(server_cert_pem, "w");
|
||||
fp = fopen_nofollow(server_cert_pem, "w");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
kmip_debug(debug, "Failed to open %s for write",
|
||||
@@ -1506,7 +1507,7 @@ retry:
|
||||
fp = NULL;
|
||||
|
||||
if (server_pubkey_pem != NULL) {
|
||||
fp = fopen(server_pubkey_pem, "w");
|
||||
fp = fopen_nofollow(server_pubkey_pem, "w");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
kmip_debug(debug, "Failed to open %s "
|
||||
@@ -1532,7 +1533,7 @@ retry:
|
||||
|
||||
if (i > 0 && cert_chain_pem != NULL) {
|
||||
if (fp == NULL)
|
||||
fp = fopen(cert_chain_pem, "w");
|
||||
fp = fopen_nofollow(cert_chain_pem, "w");
|
||||
if (fp == NULL) {
|
||||
rc = -errno;
|
||||
kmip_debug(debug, "Failed to open %s for write",
|
||||
|
||||
@@ -94,19 +94,23 @@ int kmip_connection_https_perform(struct kmip_connection *connection,
|
||||
bool debug);
|
||||
void kmip_connection_https_term(struct kmip_connection *connection);
|
||||
|
||||
/* KIMP decoding and encoding internal functions */
|
||||
/* KIMP decoding and encoding internal functions and definitions */
|
||||
#define KMIP_DECODE_MAX_NESTING_LEVEL 32
|
||||
|
||||
int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node,
|
||||
bool debug);
|
||||
size_t max_nesting_level, bool debug);
|
||||
int kmip_encode_ttlv(struct kmip_node *node, BIO *bio, size_t *size,
|
||||
bool debug);
|
||||
|
||||
int kmip_decode_json(const json_object *obj, struct kmip_node *parent,
|
||||
struct kmip_node **node, bool debug);
|
||||
struct kmip_node **node, size_t max_nesting_level,
|
||||
bool debug);
|
||||
int kmip_encode_json(const struct kmip_node *node, json_object **obj,
|
||||
bool debug);
|
||||
|
||||
int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
|
||||
struct kmip_node **node, bool debug);
|
||||
struct kmip_node **node, size_t max_nesting_level,
|
||||
bool debug);
|
||||
int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -686,14 +686,20 @@ int kmip_get_get_attribute_list_response_payload(const struct kmip_node *node,
|
||||
|
||||
if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD)
|
||||
return -EBADMSG;
|
||||
if (kmip_node_get_type(node) != KMIP_TYPE_STRUCTURE)
|
||||
return -EBADMSG;
|
||||
|
||||
if (unique_id != NULL)
|
||||
*unique_id = kmip_node_get_structure_element_by_tag(node,
|
||||
KMIP_TAG_UNIQUE_IDENTIFIER, 0);
|
||||
|
||||
if (num_attr_refs != NULL)
|
||||
if (num_attr_refs != NULL) {
|
||||
*num_attr_refs =
|
||||
kmip_node_get_structure_element_count(node) - 1;
|
||||
kmip_node_get_structure_element_count(node);
|
||||
if (*num_attr_refs == 0)
|
||||
return -EBADMSG;
|
||||
(*num_attr_refs)--;
|
||||
}
|
||||
|
||||
if (attr_ref == NULL)
|
||||
return 0;
|
||||
@@ -766,6 +772,8 @@ int kmip_get_get_attributes_response_payload(const struct kmip_node *node,
|
||||
|
||||
if (kmip_node_get_tag(node) != KMIP_TAG_RESPONSE_PAYLOAD)
|
||||
return -EBADMSG;
|
||||
if (kmip_node_get_type(node) != KMIP_TYPE_STRUCTURE)
|
||||
return -EBADMSG;
|
||||
|
||||
if (unique_id != NULL)
|
||||
*unique_id = kmip_node_get_structure_element_by_tag(node,
|
||||
@@ -798,8 +806,12 @@ int kmip_get_get_attributes_response_payload(const struct kmip_node *node,
|
||||
/* Must be a KMIP v1.x attribute then */
|
||||
kmip_node_free(attr);
|
||||
|
||||
if (num_attrs != NULL)
|
||||
*num_attrs = kmip_node_get_structure_element_count(node) - 1;
|
||||
if (num_attrs != NULL) {
|
||||
*num_attrs = kmip_node_get_structure_element_count(node);
|
||||
if (*num_attrs == 0)
|
||||
return -EBADMSG;
|
||||
(*num_attrs)--;
|
||||
}
|
||||
|
||||
if (v2_attr == NULL)
|
||||
return 0;
|
||||
|
||||
@@ -493,7 +493,8 @@ int kmip_connection_tls_perform(struct kmip_connection *conn,
|
||||
kmip_debug(debug, "%lu bytes sent", size);
|
||||
|
||||
/* receive the response */
|
||||
rc = kmip_decode_ttlv(conn->plain_tls.bio, NULL, response, debug);
|
||||
rc = kmip_decode_ttlv(conn->plain_tls.bio, NULL, response,
|
||||
KMIP_DECODE_MAX_NESTING_LEVEL, debug);
|
||||
if (rc != 0 || *response == NULL) {
|
||||
kmip_debug(debug, "kmip_decode_ttlv failed");
|
||||
goto out;
|
||||
|
||||
@@ -28,12 +28,15 @@
|
||||
* as many bytes as needed.
|
||||
* @param node On return: the decoded node. The newly allocated
|
||||
* node has a reference count of 1.
|
||||
* @param max_nesting_level the maximum nesting levels of structures within the
|
||||
* KMIP node. If the nesting level is reached, E2BIG
|
||||
* is returned.
|
||||
* @param debug if true, debug messages are printed
|
||||
*
|
||||
* @returns 0 in case of success, or a negative errno value
|
||||
*/
|
||||
int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node,
|
||||
bool debug)
|
||||
size_t max_nesting_level, bool debug)
|
||||
{
|
||||
unsigned char padding[KMIP_TTLV_BLOCK_LENGTH];
|
||||
unsigned char ttlv[KMIP_TTLV_HEADER_LENGTH];
|
||||
@@ -44,6 +47,9 @@ int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node,
|
||||
uint64_t int64;
|
||||
int rc;
|
||||
|
||||
if (max_nesting_level == 0)
|
||||
return -E2BIG;
|
||||
|
||||
if (bio == NULL || node == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -73,18 +79,18 @@ int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node,
|
||||
n->ref_count = 1;
|
||||
|
||||
/* Tag: 3-byte binary unsigned integer, transmitted big endian */
|
||||
n->tag |= (uint32_t)(ttlv[0] << 16);
|
||||
n->tag |= (uint32_t)(ttlv[1] << 8);
|
||||
n->tag |= (uint32_t)(ttlv[2]);
|
||||
n->tag |= (uint32_t)ttlv[0] << 16;
|
||||
n->tag |= (uint32_t)ttlv[1] << 8;
|
||||
n->tag |= (uint32_t)ttlv[2];
|
||||
|
||||
/* Type: 1 byte containing a coded value that indicates the data type */
|
||||
n->type = ttlv[3];
|
||||
|
||||
/* Length: 32-bit binary integer, transmitted big-endian */
|
||||
n->length |= (uint32_t)(ttlv[4] << 24);
|
||||
n->length |= (uint32_t)(ttlv[5] << 16);
|
||||
n->length |= (uint32_t)(ttlv[6] << 8);
|
||||
n->length |= (uint32_t)(ttlv[7]);
|
||||
n->length |= (uint32_t)ttlv[4] << 24;
|
||||
n->length |= (uint32_t)ttlv[5] << 16;
|
||||
n->length |= (uint32_t)ttlv[6] << 8;
|
||||
n->length |= (uint32_t)ttlv[7];
|
||||
|
||||
kmip_debug(debug, "tag: 0x%x type: 0x%x, length: %u", n->tag, n->type,
|
||||
n->length);
|
||||
@@ -98,6 +104,11 @@ int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node,
|
||||
case KMIP_TYPE_TEXT_STRING:
|
||||
case KMIP_TYPE_BYTE_STRING:
|
||||
value_len = n->length;
|
||||
if (value_len > INT_MAX) {
|
||||
rc = -EMSGSIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
value = calloc(1, value_len + 1);
|
||||
if (value == NULL) {
|
||||
kmip_debug(debug, "calloc failed");
|
||||
@@ -160,14 +171,22 @@ int kmip_decode_ttlv(BIO *bio, size_t *size, struct kmip_node **node,
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
if (size != NULL)
|
||||
|
||||
if (size != NULL) {
|
||||
if (*size < pad_len) {
|
||||
rc = -EMSGSIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*size -= pad_len;
|
||||
}
|
||||
}
|
||||
|
||||
switch (n->type) {
|
||||
case KMIP_TYPE_STRUCTURE:
|
||||
while (value_len > 0) {
|
||||
rc = kmip_decode_ttlv(bio, &value_len, &e, debug);
|
||||
rc = kmip_decode_ttlv(bio, &value_len, &e,
|
||||
max_nesting_level - 1, debug);
|
||||
if (rc != 0) {
|
||||
kmip_debug(debug, "kmip_decode_ttlv failed: "
|
||||
"rc: %d", rc);
|
||||
@@ -263,7 +282,7 @@ out:
|
||||
static int kmip_node_get_length(struct kmip_node *node, size_t *length)
|
||||
{
|
||||
struct kmip_node *element;
|
||||
size_t len;
|
||||
size_t len, prev_len;
|
||||
int rc;
|
||||
|
||||
if (node == NULL || length == NULL)
|
||||
@@ -278,10 +297,13 @@ static int kmip_node_get_length(struct kmip_node *node, size_t *length)
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
prev_len = *length;
|
||||
*length += KMIP_TTLV_HEADER_LENGTH + len;
|
||||
if ((len % KMIP_TTLV_BLOCK_LENGTH) != 0)
|
||||
*length += KMIP_TTLV_BLOCK_LENGTH -
|
||||
(len % KMIP_TTLV_BLOCK_LENGTH);
|
||||
if (*length < prev_len)
|
||||
return -EOVERFLOW;
|
||||
|
||||
element = element->next;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "names.h"
|
||||
@@ -72,6 +74,8 @@ int kmip_parse_decimal_uint(const char *str, uint64_t *val)
|
||||
|
||||
if (str == NULL)
|
||||
return -EINVAL;
|
||||
if (str[0] == '-')
|
||||
return -EBADMSG;
|
||||
|
||||
errno = 0;
|
||||
v = strtoull(str, &endptr, 10);
|
||||
@@ -164,13 +168,16 @@ int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val,
|
||||
* Format a hex string from the byte array specified in val. The caller must
|
||||
* free the returned str.
|
||||
*/
|
||||
int kmip_format_hex(const unsigned char *val, uint32_t length, bool prefix,
|
||||
int kmip_format_hex(const unsigned char *val, size_t length, bool prefix,
|
||||
char **str)
|
||||
{
|
||||
uint32_t str_len, i;
|
||||
size_t str_len, i;
|
||||
char tmp[4];
|
||||
char *ret;
|
||||
|
||||
if (length > (SIZE_MAX - ((prefix ? 2 : 0) + 1)) / 2)
|
||||
return -EINVAL;
|
||||
|
||||
str_len = length * 2 + (prefix ? 2 : 0) + 1;
|
||||
ret = calloc(1, str_len);
|
||||
if (ret == NULL)
|
||||
@@ -220,14 +227,18 @@ int kmip_parse_bignum(const char *str, bool has_prefix, BIGNUM **bn)
|
||||
int kmip_format_bignum(const BIGNUM *bn, bool prefix, char **str)
|
||||
{
|
||||
unsigned char *buf;
|
||||
uint32_t len;
|
||||
uint32_t len, prev_len;
|
||||
int rc;
|
||||
|
||||
len = kmip_encode_bignum_length(bn);
|
||||
/* BIG INTEGERS must be a multiple of 8 bytes long */
|
||||
if ((len % KMIP_BIG_INTEGER_BLOCK_LENGTH) != 0)
|
||||
if ((len % KMIP_BIG_INTEGER_BLOCK_LENGTH) != 0) {
|
||||
prev_len = len;
|
||||
len += KMIP_BIG_INTEGER_BLOCK_LENGTH -
|
||||
(len % KMIP_BIG_INTEGER_BLOCK_LENGTH);
|
||||
if (len < prev_len)
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
buf = malloc(len);
|
||||
if (buf == NULL)
|
||||
@@ -402,10 +413,10 @@ int kmip_parse_mask(enum kmip_tag tag, const char *str, char separator,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int kmip_append_string(char **str, int *str_len, char separator,
|
||||
static int kmip_append_string(char **str, size_t *str_len, char separator,
|
||||
const char *append)
|
||||
{
|
||||
int new_len;
|
||||
size_t new_len;
|
||||
char *tmp;
|
||||
|
||||
if (str == NULL || str_len == NULL)
|
||||
@@ -422,6 +433,9 @@ static int kmip_append_string(char **str, int *str_len, char separator,
|
||||
if (append != NULL)
|
||||
new_len += strlen(append);
|
||||
|
||||
if (new_len < *str_len)
|
||||
return -EOVERFLOW;
|
||||
|
||||
tmp = realloc(*str, new_len);
|
||||
if (tmp == NULL)
|
||||
return -ENOMEM;
|
||||
@@ -446,8 +460,9 @@ int kmip_format_mask(enum kmip_tag tag, int32_t value, char separator,
|
||||
char **str)
|
||||
{
|
||||
const struct kmip_enum *info;
|
||||
int rc = 0, i, s_len = 0;
|
||||
char *s = NULL, *tmp;
|
||||
size_t s_len = 0;
|
||||
int rc = 0, i;
|
||||
|
||||
info = kmip_enum_info_by_tag(tag);
|
||||
if (info == NULL || value == 0)
|
||||
@@ -726,3 +741,32 @@ enum kmip_tag kmip_find_v1_attribute_name_tag(struct kmip_node *parent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *fopen_nofollow(const char *path, const char *mode)
|
||||
{
|
||||
int flags = O_NOFOLLOW;
|
||||
int fd;
|
||||
FILE *fp;
|
||||
|
||||
/* Determine flags based on mode */
|
||||
if (mode[0] == 'r')
|
||||
flags |= (mode[1] == '+') ? O_RDWR : O_RDONLY;
|
||||
else if (mode[0] == 'w')
|
||||
flags |= O_CREAT | O_TRUNC |
|
||||
((mode[1] == '+') ? O_RDWR : O_WRONLY);
|
||||
else if (mode[0] == 'a')
|
||||
flags |= O_CREAT | O_APPEND |
|
||||
((mode[1] == '+') ? O_RDWR : O_WRONLY);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
fd = open(path, flags, 0600);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
fp = fdopen(fd, mode);
|
||||
if (fp == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ int kmip_parse_decimal_uint(const char *str, uint64_t *val);
|
||||
int kmip_parse_hex_int(const char *str, int64_t *val);
|
||||
int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val,
|
||||
uint32_t *length);
|
||||
int kmip_format_hex(const unsigned char *val, uint32_t length, bool prefix,
|
||||
int kmip_format_hex(const unsigned char *val, size_t length, bool prefix,
|
||||
char **str);
|
||||
|
||||
int kmip_parse_bignum(const char *str, bool has_prefix, BIGNUM **bn);
|
||||
@@ -58,4 +58,6 @@ void kmip_node_dump(struct kmip_node *node, bool debug);
|
||||
|
||||
enum kmip_tag kmip_find_v1_attribute_name_tag(struct kmip_node *parent);
|
||||
|
||||
FILE *fopen_nofollow(const char *path, const char *mode);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,12 +28,16 @@
|
||||
* @param parent the parent node or NULL if no parent exists.
|
||||
* @param node On return: the decoded node.The newly allocated
|
||||
* node has a reference count of 1.
|
||||
* @param max_nesting_level the maximum nesting levels of structures within the
|
||||
* KMIP node. If the nesting level is reached, E2BIG
|
||||
* is returned.
|
||||
* @param debug if true, debug messages are printed
|
||||
*
|
||||
* @returns 0 in case of success, or a negative errno value
|
||||
*/
|
||||
int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
|
||||
struct kmip_node **node, bool debug)
|
||||
struct kmip_node **node, size_t max_nesting_level,
|
||||
bool debug)
|
||||
{
|
||||
char *tag_attr = NULL, *name_attr = NULL, *type_attr = NULL;
|
||||
enum kmip_tag tag, v1_attr_tag = 0;
|
||||
@@ -44,6 +48,9 @@ int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
|
||||
int64_t int64;
|
||||
int rc = 0, i;
|
||||
|
||||
if (max_nesting_level == 0)
|
||||
return -E2BIG;
|
||||
|
||||
if (xml == NULL || node == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -122,7 +129,8 @@ int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
|
||||
if (child->type != XML_ELEMENT_NODE)
|
||||
continue;
|
||||
|
||||
rc = kmip_decode_xml(child, n, &e, debug);
|
||||
rc = kmip_decode_xml(child, n, &e,
|
||||
max_nesting_level - 1, debug);
|
||||
if (rc != 0) {
|
||||
kmip_debug(debug, "Failed to parse child "
|
||||
"element %d", i);
|
||||
@@ -452,6 +460,10 @@ int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug)
|
||||
|
||||
case KMIP_TYPE_DATE_TIME:
|
||||
tm = gmtime((time_t *)&node->date_time_value);
|
||||
if (tm == NULL) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
strftime(tmp_str, sizeof(tmp_str), KMIP_ISO8601_TIMESTAMP_UTC,
|
||||
tm);
|
||||
attr = xmlSetProp(ret_xml, (xmlChar *)KMIP_XML_VALUE,
|
||||
|
||||
@@ -28,7 +28,7 @@ detect-openssl-version.dep:
|
||||
echo " #error openssl version 1.1 is required" >> $(TMPFILE)
|
||||
echo "#endif" >> $(TMPFILE)
|
||||
echo "static void __attribute__((unused)) test(void) {" >> $(TMPFILE)
|
||||
echo " EVP_PKEY_meth_remove(NULL);" >> $(TMPFILE)
|
||||
echo " EVP_PKEY_id(NULL);" >> $(TMPFILE)
|
||||
echo "}" >> $(TMPFILE)
|
||||
mv $(TMPFILE) $@
|
||||
|
||||
|
||||
@@ -258,7 +258,9 @@ static int sk_cca_get_library_functions(const struct sk_ext_cca_lib *cca_lib,
|
||||
*
|
||||
* @param cca_lib the CCA library structure
|
||||
* @param curve_nid the nid specifying the curve.
|
||||
* @param key_token a buffer to store the generated key token
|
||||
* @param key_token a buffer to store the generated key token. If NULL,
|
||||
* the required buffer size is returned in
|
||||
* key_token_length (size query).
|
||||
* @param key_token_length On entry: the size of the buffer
|
||||
* On return: the size of the key token
|
||||
* @param debug if true, debug messages are printed
|
||||
@@ -286,7 +288,7 @@ int SK_CCA_generate_ec_key_pair(const struct sk_ext_cca_lib *cca_lib,
|
||||
long param1 = 0;
|
||||
int rc;
|
||||
|
||||
if (cca_lib == NULL || key_token == NULL || key_token_length == NULL)
|
||||
if (cca_lib == NULL || key_token_length == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (key_token == NULL) {
|
||||
@@ -384,7 +386,9 @@ int SK_CCA_generate_ec_key_pair(const struct sk_ext_cca_lib *cca_lib,
|
||||
* 3, 5, 17, 257, or 65537. Specify zero to choose the
|
||||
* exponent by random (only possible for modulus_bits
|
||||
* up to 2048).
|
||||
* @param key_token a buffer to store the generated key token
|
||||
* @param key_token a buffer to store the generated key token. If NULL,
|
||||
* the required buffer size is returned in
|
||||
* key_token_length (size query).
|
||||
* @param key_token_length On entry: the size of the buffer
|
||||
* On return: the size of the key token
|
||||
* @param debug if true, debug messages are printed
|
||||
@@ -412,7 +416,7 @@ int SK_CCA_generate_rsa_key_pair(const struct sk_ext_cca_lib *cca_lib,
|
||||
long param1 = 0;
|
||||
int rc;
|
||||
|
||||
if (cca_lib == NULL || key_token == NULL || key_token_length == NULL)
|
||||
if (cca_lib == NULL || key_token_length == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (key_token == NULL) {
|
||||
@@ -459,7 +463,7 @@ int SK_CCA_generate_rsa_key_pair(const struct sk_ext_cca_lib *cca_lib,
|
||||
case 257:
|
||||
key_value_structure.public_exp_length = 2;
|
||||
key_value_structure.public_exponent[0] = 0x01;
|
||||
key_value_structure.public_exponent[0] = 0x01;
|
||||
key_value_structure.public_exponent[1] = 0x01;
|
||||
break;
|
||||
case 65537:
|
||||
key_value_structure.public_exp_length = 3;
|
||||
@@ -560,6 +564,11 @@ static const void *sk_cca_get_pka_section(const unsigned char *key_token,
|
||||
section_hdr = (struct cca_section_header *)&key_token[ofs];
|
||||
|
||||
while (section_hdr->section_identifier != section_id) {
|
||||
if (section_hdr->section_length <
|
||||
sizeof(struct cca_section_header)) {
|
||||
sk_debug(debug, "ERROR: invalid section length");
|
||||
return NULL;
|
||||
}
|
||||
ofs += section_hdr->section_length;
|
||||
if (ofs >= token_hdr->token_length) {
|
||||
sk_debug(debug, "ERROR: section %u not found",
|
||||
@@ -1385,7 +1394,7 @@ static int sk_cca_get_public_from_rsa_key(const unsigned char *key_token,
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rsa_pub_section->section_header.section_length <
|
||||
sizeof(struct cca_ec_pub_key_section)) {
|
||||
sizeof(struct cca_rsa_pub_key_section)) {
|
||||
sk_debug(debug, "ERROR: invalid RSA public key section length");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ static int sk_ep11_generate_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
|
||||
CK_RV rv;
|
||||
int rc;
|
||||
|
||||
if (ep11_lib == NULL || key_token == NULL || key_token_length == NULL)
|
||||
if (ep11_lib == NULL || key_token_length == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (key_token == NULL) {
|
||||
@@ -262,7 +262,9 @@ static int sk_ep11_generate_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
|
||||
*
|
||||
* @param ep11_lib the Ep11 library structure
|
||||
* @param curve_nid the nid specifying the curve.
|
||||
* @param key_token a buffer to store the generated key token
|
||||
* @param key_token a buffer to store the generated key token. If NULL,
|
||||
* the required buffer size is returned in
|
||||
* key_token_length (size query).
|
||||
* @param key_token_length On entry: the size of the buffer
|
||||
* On return: the size of the key token
|
||||
* @param debug if true, debug messages are printed
|
||||
@@ -292,7 +294,7 @@ int SK_EP11_generate_ec_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
|
||||
const struct sk_ec_curve_info *curve;
|
||||
int rc;
|
||||
|
||||
if (ep11_lib == NULL || key_token == NULL || key_token_length == NULL)
|
||||
if (ep11_lib == NULL || key_token_length == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
sk_debug(debug, "curve_nid: %d", curve_nid);
|
||||
@@ -331,7 +333,9 @@ int SK_EP11_generate_ec_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
|
||||
* 3, 5, 17, 257, or 65537. Specify zero to choose the
|
||||
* exponent by random.
|
||||
* @param x9_31 if true, generate a X9.31 RSA key
|
||||
* @param key_token a buffer to store the generated key token
|
||||
* @param key_token a buffer to store the generated key token. If NULL,
|
||||
* the required buffer size is returned in
|
||||
* key_token_length (size query).
|
||||
* @param key_token_length On entry: the size of the buffer
|
||||
* On return: the size of the key token
|
||||
* @param debug if true, debug messages are printed
|
||||
@@ -365,7 +369,7 @@ int SK_EP11_generate_rsa_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
|
||||
CK_ULONG priv_tmpl_num = sizeof(priv_tmpl) / sizeof(CK_ATTRIBUTE);
|
||||
int rc;
|
||||
|
||||
if (ep11_lib == NULL || key_token == NULL || key_token_length == NULL)
|
||||
if (ep11_lib == NULL || key_token_length == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
sk_debug(debug, "modulus_bits: %lu pub_exp: %u x9_31: %d",
|
||||
@@ -413,6 +417,8 @@ static unsigned char sk_ep11_parse_der_tag(const unsigned char *data,
|
||||
if (num > sizeof(size_t))
|
||||
return 0;
|
||||
*value_len = data[2];
|
||||
if (data_len < 2 + num)
|
||||
return 0;
|
||||
for (i = 1; i < num; i++) {
|
||||
*value_len <<= 8;
|
||||
*value_len |= data[2 + i];
|
||||
@@ -498,6 +504,8 @@ static int sk_ep11_parse_spki(const unsigned char *spki, size_t spki_len,
|
||||
pub_key, pub_key_len);
|
||||
if (tag != 0x03) /* BITSTRING */
|
||||
return -EINVAL;
|
||||
if (*pub_key_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* skip unsused-bits byte */
|
||||
(*pub_key)++;
|
||||
@@ -555,7 +563,7 @@ int SK_EP11_get_key_type(const unsigned char *key_token,
|
||||
return -EINVAL;
|
||||
|
||||
spki_size = key_token_length - hdr->len;
|
||||
if (spki_size <= 0)
|
||||
if (spki_size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
rc = sk_ep11_parse_spki(key_token + hdr->len, spki_size,
|
||||
@@ -702,7 +710,7 @@ static int sk_ep11_rsa_sign(const unsigned char *key_token,
|
||||
case RSA_X931_PADDING:
|
||||
mech.mechanism = CKM_RSA_X9_31;
|
||||
|
||||
if ((hdr->flags && PKEY_TYPE_EP11_FLAG_X9_31) == 0) {
|
||||
if ((hdr->flags & PKEY_TYPE_EP11_FLAG_X9_31) == 0) {
|
||||
sk_debug(debug, "ERROR: no RSA X9.31 key");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1375,7 +1383,7 @@ int SK_EP11_get_public_from_secure_key(const unsigned char *key_token,
|
||||
return -EINVAL;
|
||||
|
||||
spki_size = key_token_length - hdr->len;
|
||||
if (spki_size <= 0)
|
||||
if (spki_size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
rc = sk_ep11_parse_spki(key_token + hdr->len, spki_size,
|
||||
|
||||
@@ -698,6 +698,7 @@ static int sk_pkey_meth_setup_pkey(EVP_PKEY *pkey,
|
||||
struct sk_pkey_data *data;
|
||||
EC_KEY *ec;
|
||||
RSA *rsa;
|
||||
int rc;
|
||||
|
||||
if (pkey == NULL || secure_key == NULL || secure_key_size == 0 ||
|
||||
funcs == NULL)
|
||||
@@ -733,12 +734,14 @@ static int sk_pkey_meth_setup_pkey(EVP_PKEY *pkey,
|
||||
ec = EVP_PKEY_get0_EC_KEY(pkey);
|
||||
if (ec == NULL) {
|
||||
sk_debug(debug, "EVP_PKEY_get0_EC_KEY failed");
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!EC_KEY_set_ex_data(ec, sk_pkey_data_ec_index, data)) {
|
||||
sk_debug(debug, "EC_KEY_set_ex_data failed");
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case EVP_PKEY_RSA:
|
||||
@@ -746,17 +749,29 @@ static int sk_pkey_meth_setup_pkey(EVP_PKEY *pkey,
|
||||
rsa = EVP_PKEY_get0_RSA(pkey);
|
||||
if (rsa == NULL) {
|
||||
sk_debug(debug, "EVP_PKEY_get0_RSA failed");
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!RSA_set_ex_data(rsa, sk_pkey_data_rsa_index, data)) {
|
||||
sk_debug(debug, "RSA_set_ex_data failed");
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (data != NULL) {
|
||||
OPENSSL_free(data->key_blob);
|
||||
OPENSSL_free(data);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -796,13 +811,13 @@ int SK_OPENSSL_init(bool debug)
|
||||
return -EIO;
|
||||
}
|
||||
sk_pkey_meth_default_method_rsa = EVP_PKEY_meth_find(EVP_PKEY_RSA);
|
||||
if (sk_pkey_meth_default_method_ec == NULL) {
|
||||
if (sk_pkey_meth_default_method_rsa == NULL) {
|
||||
sk_debug(debug, "ERROR: EVP_PKEY_meth_find(RSA) failed");
|
||||
return -EIO;
|
||||
}
|
||||
sk_pkey_meth_default_method_rsa_pss =
|
||||
EVP_PKEY_meth_find(EVP_PKEY_RSA_PSS);
|
||||
if (sk_pkey_meth_default_method_ec == NULL) {
|
||||
if (sk_pkey_meth_default_method_rsa_pss == NULL) {
|
||||
sk_debug(debug, "ERROR: EVP_PKEY_meth_find(RSA-PSS) failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
@@ -811,6 +813,35 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline FILE *fopen_nofollow(const char *path, const char *mode)
|
||||
{
|
||||
int flags = O_NOFOLLOW;
|
||||
int fd;
|
||||
FILE *fp;
|
||||
|
||||
/* Determine flags based on mode */
|
||||
if (mode[0] == 'r')
|
||||
flags |= (mode[1] == '+') ? O_RDWR : O_RDONLY;
|
||||
else if (mode[0] == 'w')
|
||||
flags |= O_CREAT | O_TRUNC |
|
||||
((mode[1] == '+') ? O_RDWR : O_WRONLY);
|
||||
else if (mode[0] == 'a')
|
||||
flags |= O_CREAT | O_APPEND |
|
||||
((mode[1] == '+') ? O_RDWR : O_WRONLY);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
fd = open(path, flags, 0600);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
fp = fdopen(fd, mode);
|
||||
if (fp == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a X.509 certificate from the specified PEM file.
|
||||
@@ -863,7 +894,7 @@ int SK_UTIL_write_x509_certificate(const char *pem_filename, X509 *cert)
|
||||
if (pem_filename == NULL || cert == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(pem_filename, "w");
|
||||
fp = fopen_nofollow(pem_filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
@@ -898,7 +929,7 @@ int SK_UTIL_write_x509_request(const char *pem_filename, X509_REQ *req,
|
||||
if (pem_filename == NULL || req == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(pem_filename, "w");
|
||||
fp = fopen_nofollow(pem_filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
@@ -982,7 +1013,7 @@ int SK_UTIL_write_key_blob(const char *filename, unsigned char *key_blob,
|
||||
if (filename == NULL || key_blob == NULL || key_blob_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(filename, "w");
|
||||
fp = fopen_nofollow(filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
@@ -1047,7 +1078,7 @@ int SK_UTIL_write_public_key(const char *pem_filename, EVP_PKEY *pkey)
|
||||
if (pem_filename == NULL || pkey == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
fp = fopen(pem_filename, "w");
|
||||
fp = fopen_nofollow(pem_filename, "w");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
|
||||
@@ -742,6 +742,8 @@ static int read_cmdline(struct task_t *task)
|
||||
buf[i] = ' ';
|
||||
}
|
||||
name_lens.cmdline_len = num;
|
||||
if (name_lens.cmdline_len > MAX_CMD_LEN)
|
||||
name_lens.cmdline_len = MAX_CMD_LEN;
|
||||
cmdlnlenp = mon_record + sizeof(struct monwrite_hdr);
|
||||
cmdlnlenp += sizeof(struct procd_hdr);
|
||||
cmdlnlenp += sizeof(struct task_t);
|
||||
|
||||
@@ -44,7 +44,20 @@
|
||||
#define MAX_GET_DATA 4094 /* maximum GET response data length */
|
||||
#define GET_AREA_LEN MAX_GET_DATA + 512 /* size for GET command area length */
|
||||
#define TIME_BUF_SIZE 128 /* buffer size for date and time string */
|
||||
#define MAX_OID_STR_LEN MAX_OID_LEN * 5 /* max OID string size */
|
||||
|
||||
/*
|
||||
* Define maximum SNMP OID string size.
|
||||
* An OID can have up to 128 sub-ids and each sub-id can have up to 10
|
||||
* digits. When converted to string, this means 1 character for the
|
||||
* period separator and 10 characters for the digits themselves. At
|
||||
* the end of OID string, we need one more character for the null
|
||||
* terminator. The unsigned long data type, which can have up to 20
|
||||
* digits is used to represent a sub-id. This means each sub-id
|
||||
* string now needs 20+1 characters instead of 10+1 in-order to avoid
|
||||
* compiler warnings.
|
||||
*/
|
||||
#define MAX_OID_STR_LEN (MAX_OID_LEN * 21) + 1
|
||||
|
||||
/* definitions for 2.6 qeth */
|
||||
#define QETH_SYSFILE "/sys/bus/ccwgroup/drivers/qeth/notifier_register"
|
||||
#define SIOC_QETH_ADP_SET_SNMP_CONTROL (SIOCDEVPRIVATE + 5)
|
||||
|
||||
@@ -110,7 +110,7 @@ int str_to_oid_conv ( char* uc_oid, oid* ul_oid )
|
||||
*********************************************************************/
|
||||
int oid_to_str_conv (oid* ul_oid, size_t length, char* uc_oid )
|
||||
{
|
||||
#define MAX_CHARS 50 /* size of buffer */
|
||||
#define MAX_CHARS 22 /* size of buffer */
|
||||
int i;
|
||||
short valid = TRUE;
|
||||
char buffer[MAX_CHARS]; /* buffer used for conversion */
|
||||
@@ -125,9 +125,9 @@ int oid_to_str_conv (oid* ul_oid, size_t length, char* uc_oid )
|
||||
{
|
||||
/* convert and append OID digit to return string */
|
||||
if (i == 0)
|
||||
sprintf( buffer, "%lu", ul_oid[i] );
|
||||
snprintf( buffer, sizeof(buffer), "%lu", ul_oid[i] );
|
||||
else
|
||||
sprintf( buffer, ".%lu", ul_oid[i] );
|
||||
snprintf( buffer, sizeof(buffer), ".%lu", ul_oid[i] );
|
||||
|
||||
strcat( uc_oid, buffer );
|
||||
} /* end for */
|
||||
|
||||
587
rust/Cargo.lock
generated
587
rust/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -17,12 +17,11 @@ resolver = "2"
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.75.0"
|
||||
rust-version = "1.85.0"
|
||||
|
||||
[workspace.lints.rust]
|
||||
missing_docs = { level = "deny", priority = 1 }
|
||||
missing_debug_implementations = "warn"
|
||||
non_ascii_idents = "warn"
|
||||
nonstandard-style = "warn"
|
||||
trivial_numeric_casts = "warn"
|
||||
unstable_features = "warn"
|
||||
|
||||
@@ -6,15 +6,15 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.95"
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
anyhow = "1.0.102"
|
||||
clap = { version = "4.6", features = ["derive"] }
|
||||
libc = "0.2"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
utils = { path = "../utils" }
|
||||
zerocopy = { version="0.8", features = ["derive"] }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.2"
|
||||
clap = { version ="4.5", features = ["derive"]}
|
||||
clap = { version ="4.6", features = ["derive"]}
|
||||
lazy_static = "1.5"
|
||||
|
||||
@@ -7,11 +7,11 @@ mod msa;
|
||||
mod query;
|
||||
mod stfle;
|
||||
|
||||
use anyhow::bail;
|
||||
use anyhow::Result as anyhowRes;
|
||||
use clap::Parser;
|
||||
use std::io::ErrorKind;
|
||||
use std::result::Result::Ok;
|
||||
|
||||
use anyhow::{bail, Result as anyhowRes};
|
||||
use clap::Parser;
|
||||
use utils::print_version;
|
||||
|
||||
use crate::cli::{Cli, Format};
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use crate::cli::Cli;
|
||||
use core::fmt::{Display, Formatter, Result};
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
use utils::HexSlice;
|
||||
|
||||
use crate::cli::Cli;
|
||||
|
||||
/// Number of total function codes (0 to 127)
|
||||
pub const NUMBER_FUNC_CODES: usize = 128;
|
||||
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Error;
|
||||
use std::io::Read;
|
||||
use std::io::{Error, Read};
|
||||
use std::ops::Index;
|
||||
use std::result::Result;
|
||||
|
||||
use zerocopy::FromBytes;
|
||||
|
||||
use crate::msa::InstructionKind;
|
||||
use crate::msa::QueryAuthInfo;
|
||||
use crate::msa::{InstructionKind, QueryAuthInfo};
|
||||
|
||||
/// Path to sysfs in which the query and qai informations are fetched from
|
||||
const SYSFS_PATH: &str = "/sys/devices/system/cpu/cpacf/";
|
||||
|
||||
@@ -15,17 +15,18 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.5"
|
||||
curl = "0.4.47"
|
||||
curl = "0.4.49"
|
||||
enum_dispatch = "0.3.13"
|
||||
foreign-types = "0.3.2"
|
||||
log = { version = "0.4.25", features = ["std", "release_max_level_debug"] }
|
||||
openssl = "0.10.70"
|
||||
openssl-sys = "0.9.105"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
thiserror = "2.0.11"
|
||||
log = { version = "0.4.29", features = ["std", "release_max_level_debug"] }
|
||||
openssl = "0.10.80"
|
||||
openssl-sys = "0.9.116"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
thiserror = "2.0.18"
|
||||
zerocopy = { version="0.8", features = ["derive"] }
|
||||
|
||||
pv_core = { path = "../pv_core", package = "s390_pv_core", version = "0.12.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_test = "1.0.177"
|
||||
testing_logger = "0.1.1"
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use pv::request::EcPubKeyCoord;
|
||||
use pv_core::misc::encode_hex;
|
||||
use s390_pv as pv;
|
||||
|
||||
use std::env::args;
|
||||
|
||||
use pv::misc::{read_certs, read_file};
|
||||
use pv::request::EcPubKeyCoord;
|
||||
use pv::{Error, Result};
|
||||
use pv_core::misc::encode_hex;
|
||||
use s390_pv as pv;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let hkd = args().nth(1).expect("Expect one Host-key document");
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2023, 2024
|
||||
|
||||
use std::{
|
||||
io::{Read, Seek, SeekFrom::Current},
|
||||
mem::size_of,
|
||||
};
|
||||
use std::io::SeekFrom::Current;
|
||||
use std::io::{Read, Seek};
|
||||
use std::mem::size_of;
|
||||
|
||||
use log::{debug, warn};
|
||||
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, U32, U64};
|
||||
@@ -13,6 +12,13 @@ use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, U32, U64
|
||||
// (SE) boot request control block aka SE header
|
||||
use crate::{assert_size, request::MagicValue, static_assert, Error, Result, PAGESIZE};
|
||||
|
||||
/// Version of the Secure Execution header
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SeHdrVersion {
|
||||
/// Secure Execution header v1
|
||||
One = 0x100,
|
||||
}
|
||||
|
||||
/// Struct containing all SE-header tags.
|
||||
///
|
||||
/// Contains:
|
||||
@@ -206,7 +212,7 @@ impl BootHdrTags {
|
||||
///
|
||||
/// This function will return an error if the header could not be found in
|
||||
/// `img` or is invalid.
|
||||
pub fn from_se_image<R>(img: &mut R) -> Result<Self>
|
||||
pub fn from_se_image<R>(img: &mut R) -> Result<(Self, SeHdrVersion)>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
@@ -233,10 +239,13 @@ impl BootHdrTags {
|
||||
};
|
||||
|
||||
// Some sanity checks
|
||||
if hdr_head.version.get() != 0x100 {
|
||||
debug!("Unsupported hdr-version: {:0>4x}", hdr_head.version.get());
|
||||
return Err(Error::InvBootHdr);
|
||||
}
|
||||
let hdr_version = match hdr_head.version.get() {
|
||||
0x100 => SeHdrVersion::One,
|
||||
_ => {
|
||||
debug!("Unsupported hdr-version: {:0>4x}", hdr_head.version.get());
|
||||
return Err(Error::InvBootHdr);
|
||||
}
|
||||
};
|
||||
|
||||
// go to the Boot header tag
|
||||
img.seek(Current(
|
||||
@@ -249,12 +258,15 @@ impl BootHdrTags {
|
||||
let mut tag = [0u8; BootHdrHead::TAG_SIZE];
|
||||
img.read_exact(tag.as_mut_slice())?;
|
||||
|
||||
Ok(Self {
|
||||
pld: hdr_head.pld,
|
||||
ald: hdr_head.ald,
|
||||
tld: hdr_head.tld,
|
||||
tag,
|
||||
})
|
||||
Ok((
|
||||
Self {
|
||||
pld: hdr_head.pld,
|
||||
ald: hdr_head.ald,
|
||||
tld: hdr_head.tld,
|
||||
tag,
|
||||
},
|
||||
hdr_version,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +332,7 @@ mod tests {
|
||||
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)).unwrap();
|
||||
assert_eq!(hdr_tags, EXP_HDR);
|
||||
assert_eq!(hdr_tags, (EXP_HDR, SeHdrVersion::One));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -356,18 +368,19 @@ mod tests {
|
||||
let bin_hdr = get_test_asset!("exp/secure_guest.hdr");
|
||||
img[0x12000..0x12280].copy_from_slice(bin_hdr);
|
||||
let hdr_tags = BootHdrTags::from_se_image(&mut Cursor::new(img)).unwrap();
|
||||
assert_eq!(hdr_tags, EXP_HDR);
|
||||
assert_eq!(hdr_tags, (EXP_HDR, SeHdrVersion::One));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tags_convert_u8() {
|
||||
let bin_hdr = get_test_asset!("exp/secure_guest.hdr");
|
||||
let hdr_tags = BootHdrTags::from_se_image(&mut Cursor::new(*bin_hdr)).unwrap();
|
||||
let ser: &[u8] = hdr_tags.as_ref();
|
||||
let ser: &[u8] = hdr_tags.0.as_ref();
|
||||
let mut ser = ser.to_vec();
|
||||
|
||||
let der: BootHdrTags = ser.clone().try_into().unwrap();
|
||||
assert_eq!(hdr_tags, der);
|
||||
assert_eq!(hdr_tags.0, der);
|
||||
assert_eq!(hdr_tags.1, SeHdrVersion::One);
|
||||
|
||||
ser.pop();
|
||||
let der: Result<BootHdrTags> = ser.clone().try_into();
|
||||
@@ -380,7 +393,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn se_img_metadata() {
|
||||
fn se_img_metadata_v1() {
|
||||
let metadata = SeImgMetaData::new_v1(0x14000, 0x16000);
|
||||
let data = [
|
||||
83, 101, 73, 109, 103, 76, 110, 120, 0, 0, 0, 0, 0, 1, 64, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
|
||||
@@ -2,25 +2,28 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2023, 2024
|
||||
|
||||
use std::{convert::TryInto, fmt::Display, ops::Range};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Range;
|
||||
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use openssl::{
|
||||
derive::Deriver,
|
||||
ec::{EcGroup, EcKey},
|
||||
hash::{DigestBytes, MessageDigest},
|
||||
md::MdRef,
|
||||
nid::Nid,
|
||||
pkey::{HasPublic, Id, PKey, PKeyRef, Private, Public},
|
||||
pkey_ctx::{HkdfMode, PkeyCtx},
|
||||
rand::rand_bytes,
|
||||
rsa::Padding,
|
||||
sign::{Signer, Verifier},
|
||||
symm::{decrypt_aead as openssl_decrypt_aead, encrypt_aead as openssl_encrypt_aead, Cipher},
|
||||
use openssl::derive::Deriver;
|
||||
use openssl::ec::{EcGroup, EcKey};
|
||||
use openssl::hash::{DigestBytes, MessageDigest};
|
||||
use openssl::md::MdRef;
|
||||
use openssl::nid::Nid;
|
||||
use openssl::pkey::{HasPublic, Id, PKey, PKeyRef, Private, Public};
|
||||
use openssl::pkey_ctx::{HkdfMode, PkeyCtx};
|
||||
use openssl::rand::rand_bytes;
|
||||
use openssl::rsa::Padding;
|
||||
use openssl::sign::{Signer, Verifier};
|
||||
use openssl::symm::{
|
||||
decrypt_aead as openssl_decrypt_aead, encrypt_aead as openssl_encrypt_aead, Cipher,
|
||||
};
|
||||
use pv_core::request::Confidential;
|
||||
|
||||
use crate::{error::Result, Error};
|
||||
use crate::error::Result;
|
||||
use crate::Error;
|
||||
|
||||
/// An AES256-GCM key that will purge itself out of the memory when going out of scope
|
||||
pub type Aes256GcmKey = Confidential<[u8; SymKeyType::AES_256_GCM_KEY_LEN]>;
|
||||
@@ -159,6 +162,12 @@ impl SymKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SymKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "SymKey({:?})", self.key_type())
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs an hkdf according to RFC 5869.
|
||||
/// See [`OpenSSL HKDF`]()
|
||||
///
|
||||
@@ -539,8 +548,166 @@ pub(crate) fn verify_signature<T: HasPublic>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use super::*;
|
||||
use crate::{get_test_asset, test_utils::*, PvCoreError};
|
||||
use crate::test_utils::*;
|
||||
use crate::{get_test_asset, PvCoreError};
|
||||
|
||||
/// Test that deterministic RNG contexts are thread-local and don't interfere.
|
||||
///
|
||||
/// Per OpenSSL documentation (RAND_get0_primary(3)):
|
||||
/// "The public and private DRBG are thread-local instances, which are used by
|
||||
/// RAND_bytes() and RAND_priv_bytes(), respectively."
|
||||
///
|
||||
/// Reference: <https://docs.openssl.org/3.1/man3/RAND_get0_primary/>
|
||||
///
|
||||
/// Note: RAND_set0_public() and RAND_set0_private() require OpenSSL >= 3.1.
|
||||
#[test]
|
||||
fn test_deterministic_rng_thread_isolation() {
|
||||
use std::sync::Barrier;
|
||||
|
||||
use openssl::rand::rand_bytes;
|
||||
|
||||
// Barriers to synchronize: thread1 installs → thread2 installs → both generate → both
|
||||
// complete
|
||||
let barrier_after_t1_install = Arc::new(Barrier::new(2));
|
||||
let barrier_after_t2_install = Arc::new(Barrier::new(2));
|
||||
let barrier_after_rand_bytes = Arc::new(Barrier::new(2));
|
||||
|
||||
let barrier1_clone = Arc::clone(&barrier_after_t1_install);
|
||||
let barrier2_clone = Arc::clone(&barrier_after_t2_install);
|
||||
let barrier3_clone = Arc::clone(&barrier_after_rand_bytes);
|
||||
|
||||
// Thread 1: Install deterministic RNG with specific entropy
|
||||
let thread1 = thread::spawn(move || {
|
||||
let entropy = [0x42u8; 4096];
|
||||
let nonce = [0x24u8; 48];
|
||||
|
||||
// Install thread-local deterministic RNG
|
||||
let _rng = DeterministicTestRandGuard::install(&entropy, &nonce).unwrap();
|
||||
|
||||
// Signal thread2 that we've installed our RNG
|
||||
barrier1_clone.wait();
|
||||
|
||||
// Wait for thread2 to install its RNG
|
||||
barrier2_clone.wait();
|
||||
|
||||
// Now generate bytes while thread2 also has its RNG installed
|
||||
let mut buf = [0u8; 32];
|
||||
rand_bytes(&mut buf).unwrap();
|
||||
|
||||
// Wait for thread2 to also complete rand_bytes
|
||||
barrier3_clone.wait();
|
||||
|
||||
buf
|
||||
});
|
||||
|
||||
// Thread 2: Install different deterministic RNG after thread1
|
||||
let thread2 = thread::spawn(move || {
|
||||
// Wait for thread1 to install its RNG first
|
||||
barrier_after_t1_install.wait();
|
||||
|
||||
// Now install our own thread-local deterministic RNG with different entropy
|
||||
let entropy = [0xAAu8; 4096];
|
||||
let nonce = [0x55u8; 48];
|
||||
let _rng = DeterministicTestRandGuard::install(&entropy, &nonce).unwrap();
|
||||
|
||||
// Signal thread1 that we've installed our RNG
|
||||
barrier_after_t2_install.wait();
|
||||
|
||||
// Generate bytes with our different entropy (concurrently with thread1)
|
||||
let mut buf = [0u8; 32];
|
||||
rand_bytes(&mut buf).unwrap();
|
||||
|
||||
// Wait for thread1 to also complete rand_bytes
|
||||
barrier_after_rand_bytes.wait();
|
||||
|
||||
buf
|
||||
});
|
||||
|
||||
let t1_buf = thread1.join().unwrap();
|
||||
let t2_buf = thread2.join().unwrap();
|
||||
|
||||
// Expected deterministic values for thread 1 (entropy=0x42, nonce=0x24)
|
||||
let expected_t1: [u8; 32] = [
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
];
|
||||
|
||||
// Expected deterministic values for thread 2 (entropy=0xAA, nonce=0x55)
|
||||
let expected_t2: [u8; 32] = [
|
||||
170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
|
||||
170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
|
||||
];
|
||||
|
||||
// Verify each thread produced its expected deterministic output
|
||||
assert_eq!(
|
||||
t1_buf, expected_t1,
|
||||
"Thread 1 should produce deterministic output"
|
||||
);
|
||||
assert_eq!(
|
||||
t2_buf, expected_t2,
|
||||
"Thread 2 should produce deterministic output"
|
||||
);
|
||||
|
||||
// Also verify they are different (proves thread-local isolation)
|
||||
assert_ne!(
|
||||
t1_buf, t2_buf,
|
||||
"Different thread-local entropy should produce different output"
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that the original RNG is properly restored after DeterministicTestRandGuard is dropped
|
||||
#[test]
|
||||
fn test_deterministic_rng_restoration() {
|
||||
use openssl::rand::rand_bytes;
|
||||
|
||||
// Generate random bytes with system RNG before installing deterministic RNG
|
||||
let mut before_buf = [0u8; 32];
|
||||
rand_bytes(&mut before_buf).unwrap();
|
||||
|
||||
let deterministic_buf = {
|
||||
let entropy = [0x42u8; 4096];
|
||||
let nonce = [0x24u8; 48];
|
||||
|
||||
// Install deterministic RNG
|
||||
let _rng = DeterministicTestRandGuard::install(&entropy, &nonce).unwrap();
|
||||
|
||||
// Generate deterministic bytes
|
||||
let mut buf = [0u8; 32];
|
||||
rand_bytes(&mut buf).unwrap();
|
||||
|
||||
// Expected deterministic output
|
||||
let expected: [u8; 32] = [
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
|
||||
];
|
||||
assert_eq!(buf, expected, "Should produce deterministic output");
|
||||
|
||||
buf
|
||||
// _rng is dropped here, should restore original RNG
|
||||
};
|
||||
|
||||
// Generate random bytes again with restored system RNG
|
||||
let mut after_buf = [0u8; 32];
|
||||
rand_bytes(&mut after_buf).unwrap();
|
||||
|
||||
// The system RNG should produce different random values each time
|
||||
// (extremely unlikely to match the deterministic output)
|
||||
assert_ne!(
|
||||
after_buf, deterministic_buf,
|
||||
"After restoration, system RNG should produce different random values"
|
||||
);
|
||||
|
||||
// Also verify that before and after are different (system RNG produces random values)
|
||||
// Note: This could theoretically fail with probability 1/2^256, but that's negligible
|
||||
assert_ne!(
|
||||
before_buf, after_buf,
|
||||
"System RNG should produce different random values on each call"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sign_ec() {
|
||||
|
||||
@@ -94,7 +94,7 @@ pub enum Error {
|
||||
BinArcbInvVersion(u32),
|
||||
|
||||
#[error(
|
||||
"The attestation request encrypted sice is to0 small {0}. Request probably tampered with."
|
||||
"The attestation request encrypted sice is too small {0}. Request probably tampered with."
|
||||
)]
|
||||
BinArcbSeaSmall(u32),
|
||||
|
||||
@@ -173,8 +173,16 @@ pub enum HkdVerifyErrorType {
|
||||
IssuerMismatch,
|
||||
#[error("No CRL distribution points found")]
|
||||
NoCrlDP,
|
||||
#[error("CRL distribution point uses unsupported protocol (only HTTP/HTTPS allowed)")]
|
||||
InvalidCrlProtocol,
|
||||
#[error("The IBM Z signing key could not be verified. Error occurred at level {1}")]
|
||||
IbmSignInvalid(#[source] openssl::x509::X509VerifyResult, u32),
|
||||
#[error("Too many redirections during CRL download")]
|
||||
TooManyRedirectionsCrlDownload,
|
||||
#[error("CRL download exceeds maximum file size of {} MiB", .0 / (1024 * 1024))]
|
||||
CrlDownloadTooLarge(u64),
|
||||
#[error("CRL download failed")]
|
||||
CrlDownloadFailed,
|
||||
}
|
||||
|
||||
macro_rules! bail_hkd_verify {
|
||||
|
||||
@@ -63,13 +63,11 @@ pub mod uv {
|
||||
pub mod attest {
|
||||
pub use pv_core::attest::*;
|
||||
|
||||
pub use crate::uvattest::{
|
||||
additional::AdditionalData,
|
||||
arcb::{
|
||||
AttestationAuthenticated, AttestationFlags, AttestationRequest, AttestationVersion,
|
||||
},
|
||||
attest::{AttestationItems, AttestationMeasurement},
|
||||
pub use crate::uvattest::additional::AdditionalData;
|
||||
pub use crate::uvattest::arcb::{
|
||||
AttestationAuthenticated, AttestationFlags, AttestationRequest, AttestationVersion,
|
||||
};
|
||||
pub use crate::uvattest::attest::{AttestationItems, AttestationMeasurement};
|
||||
}
|
||||
|
||||
/// Definitions and functions to write objects in PEM format
|
||||
@@ -91,27 +89,22 @@ pub use crate::error::HkdVerifyErrorType;
|
||||
|
||||
/// Functionalities to build UV requests
|
||||
pub mod request {
|
||||
pub use crate::{
|
||||
brcb::{seek_se_hdr_start, BootHdrTags, SeImgMetaData},
|
||||
crypto::{
|
||||
decrypt_aead, derive_aes256_gcm_key, encrypt_aead, gen_ec_key, random_array,
|
||||
AeadDecryptionResult, AeadEncryptionResult, Aes256GcmKey, Aes256XtsKey, SymKey,
|
||||
SymKeyType, SHA_512_HASH_LEN,
|
||||
},
|
||||
req::{EcPubKeyCoord, Encrypt, Keyslot, ReqEncrCtx, Request},
|
||||
verify::{CertVerifier, HkdVerifier, NoVerifyHkd},
|
||||
pub use crate::brcb::{seek_se_hdr_start, BootHdrTags, SeImgMetaData};
|
||||
pub use crate::crypto::{
|
||||
decrypt_aead, derive_aes256_gcm_key, encrypt_aead, gen_ec_key, random_array,
|
||||
AeadDecryptionResult, AeadEncryptionResult, Aes256GcmKey, Aes256XtsKey, SymKey, SymKeyType,
|
||||
SHA_512_HASH_LEN,
|
||||
};
|
||||
pub use crate::req::{EcPubKeyCoord, Encrypt, HostKey, Keyslot, ReqEncrCtx, Request};
|
||||
pub use crate::verify::{CertVerifier, HkdVerifier, NoVerifyHkd};
|
||||
|
||||
/// Reexports some useful OpenSSL symbols
|
||||
pub mod openssl {
|
||||
pub use openssl::{
|
||||
error::ErrorStack,
|
||||
hash::DigestBytes,
|
||||
nid::Nid,
|
||||
pkey,
|
||||
sha::{Sha256, Sha512},
|
||||
x509,
|
||||
};
|
||||
pub use openssl::error::ErrorStack;
|
||||
pub use openssl::hash::DigestBytes;
|
||||
pub use openssl::nid::Nid;
|
||||
pub use openssl::sha::{Sha256, Sha512};
|
||||
pub use openssl::{pkey, x509};
|
||||
// rust-OpenSSL does not define these NIDs
|
||||
#[allow(missing_docs)]
|
||||
pub const NID_ED25519: Nid = Nid::from_raw(openssl_sys::NID_ED25519);
|
||||
@@ -120,7 +113,6 @@ pub mod request {
|
||||
}
|
||||
|
||||
pub use pv_core::request::*;
|
||||
|
||||
pub use pv_core::PolicyReference;
|
||||
}
|
||||
|
||||
@@ -128,11 +120,9 @@ pub mod request {
|
||||
pub mod secret {
|
||||
pub use pv_core::secret::*;
|
||||
|
||||
pub use crate::uvsecret::{
|
||||
asrcb::{AddSecretFlags, AddSecretRequest, AddSecretVersion},
|
||||
ext_secret::ExtSecret,
|
||||
guest_secret::GuestSecret,
|
||||
retr_secret::{IbmProtectedKey, RetrievedSecret},
|
||||
user_data::verify_asrcb_and_get_user_data,
|
||||
};
|
||||
pub use crate::uvsecret::asrcb::{AddSecretFlags, AddSecretRequest, AddSecretVersion};
|
||||
pub use crate::uvsecret::ext_secret::ExtSecret;
|
||||
pub use crate::uvsecret::guest_secret::GuestSecret;
|
||||
pub use crate::uvsecret::retr_secret::{IbmProtectedKey, RetrievedSecret};
|
||||
pub use crate::uvsecret::user_data::verify_asrcb_and_get_user_data;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use std::ffi::c_int;
|
||||
use std::fmt;
|
||||
|
||||
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
|
||||
use openssl::x509::{X509CrlRef, X509Ref};
|
||||
use std::ffi::c_int;
|
||||
|
||||
mod ffi {
|
||||
extern "C" {
|
||||
@@ -99,9 +99,8 @@ impl AkidExtension for X509CrlRef {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::test_utils::load_gen_cert;
|
||||
|
||||
use super::*;
|
||||
use crate::test_utils::load_gen_cert;
|
||||
|
||||
#[test]
|
||||
fn akid() {
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use core::slice;
|
||||
use std::ffi::c_int;
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl_sys::BIO_new_mem_buf;
|
||||
use std::ffi::c_int;
|
||||
use std::{marker::PhantomData, ptr};
|
||||
|
||||
pub struct BioMem(*mut openssl_sys::BIO);
|
||||
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
pub use crate::openssl_extensions::stackable_crl::*;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use openssl::{
|
||||
error::ErrorStack,
|
||||
stack::{Stack, StackRef},
|
||||
x509::{
|
||||
store::{X509StoreBuilderRef, X509StoreRef},
|
||||
X509CrlRef, X509NameRef, X509Ref, X509StoreContextRef, X509,
|
||||
},
|
||||
};
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::stack::{Stack, StackRef};
|
||||
use openssl::x509::store::{X509StoreBuilderRef, X509StoreRef};
|
||||
use openssl::x509::{X509CrlRef, X509NameRef, X509Ref, X509StoreContextRef, X509};
|
||||
|
||||
pub use crate::openssl_extensions::stackable_crl::*;
|
||||
|
||||
pub fn opt_to_ptr<T: ForeignTypeRef>(o: Option<&T>) -> *mut T::CType {
|
||||
match o {
|
||||
|
||||
595
rust/pv/src/openssl_extensions/ml_kem.rs
Normal file
595
rust/pv/src/openssl_extensions/ml_kem.rs
Normal file
@@ -0,0 +1,595 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
#![cfg_attr(not(test), expect(unused))]
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use foreign_types::ForeignType;
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::pkey::{KeyType, PKey, Private};
|
||||
use openssl::pkey_ctx::PkeyCtx;
|
||||
|
||||
// automatically generated by rust-bindgen 0.69.5
|
||||
|
||||
mod ffi {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct evp_pkey_ctx_st {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
pub type EvpPkeyCtx = evp_pkey_ctx_st;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ossl_param_st {
|
||||
pub key: *const ::std::os::raw::c_char,
|
||||
pub data_type: ::std::os::raw::c_uint,
|
||||
pub data: *mut ::std::os::raw::c_void,
|
||||
pub data_size: usize,
|
||||
pub return_size: usize,
|
||||
}
|
||||
pub type OsslParam = ossl_param_st;
|
||||
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_CTX_new_from_name(
|
||||
libctx: *mut ::std::os::raw::c_void,
|
||||
name: *const ::std::os::raw::c_char,
|
||||
propquery: *const ::std::os::raw::c_char,
|
||||
) -> *mut EvpPkeyCtx;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_keygen_init(ctx: *mut EvpPkeyCtx) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_generate(
|
||||
ctx: *mut EvpPkeyCtx,
|
||||
ppkey: *mut *mut ::std::os::raw::c_void,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_CTX_free(ctx: *mut EvpPkeyCtx);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_encapsulate_init(
|
||||
ctx: *mut EvpPkeyCtx,
|
||||
params: *const OsslParam,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_encapsulate(
|
||||
ctx: *mut EvpPkeyCtx,
|
||||
wrappedkey: *mut ::std::os::raw::c_uchar,
|
||||
wrappedkeylen: *mut usize,
|
||||
genkey: *mut ::std::os::raw::c_uchar,
|
||||
genkeylen: *mut usize,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_decapsulate_init(
|
||||
ctx: *mut EvpPkeyCtx,
|
||||
params: *const OsslParam,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn EVP_PKEY_decapsulate(
|
||||
ctx: *mut EvpPkeyCtx,
|
||||
unwrapped: *mut ::std::os::raw::c_uchar,
|
||||
unwrappedlen: *mut usize,
|
||||
wrapped: *const ::std::os::raw::c_uchar,
|
||||
wrappedlen: usize,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
const ML_KEM_512_NAME: &CStr = c"ML-KEM-512";
|
||||
const ML_KEM_768_NAME: &CStr = c"ML-KEM-768";
|
||||
const ML_KEM_1024_NAME: &CStr = c"ML-KEM-1024";
|
||||
|
||||
fn ml_kem_name(key_type: KeyType) -> Result<&'static CStr, ErrorStack> {
|
||||
if key_type == KeyType::ML_KEM_512 {
|
||||
Ok(ML_KEM_512_NAME)
|
||||
} else if key_type == KeyType::ML_KEM_768 {
|
||||
Ok(ML_KEM_768_NAME)
|
||||
} else if key_type == KeyType::ML_KEM_1024 {
|
||||
Ok(ML_KEM_1024_NAME)
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulate a key
|
||||
pub trait PkeyEncapsulateContext {
|
||||
/// Initialize the encapsulation operation.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the OpenSSL operation fails.
|
||||
fn encapsulate_init(&mut self) -> Result<(), ErrorStack>;
|
||||
|
||||
/// Perform the encapsulation operation.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `wrappedkey`: Optional buffer to receive the wrapped key.
|
||||
/// - `genkey`: Optional buffer to receive the generated key.
|
||||
///
|
||||
/// # Returns
|
||||
/// A tuple of `(wrappedkey_len, genkey_len)` on success.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the OpenSSL operation fails.
|
||||
fn encapsulate(
|
||||
&mut self,
|
||||
wrappedkey: Option<&mut [u8]>,
|
||||
genkey: Option<&mut [u8]>,
|
||||
) -> Result<(usize, usize), ErrorStack>;
|
||||
|
||||
/// Convenience method to encapsulate into vectors.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `wrappedkey`: Buffer to receive the wrapped key (ciphertext).
|
||||
/// - `genkey`: Buffer to receive the generated key (shared secret).
|
||||
///
|
||||
/// # Returns
|
||||
/// A tuple of `(wrappedkey_len, genkey_len)` on success.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the OpenSSL operation fails.
|
||||
fn encapsulate_to_vec(
|
||||
&mut self,
|
||||
wrappedkey: &mut Vec<u8>,
|
||||
genkey: &mut Vec<u8>,
|
||||
) -> Result<(usize, usize), ErrorStack> {
|
||||
let wrappedkey_base = wrappedkey.len();
|
||||
let genkey_base = genkey.len();
|
||||
|
||||
// Query the required output buffer sizes.
|
||||
let (wrappedkey_len, genkey_len) = self.encapsulate(None, None)?;
|
||||
|
||||
wrappedkey.resize(wrappedkey_base + wrappedkey_len, 0);
|
||||
genkey.resize(genkey_base + genkey_len, 0);
|
||||
|
||||
let (wrappedkey_len, genkey_len) = self.encapsulate(
|
||||
Some(&mut wrappedkey[wrappedkey_base..]),
|
||||
Some(&mut genkey[genkey_base..]),
|
||||
)?;
|
||||
|
||||
wrappedkey.truncate(wrappedkey_base + wrappedkey_len);
|
||||
genkey.truncate(genkey_base + genkey_len);
|
||||
|
||||
Ok((wrappedkey_len, genkey_len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PkeyEncapsulateContext for PkeyCtx<T> {
|
||||
#[inline]
|
||||
fn encapsulate_init(&mut self) -> Result<(), ErrorStack> {
|
||||
// SAFETY: self.as_ptr() returns a valid EVP_PKEY_CTX pointer. Parameter-based
|
||||
// configuration is intentionally unsupported here, so a null params pointer is passed.
|
||||
let ret = unsafe {
|
||||
ffi::EVP_PKEY_encapsulate_init(self.as_ptr() as *mut ffi::EvpPkeyCtx, std::ptr::null())
|
||||
};
|
||||
|
||||
if ret == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
|
||||
fn encapsulate(
|
||||
&mut self,
|
||||
wrappedkey: Option<&mut [u8]>,
|
||||
genkey: Option<&mut [u8]>,
|
||||
) -> Result<(usize, usize), ErrorStack> {
|
||||
let mut wrappedkey_len = wrappedkey.as_ref().map_or(0, |buf| buf.len());
|
||||
let mut genkey_len = genkey.as_ref().map_or(0, |buf| buf.len());
|
||||
|
||||
let wrappedkey_ptr = wrappedkey
|
||||
.map(|buf| buf.as_mut_ptr())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
let genkey_ptr = genkey
|
||||
.map(|buf| buf.as_mut_ptr())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
|
||||
// SAFETY: All pointers are either valid mutable buffers or null.
|
||||
let ret = unsafe {
|
||||
ffi::EVP_PKEY_encapsulate(
|
||||
self.as_ptr() as *mut ffi::EvpPkeyCtx,
|
||||
wrappedkey_ptr,
|
||||
&mut wrappedkey_len,
|
||||
genkey_ptr,
|
||||
&mut genkey_len,
|
||||
)
|
||||
};
|
||||
|
||||
if ret == 1 {
|
||||
Ok((wrappedkey_len, genkey_len))
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Decapsulate a key
|
||||
pub trait PkeyDecapsulateContext {
|
||||
/// Initialize the decapsulation operation.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the OpenSSL operation fails.
|
||||
fn decapsulate_init(&mut self) -> Result<(), ErrorStack>;
|
||||
|
||||
/// Perform the decapsulation operation.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `wrapped`: The wrapped key (ciphertext) to decapsulate.
|
||||
/// - `unwrapped`: Optional buffer to receive the unwrapped shared secret.
|
||||
///
|
||||
/// # Returns
|
||||
/// The length of the unwrapped shared secret on success.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the OpenSSL operation fails.
|
||||
fn decapsulate(
|
||||
&mut self,
|
||||
wrapped: &[u8],
|
||||
unwrapped: Option<&mut [u8]>,
|
||||
) -> Result<usize, ErrorStack>;
|
||||
|
||||
/// Convenience method to decapsulate into a vector.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `wrapped`: The wrapped key (ciphertext) to decapsulate.
|
||||
/// - `unwrapped`: Buffer to receive the unwrapped shared secret.
|
||||
///
|
||||
/// # Returns
|
||||
/// The length of the unwrapped shared secret on success.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the OpenSSL operation fails.
|
||||
fn decapsulate_to_vec(
|
||||
&mut self,
|
||||
wrapped: &[u8],
|
||||
unwrapped: &mut Vec<u8>,
|
||||
) -> Result<usize, ErrorStack> {
|
||||
let unwrapped_base = unwrapped.len();
|
||||
|
||||
// Query the required output buffer size.
|
||||
let unwrapped_len = self.decapsulate(wrapped, None)?;
|
||||
|
||||
unwrapped.resize(unwrapped_base + unwrapped_len, 0);
|
||||
|
||||
let unwrapped_len = self.decapsulate(wrapped, Some(&mut unwrapped[unwrapped_base..]))?;
|
||||
|
||||
unwrapped.truncate(unwrapped_base + unwrapped_len);
|
||||
|
||||
Ok(unwrapped_len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PkeyDecapsulateContext for PkeyCtx<T> {
|
||||
#[inline]
|
||||
fn decapsulate_init(&mut self) -> Result<(), ErrorStack> {
|
||||
// SAFETY: self.as_ptr() returns a valid EVP_PKEY_CTX pointer. Parameter-based
|
||||
// configuration is intentionally unsupported here, so a null params pointer is passed.
|
||||
let ret = unsafe {
|
||||
ffi::EVP_PKEY_decapsulate_init(self.as_ptr() as *mut ffi::EvpPkeyCtx, std::ptr::null())
|
||||
};
|
||||
|
||||
if ret == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
|
||||
fn decapsulate(
|
||||
&mut self,
|
||||
wrapped: &[u8],
|
||||
unwrapped: Option<&mut [u8]>,
|
||||
) -> Result<usize, ErrorStack> {
|
||||
let mut unwrapped_len = unwrapped.as_ref().map_or(0, |buf| buf.len());
|
||||
|
||||
let unwrapped_ptr = unwrapped
|
||||
.map(|buf| buf.as_mut_ptr())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
|
||||
// SAFETY: All pointers are either valid mutable buffers or null, and wrapped is a valid
|
||||
// slice.
|
||||
let ret = unsafe {
|
||||
ffi::EVP_PKEY_decapsulate(
|
||||
self.as_ptr() as *mut ffi::EvpPkeyCtx,
|
||||
unwrapped_ptr,
|
||||
&mut unwrapped_len,
|
||||
wrapped.as_ptr(),
|
||||
wrapped.len(),
|
||||
)
|
||||
};
|
||||
|
||||
if ret == 1 {
|
||||
Ok(unwrapped_len)
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ML-KEM key generation context.
|
||||
///
|
||||
/// The inner pointer is guaranteed to be non-null for the lifetime of the context.
|
||||
pub struct MlKemKeyCtx {
|
||||
ctx: NonNull<ffi::EvpPkeyCtx>,
|
||||
}
|
||||
|
||||
impl MlKemKeyCtx {
|
||||
/// Create a new ML-KEM key generation context.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `key_type`: The ML-KEM key type (`KeyType::ML_KEM_512`, `KeyType::ML_KEM_768`, or
|
||||
/// `KeyType::ML_KEM_1024`).
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the context cannot be created or the key type is unsupported.
|
||||
pub fn new(key_type: KeyType) -> Result<Self, ErrorStack> {
|
||||
let name = ml_kem_name(key_type)?;
|
||||
|
||||
// SAFETY: name is a valid null-terminated C string.
|
||||
let ctx = unsafe {
|
||||
ffi::EVP_PKEY_CTX_new_from_name(std::ptr::null_mut(), name.as_ptr(), std::ptr::null())
|
||||
};
|
||||
let Some(ctx) = NonNull::new(ctx) else {
|
||||
return Err(ErrorStack::get());
|
||||
};
|
||||
|
||||
// SAFETY: ctx is a valid non-null pointer.
|
||||
let ret = unsafe { ffi::EVP_PKEY_keygen_init(ctx.as_ptr()) };
|
||||
if ret != 1 {
|
||||
// SAFETY: ctx is a valid non-null pointer.
|
||||
unsafe { ffi::EVP_PKEY_CTX_free(ctx.as_ptr()) };
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
|
||||
Ok(Self { ctx })
|
||||
}
|
||||
|
||||
/// Generate an ML-KEM keypair.
|
||||
///
|
||||
/// # Returns
|
||||
/// A `PKey` containing both the private and public key.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if key generation fails.
|
||||
pub fn generate(&mut self) -> Result<PKey<Private>, ErrorStack> {
|
||||
let mut pkey: *mut std::os::raw::c_void = std::ptr::null_mut();
|
||||
|
||||
// SAFETY: self.ctx is valid, and pkey is a valid mutable pointer.
|
||||
let ret = unsafe { ffi::EVP_PKEY_generate(self.ctx.as_ptr(), &mut pkey) };
|
||||
|
||||
if ret != 1 || pkey.is_null() {
|
||||
return Err(ErrorStack::get());
|
||||
}
|
||||
|
||||
// SAFETY: pkey is a valid EVP_PKEY pointer created by OpenSSL.
|
||||
unsafe { Ok(PKey::from_ptr(pkey as *mut openssl_sys::EVP_PKEY)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MlKemKeyCtx {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: self.ctx is guaranteed to be non-null and owned by this context.
|
||||
unsafe {
|
||||
ffi::EVP_PKEY_CTX_free(self.ctx.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate an ML-KEM keypair.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `key_type`: The ML-KEM key type (`KeyType::ML_KEM_512`, `KeyType::ML_KEM_768`, or
|
||||
/// `KeyType::ML_KEM_1024`).
|
||||
///
|
||||
/// # Returns
|
||||
/// A `PKey` containing both the private and public key.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if key generation fails.
|
||||
pub fn generate_ml_kem(key_type: KeyType) -> Result<PKey<Private>, ErrorStack> {
|
||||
let mut ctx = MlKemKeyCtx::new(key_type)?;
|
||||
ctx.generate()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn roundtrip_ml_kem(key_type: KeyType, expected_ciphertext_len: usize) {
|
||||
let keypair = generate_ml_kem(key_type).expect("Failed to generate ML-KEM keypair");
|
||||
|
||||
// Extract public key for encapsulation
|
||||
let public_key_der = keypair
|
||||
.public_key_to_der()
|
||||
.expect("Failed to export public key");
|
||||
let public_key =
|
||||
PKey::public_key_from_der(&public_key_der).expect("Failed to import public key");
|
||||
|
||||
// Encapsulate: generate ciphertext and shared secret using public key
|
||||
let mut ctx_enc =
|
||||
PkeyCtx::new(&public_key).expect("Failed to create encapsulation context");
|
||||
ctx_enc
|
||||
.encapsulate_init()
|
||||
.expect("Failed to initialize encapsulation");
|
||||
|
||||
let mut ciphertext = Vec::new();
|
||||
let mut shared_secret_enc = Vec::new();
|
||||
ctx_enc
|
||||
.encapsulate_to_vec(&mut ciphertext, &mut shared_secret_enc)
|
||||
.expect("Failed to encapsulate");
|
||||
|
||||
assert!(!ciphertext.is_empty(), "Ciphertext should not be empty");
|
||||
assert!(
|
||||
!shared_secret_enc.is_empty(),
|
||||
"Shared secret should not be empty"
|
||||
);
|
||||
|
||||
// Decapsulate: recover shared secret from ciphertext using private key
|
||||
let mut ctx_dec = PkeyCtx::new(&keypair).expect("Failed to create decapsulation context");
|
||||
ctx_dec
|
||||
.decapsulate_init()
|
||||
.expect("Failed to initialize decapsulation");
|
||||
|
||||
let mut shared_secret_dec = Vec::new();
|
||||
ctx_dec
|
||||
.decapsulate_to_vec(&ciphertext, &mut shared_secret_dec)
|
||||
.expect("Failed to decapsulate");
|
||||
|
||||
// Verify that the shared secrets match
|
||||
assert_eq!(
|
||||
shared_secret_enc, shared_secret_dec,
|
||||
"Shared secrets from encapsulation and decapsulation should match"
|
||||
);
|
||||
assert_eq!(ciphertext.len(), expected_ciphertext_len);
|
||||
assert_eq!(shared_secret_enc.len(), 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encapsulate_decapsulate_roundtrip_ml_kem_512() {
|
||||
roundtrip_ml_kem(KeyType::ML_KEM_512, 768);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encapsulate_decapsulate_roundtrip_ml_kem_768() {
|
||||
roundtrip_ml_kem(KeyType::ML_KEM_768, 1088);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encapsulate_decapsulate_roundtrip_ml_kem_1024() {
|
||||
roundtrip_ml_kem(KeyType::ML_KEM_1024, 1568);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ml_kem_key_ctx_new_accepts_supported_key_types() {
|
||||
MlKemKeyCtx::new(KeyType::ML_KEM_512).expect("ML-KEM-512 context creation must succeed");
|
||||
MlKemKeyCtx::new(KeyType::ML_KEM_768).expect("ML-KEM-768 context creation must succeed");
|
||||
MlKemKeyCtx::new(KeyType::ML_KEM_1024).expect("ML-KEM-1024 context creation must succeed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ml_kem_key_ctx_new_rejects_unsupported_key_type() {
|
||||
assert!(
|
||||
MlKemKeyCtx::new(KeyType::RSA).is_err(),
|
||||
"Unsupported key type must fail"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ml_kem_key_ctx_generate_produces_ml_kem_keypair() {
|
||||
let mut ctx = MlKemKeyCtx::new(KeyType::ML_KEM_768)
|
||||
.expect("ML-KEM-768 context creation must succeed");
|
||||
let keypair = ctx
|
||||
.generate()
|
||||
.expect("ML-KEM-768 key generation must succeed");
|
||||
|
||||
let public_key_der = keypair
|
||||
.public_key_to_der()
|
||||
.expect("Generated keypair must export a public key");
|
||||
let public_key =
|
||||
PKey::public_key_from_der(&public_key_der).expect("Generated public key must reimport");
|
||||
|
||||
let mut ctx_enc =
|
||||
PkeyCtx::new(&public_key).expect("Failed to create encapsulation context");
|
||||
ctx_enc
|
||||
.encapsulate_init()
|
||||
.expect("Failed to initialize encapsulation");
|
||||
|
||||
let mut ciphertext = Vec::new();
|
||||
let mut shared_secret = Vec::new();
|
||||
ctx_enc
|
||||
.encapsulate_to_vec(&mut ciphertext, &mut shared_secret)
|
||||
.expect("Generated keypair must support encapsulation");
|
||||
|
||||
assert_eq!(ciphertext.len(), 1088);
|
||||
assert_eq!(shared_secret.len(), 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_ml_kem_rejects_unsupported_key_type() {
|
||||
generate_ml_kem(KeyType::RSA).expect_err("Unsupported key type must fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encapsulate_requires_init() {
|
||||
let keypair =
|
||||
generate_ml_kem(KeyType::ML_KEM_512).expect("Failed to generate ML-KEM-512 keypair");
|
||||
let public_key_der = keypair
|
||||
.public_key_to_der()
|
||||
.expect("Failed to export public key");
|
||||
let public_key =
|
||||
PKey::public_key_from_der(&public_key_der).expect("Failed to import public key");
|
||||
|
||||
let mut ctx_enc =
|
||||
PkeyCtx::new(&public_key).expect("Failed to create encapsulation context");
|
||||
let err = ctx_enc
|
||||
.encapsulate_to_vec(&mut Vec::new(), &mut Vec::new())
|
||||
.expect_err("Encapsulation without init must fail");
|
||||
|
||||
assert!(
|
||||
!err.errors().is_empty(),
|
||||
"OpenSSL should report an error when encapsulate_init was not called"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decapsulate_requires_init() {
|
||||
let keypair =
|
||||
generate_ml_kem(KeyType::ML_KEM_512).expect("Failed to generate ML-KEM-512 keypair");
|
||||
let mut ctx_dec = PkeyCtx::new(&keypair).expect("Failed to create decapsulation context");
|
||||
let err = ctx_dec
|
||||
.decapsulate_to_vec(&[0_u8; 768], &mut Vec::new())
|
||||
.expect_err("Decapsulation without init must fail");
|
||||
|
||||
assert!(
|
||||
!err.errors().is_empty(),
|
||||
"OpenSSL should report an error when decapsulate_init was not called"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decapsulate_rejects_undersized_output_buffer() {
|
||||
let keypair =
|
||||
generate_ml_kem(KeyType::ML_KEM_768).expect("Failed to generate ML-KEM-768 keypair");
|
||||
|
||||
let public_key_der = keypair
|
||||
.public_key_to_der()
|
||||
.expect("Failed to export public key");
|
||||
let public_key =
|
||||
PKey::public_key_from_der(&public_key_der).expect("Failed to import public key");
|
||||
|
||||
let mut ctx_enc =
|
||||
PkeyCtx::new(&public_key).expect("Failed to create encapsulation context");
|
||||
ctx_enc
|
||||
.encapsulate_init()
|
||||
.expect("Failed to initialize encapsulation");
|
||||
|
||||
let mut ciphertext = Vec::new();
|
||||
let mut shared_secret = Vec::new();
|
||||
ctx_enc
|
||||
.encapsulate_to_vec(&mut ciphertext, &mut shared_secret)
|
||||
.expect("Failed to encapsulate");
|
||||
|
||||
let mut ctx_dec = PkeyCtx::new(&keypair).expect("Failed to create decapsulation context");
|
||||
ctx_dec
|
||||
.decapsulate_init()
|
||||
.expect("Failed to initialize decapsulation");
|
||||
|
||||
let mut undersized = [0_u8; 31];
|
||||
let err = ctx_dec
|
||||
.decapsulate(&ciphertext, Some(&mut undersized))
|
||||
.expect_err("Undersized output buffer must fail");
|
||||
|
||||
assert!(
|
||||
!err.errors().is_empty(),
|
||||
"OpenSSL should report an error for an undersized output buffer"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,11 @@
|
||||
mod akid;
|
||||
mod bio;
|
||||
mod crl;
|
||||
mod ml_kem;
|
||||
mod stackable_crl;
|
||||
|
||||
pub use akid::*;
|
||||
pub use bio::*;
|
||||
pub use crl::*;
|
||||
#[expect(unused_imports)]
|
||||
pub use ml_kem::*;
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use crate::openssl_extensions::bio::BioMemSlice;
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use openssl::{
|
||||
error::ErrorStack,
|
||||
stack::Stackable,
|
||||
x509::{X509Crl, X509CrlRef},
|
||||
};
|
||||
use std::ptr;
|
||||
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::stack::Stackable;
|
||||
use openssl::x509::{X509Crl, X509CrlRef};
|
||||
|
||||
use crate::openssl_extensions::bio::BioMemSlice;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StackableX509Crl(*mut openssl_sys::X509_CRL);
|
||||
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use crate::Result;
|
||||
use crate::{openssl_extensions::BioMem, Error};
|
||||
use std::ffi::{c_char, CString};
|
||||
use std::fmt::Display;
|
||||
|
||||
use openssl::error::ErrorStack;
|
||||
use pv_core::request::Confidential;
|
||||
use std::{
|
||||
ffi::{c_char, CString},
|
||||
fmt::Display,
|
||||
};
|
||||
|
||||
use crate::openssl_extensions::BioMem;
|
||||
use crate::{Error, Result};
|
||||
|
||||
mod ffi {
|
||||
use openssl_sys::BIO;
|
||||
use std::ffi::{c_char, c_int, c_long, c_uchar};
|
||||
|
||||
use openssl_sys::BIO;
|
||||
extern "C" {
|
||||
pub fn PEM_write_bio(
|
||||
bio: *mut BIO,
|
||||
@@ -141,8 +142,8 @@ impl Pem {
|
||||
|
||||
let inner_pem = InnerPem::new(name, header, data.as_ref())?;
|
||||
|
||||
// Create the PEM format eagerly so that to_string/display cannot fail because of ASCII or OpenSSL Errors
|
||||
// Both error should be very unlikely
|
||||
// Create the PEM format eagerly so that to_string/display cannot fail because of ASCII or
|
||||
// OpenSSL Errors Both error should be very unlikely
|
||||
// OpenSSL should be able to create PEM if there is enough memory and produce a non-null
|
||||
// terminated ASCII-string
|
||||
// Unwrap succeeds it's all ASCII
|
||||
|
||||
@@ -1,692 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
use std::mem::size_of;
|
||||
|
||||
use openssl::{
|
||||
bn::{BigNum, BigNumContext},
|
||||
ec::{EcGroup, EcGroupRef, EcKey, EcPointRef},
|
||||
error::ErrorStack,
|
||||
hash::{DigestBytes, MessageDigest},
|
||||
nid::Nid,
|
||||
pkey::{PKey, PKeyRef, Private, Public},
|
||||
};
|
||||
use pv_core::request::{RequestMagic, RequestVersion};
|
||||
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, U32};
|
||||
|
||||
use crate::{
|
||||
assert_size,
|
||||
crypto::{
|
||||
decrypt_aead, derive_aes256_gcm_key, encrypt_aead, gen_ec_key, hash, random_array,
|
||||
AeadEncryptionResult, SymKey, SymKeyType,
|
||||
},
|
||||
misc::to_u32,
|
||||
request::Confidential,
|
||||
Error, Result,
|
||||
};
|
||||
/// Encrypt a _secret_ using self and a given private key.
|
||||
pub trait Encrypt {
|
||||
/// Encrypts `secret` using `self` and `priv_key` the encryption.
|
||||
///
|
||||
/// # Returns
|
||||
/// the encrypted data.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not encrypt the secret.
|
||||
fn encrypt(&self, secret: &[u8], priv_key: &PKeyRef<Private>) -> Result<Vec<u8>> {
|
||||
let mut res = Vec::with_capacity(80);
|
||||
self.encrypt_to(secret, priv_key, &mut res)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Encrypts `secret` using `self` and `priv_key` the encryption.
|
||||
/// Appends the encrypted data to `to`
|
||||
///
|
||||
/// # Returns
|
||||
/// The encrypted data.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not encrypt the secret.
|
||||
fn encrypt_to(
|
||||
&self,
|
||||
secret: &[u8],
|
||||
priv_key: &PKeyRef<Private>,
|
||||
to: &mut Vec<u8>,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Types of Authenticated Data
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub enum Aad<'a> {
|
||||
/// Authenticated Keyslot
|
||||
Ks(&'a Keyslot),
|
||||
/// Unchanged authenticated data
|
||||
Plain(&'a [u8]),
|
||||
/// Authenticated data that has to be encrypted in beforehand
|
||||
Encr(&'a dyn Encrypt),
|
||||
}
|
||||
|
||||
/// IBM Z Host key-slot
|
||||
///
|
||||
/// Layout in binary format:
|
||||
/// ```none
|
||||
/// _______________________________________________________________
|
||||
/// | Public Host Key Hash (32) |
|
||||
/// | Wrapped(=Encrypted) Request Protection Key(32) |
|
||||
/// | Key Slot Tag (16) |
|
||||
/// |_____________________________________________________________|
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Keyslot(PKey<Public>);
|
||||
|
||||
impl Keyslot {
|
||||
/// Size of a host-key hash
|
||||
pub const PHKH_SIZE: u32 = 0x20;
|
||||
|
||||
/// Creates a new Keyslot from the provided public key
|
||||
pub fn new(hostkey: PKey<Public>) -> Self {
|
||||
Self(hostkey)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encrypt for Keyslot {
|
||||
/// Encrypts the given request protection key `prot_key`.
|
||||
///
|
||||
/// The AES256 encryption key is derived from `self` as public key, and `priv_key` as private
|
||||
/// key.
|
||||
///
|
||||
/// # Returns
|
||||
/// The encrypted Keyslot.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not encrypt the secret.
|
||||
fn encrypt_to(
|
||||
&self,
|
||||
prot_key: &[u8],
|
||||
priv_key: &PKeyRef<Private>,
|
||||
to: &mut Vec<u8>,
|
||||
) -> Result<()> {
|
||||
let derived_key = derive_aes256_gcm_key(priv_key, &self.0)?;
|
||||
let mut wrpk_and_kst =
|
||||
encrypt_aead(&derived_key.into(), &[0; 12], &[], prot_key)?.into_buf();
|
||||
let phk: EcPubKeyCoord = self.0.as_ref().try_into()?;
|
||||
|
||||
to.reserve(80);
|
||||
to.extend_from_slice(&hash(MessageDigest::sha256(), phk.as_ref())?);
|
||||
to.append(&mut wrpk_and_kst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Context used to manage the encryption of requests.
|
||||
/// Intended to be used by [`Request`] implementations
|
||||
#[derive(Debug)]
|
||||
pub struct ReqEncrCtx {
|
||||
iv: [u8; 12],
|
||||
priv_key: PKey<Private>,
|
||||
prot_key: SymKey,
|
||||
}
|
||||
impl ReqEncrCtx {
|
||||
/// Create a new encryption context that uses AES256.
|
||||
///
|
||||
/// * `iv` - Initialization vector for the request encryption
|
||||
/// * `priv_key` - Private key to wrap [`Keyslot`]
|
||||
/// * `prot_key` - Symmetric key for request encryption. Part of [`Keyslot`]
|
||||
///
|
||||
/// If an argument is set to `None` a ranom is generated
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not generate a random value.
|
||||
pub fn new_aes_256<I, P, S>(iv: I, priv_key: P, prot_key: S) -> Result<Self>
|
||||
where
|
||||
I: Into<Option<[u8; 12]>>,
|
||||
P: Into<Option<PKey<Private>>>,
|
||||
S: Into<Option<SymKey>>,
|
||||
{
|
||||
let iv = iv.into().unwrap_or(random_array()?);
|
||||
let priv_key = priv_key.into().unwrap_or(gen_ec_key(Nid::SECP521R1)?);
|
||||
let prot_key = prot_key
|
||||
.into()
|
||||
.unwrap_or(SymKey::random(SymKeyType::Aes256Gcm)?);
|
||||
Ok(Self {
|
||||
iv,
|
||||
priv_key,
|
||||
prot_key,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new encryption context with random input values.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not generate a random value.
|
||||
pub fn random(ket_tp: SymKeyType) -> Result<Self> {
|
||||
match ket_tp {
|
||||
SymKeyType::Aes256Gcm => Self::new_aes_256(None, None, None),
|
||||
SymKeyType::Aes256Xts => Err(Error::NoAeadKey),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the authenticated data for a request.
|
||||
/// # Returns
|
||||
/// ```none
|
||||
/// _______________________________________________________________
|
||||
/// | MAGIC (8) Version Number (4) Size (4)|
|
||||
/// | IV (12) Reserved (4)|
|
||||
/// | Reserved (7) Num keyslots (1) Reserved(4) Encr Size (4)|
|
||||
/// | --------------------------------------------------- |
|
||||
/// | Request type dependent AAD data |
|
||||
/// |-------------------------------------------------------------|
|
||||
/// ```
|
||||
pub fn build_aad<O>(
|
||||
&self,
|
||||
version: RequestVersion,
|
||||
aad: &Vec<Aad>,
|
||||
encr_size: usize,
|
||||
magic: O,
|
||||
) -> Result<Vec<u8>>
|
||||
where
|
||||
O: Into<Option<RequestMagic>>,
|
||||
{
|
||||
self.build_aad_impl(version, aad, encr_size, magic.into())
|
||||
}
|
||||
|
||||
/// Concrete implementation for [`ReqEncrCtx::build_aad`].
|
||||
fn build_aad_impl(
|
||||
&self,
|
||||
version: RequestVersion,
|
||||
aad: &Vec<Aad>,
|
||||
encr_size: usize,
|
||||
magic: Option<RequestMagic>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let nks = aad.iter().filter(|a| matches!(a, Aad::Ks(_))).count();
|
||||
let nks: u8 = match nks {
|
||||
0 => Err(Error::NoHostkey),
|
||||
n if n > u8::MAX as usize => Err(Error::ManyHostkeys),
|
||||
n => Ok(n as u8),
|
||||
}?;
|
||||
let mut auth_data: Vec<u8> = Vec::with_capacity(2048);
|
||||
|
||||
// reserve space for the request header
|
||||
auth_data.resize(size_of::<RequestHdr>(), 0);
|
||||
|
||||
for a in aad {
|
||||
match a {
|
||||
Aad::Plain(p) => auth_data.extend_from_slice(p),
|
||||
Aad::Ks(ks) => {
|
||||
ks.encrypt_to(self.prot_key.value(), &self.priv_key, &mut auth_data)?
|
||||
}
|
||||
Aad::Encr(e) => {
|
||||
e.encrypt_to(self.prot_key.value(), &self.priv_key, &mut auth_data)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(|| 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
|
||||
auth_data[..size_of::<RequestHdr>()].copy_from_slice(req_hdr.as_bytes());
|
||||
Ok(auth_data)
|
||||
}
|
||||
|
||||
/// Get the public coordinates from the private key (Customer private key)
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the public key could not be extracted by OpenSSL.
|
||||
/// Very unlikely.
|
||||
pub fn key_coords(&self) -> Result<EcPubKeyCoord> {
|
||||
self.priv_key.as_ref().try_into().map_err(Error::Crypto)
|
||||
}
|
||||
|
||||
/// Encrypt confidential Data with this encryption context and provide a GCM tag.
|
||||
///
|
||||
/// * `aad` - additional authentic data
|
||||
/// * `conf` - data to be encrypted
|
||||
///
|
||||
/// # Returns
|
||||
/// [`Vec<u8>`] with the following content:
|
||||
/// 1. `aad`
|
||||
/// 2. `encr(conf)`
|
||||
/// 3. `aes gcm tag`
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the data could not be encrypted by OpenSSL.
|
||||
pub(crate) fn encrypt_aead(&self, aad: &[u8], conf: &[u8]) -> Result<AeadEncryptionResult> {
|
||||
encrypt_aead(&self.prot_key, &self.iv, aad, conf)
|
||||
}
|
||||
|
||||
/// Returns a reference to the request protection key of this [`ReqEncrCtx`].
|
||||
pub fn prot_key(&self) -> &SymKey {
|
||||
&self.prot_key
|
||||
}
|
||||
}
|
||||
|
||||
/// Public key components of an [`openssl::ec::EcKey`] key.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EcPubKeyCoord([u8; 160]);
|
||||
impl AsRef<[u8]> for EcPubKeyCoord {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
const ECDH_PUB_KEY_COORD_POINT_SIZE: usize = 0x50;
|
||||
|
||||
impl EcPubKeyCoord {
|
||||
/// Returns the SHA256 hash of the [`EcPubKeyCoord`].
|
||||
///
|
||||
/// If [`EcPubKeyCoord`] was built from a host-key, this value is the public host-key hash.
|
||||
pub fn sha256(&self) -> Result<DigestBytes> {
|
||||
hash(MessageDigest::sha256(), self.as_ref())
|
||||
}
|
||||
|
||||
/// Construct a [`EcPubKeyCoord`]
|
||||
///
|
||||
/// # Safety
|
||||
/// This function is marked unsafe, because data not representing two EC points violates the
|
||||
/// invariant of this struct.
|
||||
pub unsafe fn from_data(data: [u8; 160]) -> Self {
|
||||
EcPubKeyCoord(data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the pub ECDH coordinates in the format the Ultravisor expects it:
|
||||
/// The two coordinates are padded to 80 bytes each.
|
||||
fn get_pub_ecdh_points(pkey: &EcPointRef, grp: &EcGroupRef) -> Result<[u8; 160], ErrorStack> {
|
||||
let mut x = BigNum::new()?;
|
||||
let mut y = BigNum::new()?;
|
||||
let mut bn_ctx = BigNumContext::new()?;
|
||||
pkey.affine_coordinates(grp, &mut x, &mut y, &mut bn_ctx)?;
|
||||
let mut coord: Vec<u8> = x.to_vec_padded(ECDH_PUB_KEY_COORD_POINT_SIZE as i32)?;
|
||||
coord.append(&mut y.to_vec_padded(ECDH_PUB_KEY_COORD_POINT_SIZE as i32)?);
|
||||
Ok(coord.try_into().unwrap())
|
||||
}
|
||||
|
||||
impl TryFrom<EcPubKeyCoord> for PKey<Public> {
|
||||
type Error = ErrorStack;
|
||||
|
||||
fn try_from(value: EcPubKeyCoord) -> Result<Self, Self::Error> {
|
||||
let ecdh = value.as_ref();
|
||||
let grp = EcGroup::from_curve_name(Nid::SECP521R1)?;
|
||||
let x = BigNum::from_slice(&ecdh[..ECDH_PUB_KEY_COORD_POINT_SIZE])?;
|
||||
let y = BigNum::from_slice(&ecdh[ECDH_PUB_KEY_COORD_POINT_SIZE..])?;
|
||||
let ec_key = EcKey::from_public_key_affine_coordinates(&grp, &x, &y)?;
|
||||
Self::from_ec_key(ec_key)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! ecdh_from {
|
||||
($type: ty) => {
|
||||
impl TryFrom<&PKeyRef<$type>> for EcPubKeyCoord {
|
||||
type Error = ErrorStack;
|
||||
|
||||
fn try_from(key: &PKeyRef<$type>) -> Result<Self, Self::Error> {
|
||||
let k = key.ec_key()?;
|
||||
k.check_key()?;
|
||||
let grp = k.group();
|
||||
let pub_key = k.public_key();
|
||||
let coord = get_pub_ecdh_points(pub_key, grp)?;
|
||||
Ok(Self(coord))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PKey<$type>> for EcPubKeyCoord {
|
||||
type Error = ErrorStack;
|
||||
|
||||
fn try_from(key: PKey<$type>) -> Result<Self, Self::Error> {
|
||||
let key_ref = key.as_ref();
|
||||
key_ref.try_into()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ecdh_from!(Private);
|
||||
ecdh_from!(Public);
|
||||
|
||||
/// Representation of the shared parts of the request header.
|
||||
/// Used by [`ReqEncrCtx`]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable)]
|
||||
struct RequestHdr {
|
||||
magic: [u8; 8],
|
||||
rqvn: U32<BigEndian>,
|
||||
rql: U32<BigEndian>,
|
||||
iv: [u8; 12],
|
||||
reserved1c: [u8; 4],
|
||||
reserved20: [u8; 7],
|
||||
nks: u8,
|
||||
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 {
|
||||
Self {
|
||||
magic: magic.unwrap_or_default(),
|
||||
rqvn: rqvn.into(),
|
||||
rql: rql.into(),
|
||||
iv,
|
||||
reserved1c: [0; 4],
|
||||
reserved20: [0; 7],
|
||||
nks,
|
||||
reserved28: 0,
|
||||
sea: sea.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait representing a request for the Ultravisor.
|
||||
///
|
||||
/// All requests share a few things:
|
||||
/// * All requests need to be encrypted on a trusted machine
|
||||
/// * All requests have at least one Hostkeyslot
|
||||
///
|
||||
/// The encryption setup is handled by [`ReqEncrCtx`]. Implementers need to pass the data to the
|
||||
/// `ReqEncrCtx` when implementing `encrypt`. A hostkey should be represented by [`Keyslot`] during
|
||||
/// encryption.
|
||||
///
|
||||
/// An UV request consists of an authenticated area (AAD), an encrypted area (Encr) and a 16 byte
|
||||
/// tag. The AAD contains a general header and Request type defined data (including Keyslots). It
|
||||
/// is encrypted with an Request protection key (symmetric). This key is encrypted with a
|
||||
/// (generated) private key and the public key of the host system (Host key)
|
||||
/// ```none
|
||||
/// _______________________________________________________________
|
||||
/// | MAGIC (8) Version Number (4) Size (4)|
|
||||
/// | IV (12) Reserved (4)|
|
||||
/// | Reserved (7) Num keyslots (1) Reserved(4) Encr Size (4)|
|
||||
/// | --------------------------------------------------- |
|
||||
/// | Request type dependent AAD data |
|
||||
/// | ---------------------------------------------------- |
|
||||
/// | Encrypted (request type dependent) data |
|
||||
/// | ---------------------------------------------------- |
|
||||
/// | AES GCM Tag (16) |
|
||||
/// |_____________________________________________________________|
|
||||
/// ```
|
||||
pub trait Request {
|
||||
/// Encrypt the request into its binary format
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the encryption fails, the request does not have at
|
||||
/// least a hostkey, or other implementation dependent contracts are not met.
|
||||
fn encrypt(&self, ctx: &ReqEncrCtx) -> Result<Vec<u8>>;
|
||||
/// Add a host-key to this request
|
||||
///
|
||||
/// Must be called at least once, otherwise {`Request::encrypt`} will fail
|
||||
fn add_hostkey(&mut self, hostkey: PKey<Public>);
|
||||
}
|
||||
|
||||
/// A struct to represent some parts of a binary/encrypted request.
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
pub(crate) 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 = SymKeyType::AES_256_GCM_TAG_LEN;
|
||||
|
||||
/// Get the locations from this request.
|
||||
///
|
||||
/// Does minimal sanity test, just tests to prevent panics.
|
||||
/// `req` may be larger than the actual request.
|
||||
pub(crate) fn get(req: &'a [u8]) -> Result<Self> {
|
||||
let (hdr, _) = RequestHdr::read_from_prefix(req).map_err(|_| 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(crate) fn version(&self) -> u32 {
|
||||
self.version
|
||||
}
|
||||
|
||||
/// Returns the length of this [`BinReqValues`].
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Returns the size of the encrypted area
|
||||
pub(crate) fn sea(&self) -> u32 {
|
||||
self.encr.len() as u32
|
||||
}
|
||||
|
||||
/// Decrypts the encrypted area with the provided key
|
||||
pub(crate) fn decrypt(&self, key: &SymKey) -> Result<Confidential<Vec<u8>>> {
|
||||
let result = decrypt_aead(key, self.iv, self.aad, self.encr, self.tag)?;
|
||||
Ok(result.into_plain())
|
||||
}
|
||||
|
||||
/// Returns a reference to the request dependent authenticated area of this [`BinReqValues`]
|
||||
/// already interpreted.
|
||||
///
|
||||
/// If target struct is larger than the request depended-AAD None is returned. See
|
||||
/// [`FromBytes::ref_from_prefix`]
|
||||
pub(crate) fn req_dep_aad<T>(&self) -> Option<&T>
|
||||
where
|
||||
T: FromBytes + Sized + Immutable + KnownLayout,
|
||||
{
|
||||
T::ref_from_prefix(self.req_dep_aad).map(|s| s.0).ok()
|
||||
}
|
||||
|
||||
/// Returns a reference to the tag of this [`BinReqValues`].
|
||||
pub(crate) fn tag(&self) -> &[u8] {
|
||||
self.tag
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{get_test_asset, request::SymKey, test_utils::*};
|
||||
|
||||
static TEST_MAGIC: [u8; 8] = 0x12345689abcdef00u64.to_be_bytes();
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad() {
|
||||
let (cust_key, host_key) = get_test_keys();
|
||||
let ks = Keyslot::new(host_key);
|
||||
let ctx = ReqEncrCtx::new_aes_256(
|
||||
Some([0x11; 12]),
|
||||
Some(cust_key),
|
||||
Some(SymKey::Aes256([0x17; 32].into())),
|
||||
)
|
||||
.unwrap();
|
||||
let v = [0x55; 8];
|
||||
let aad = Aad::Plain(&v);
|
||||
let aad = ctx
|
||||
.build_aad(0x200, &vec![aad, Aad::Ks(&ks)], 16, Some(TEST_MAGIC))
|
||||
.unwrap();
|
||||
|
||||
let mut aad_exp = vec![
|
||||
0x12, 0x34, 0x56, 0x89, 0xab, 0xcd, 0xef, 0, // progr
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0, 168, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
1, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 16, // sea
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // aad
|
||||
];
|
||||
aad_exp.extend_from_slice(get_test_asset!("exp/keyslot.bin"));
|
||||
assert_eq!(&aad, &aad_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad_nks_no() {
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let aad = Vec::<Aad>::new();
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
|
||||
assert!(matches!(aad, Err(Error::NoHostkey)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad_nks_many() {
|
||||
let (_, host_key) = get_test_keys();
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let ks: Vec<Keyslot> = (0..257).map(|_| Keyslot::new(host_key.clone())).collect();
|
||||
let mut aad = Vec::<Aad>::new();
|
||||
ks.iter().for_each(|ks| aad.push(Aad::Ks(ks)));
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
|
||||
assert!(matches!(aad, Err(Error::ManyHostkeys)));
|
||||
}
|
||||
#[test]
|
||||
fn encr_build_aad_nks() {
|
||||
let (_, host_key) = get_test_keys();
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let ks = [
|
||||
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)));
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC)).unwrap();
|
||||
|
||||
assert_eq!(aad.get(39).unwrap(), &3u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn req_hdr() {
|
||||
let hdr = RequestHdr::new(0x200, 22, [0x11; 12], 15, 44, None);
|
||||
let hdr_bin = hdr.as_bytes();
|
||||
let hdr_bin_exp = [
|
||||
0u8, 0, 0, 0, 0, 0, 0, 0, // magic
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0, 22, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
15, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 44, // sea
|
||||
];
|
||||
assert_eq!(hdr_bin, &hdr_bin_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn req_hdr2() {
|
||||
let mut hdr = RequestHdr::new(0x200, 0x1234, [0x11; 12], 15, 44, Some(TEST_MAGIC));
|
||||
let hdr_bin = hdr.as_mut_bytes();
|
||||
let hdr_bin_exp = [
|
||||
0x12, 0x34, 0x56, 0x89, 0xab, 0xcd, 0xef, 0, // magic
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0x12, 0x34, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
15, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 44, // sea
|
||||
];
|
||||
assert_eq!(hdr_bin, &hdr_bin_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyslot() {
|
||||
let (cust_key, host_key) = get_test_keys();
|
||||
let exp_keyslot = get_test_asset!("exp/keyslot.bin").to_vec();
|
||||
|
||||
let keyslot = Keyslot::new(host_key);
|
||||
let encr_ks = keyslot.encrypt(&[0x17u8; 32], &cust_key).unwrap();
|
||||
|
||||
assert_eq!(exp_keyslot, encr_ks);
|
||||
|
||||
let encr_ks = keyslot.encrypt(&[0x16u8; 32], &cust_key).unwrap();
|
||||
assert_ne!(exp_keyslot, encr_ks);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ec_pub_ec_coord_from() {
|
||||
let (cust_key, _) = get_test_keys();
|
||||
let pub_key = get_test_asset!("keys/public_cust.bin");
|
||||
assert_eq!(pub_key.len(), 160);
|
||||
|
||||
let ec_coord: EcPubKeyCoord = cust_key.as_ref().try_into().unwrap();
|
||||
assert_eq!(ec_coord.as_ref(), pub_key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ec_pub_ec_coord_hash() {
|
||||
let exp = [
|
||||
0x5e, 0xe9, 0x05, 0xa9, 0xbe, 0x70, 0x36, 0x68, 0x15, 0xa4, 0x56, 0x41, 0xaf, 0xae,
|
||||
0x00, 0x97, 0x3b, 0x1f, 0x45, 0x29, 0x2f, 0x43, 0xbc, 0xd7, 0x63, 0x8e, 0xe2, 0xa7,
|
||||
0x3f, 0xd7, 0xc4, 0x5e,
|
||||
];
|
||||
let (cust_key, _) = get_test_keys();
|
||||
let ec_coord: EcPubKeyCoord = cust_key.as_ref().try_into().unwrap();
|
||||
let hash = ec_coord.sha256().unwrap();
|
||||
|
||||
assert_eq!(hash.as_ref(), &exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_ecdh_and_vice_versa() {
|
||||
let (_, cust_pub) = get_test_keys();
|
||||
let phk: EcPubKeyCoord = cust_pub.clone().try_into().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
phk.as_ref(),
|
||||
&[
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 118, 136, 28, 216, 75, 139, 109, 231,
|
||||
18, 60, 126, 144, 14, 223, 120, 231, 247, 182, 132, 153, 145, 70, 177, 38, 59, 168,
|
||||
184, 108, 132, 71, 240, 138, 182, 212, 105, 194, 177, 40, 237, 158, 28, 53, 1, 88,
|
||||
5, 172, 211, 211, 2, 51, 211, 145, 34, 247, 226, 248, 170, 28, 43, 20, 123, 120,
|
||||
131, 180, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 69, 86, 194, 92,
|
||||
249, 47, 41, 206, 102, 189, 68, 17, 77, 107, 123, 60, 120, 225, 58, 63, 144, 189,
|
||||
185, 0, 64, 246, 135, 110, 82, 98, 247, 120, 166, 26, 147, 125, 27, 52, 128, 46,
|
||||
178, 87, 227, 78, 6, 114, 221, 95, 42, 52, 122, 221, 170, 40, 32, 53, 9, 42, 112,
|
||||
195, 92, 46, 121, 115
|
||||
]
|
||||
);
|
||||
let cust_pub_back: PKey<Public> = phk.try_into().unwrap();
|
||||
assert!(cust_pub.public_eq(&cust_pub_back));
|
||||
}
|
||||
}
|
||||
257
rust/pv/src/req/context.rs
Normal file
257
rust/pv/src/req/context.rs
Normal file
@@ -0,0 +1,257 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
//! Request encryption context for managing UV request encryption.
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
use openssl::nid::Nid;
|
||||
use openssl::pkey::{PKey, Private};
|
||||
use pv_core::request::{RequestMagic, RequestVersion};
|
||||
use zerocopy::IntoBytes;
|
||||
|
||||
use super::{Aad, EcPubKeyCoord, Encrypt, RequestHdr};
|
||||
use crate::crypto::{
|
||||
encrypt_aead, gen_ec_key, random_array, AeadEncryptionResult, SymKey, SymKeyType,
|
||||
};
|
||||
use crate::misc::to_u32;
|
||||
use crate::{Error, Result};
|
||||
|
||||
/// Context used to manage the encryption of requests.
|
||||
/// Intended to be used by [`Request`](super::Request) implementations
|
||||
#[derive(Debug)]
|
||||
pub struct ReqEncrCtx {
|
||||
iv: [u8; 12],
|
||||
priv_key: PKey<Private>,
|
||||
prot_key: SymKey,
|
||||
}
|
||||
|
||||
impl ReqEncrCtx {
|
||||
/// Create a new encryption context that uses AES256.
|
||||
///
|
||||
/// * `iv` - Initialization vector for the request encryption
|
||||
/// * `priv_key` - Private key to wrap [`Keyslot`](super::Keyslot)
|
||||
/// * `prot_key` - Symmetric key for request encryption. Part of [`Keyslot`](super::Keyslot)
|
||||
///
|
||||
/// If an argument is set to `None` a random is generated
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not generate a random value.
|
||||
pub fn new_aes_256<I, P, S>(iv: I, priv_key: P, prot_key: S) -> Result<Self>
|
||||
where
|
||||
I: Into<Option<[u8; 12]>>,
|
||||
P: Into<Option<PKey<Private>>>,
|
||||
S: Into<Option<SymKey>>,
|
||||
{
|
||||
let iv = iv.into().unwrap_or(random_array()?);
|
||||
let priv_key = priv_key.into().unwrap_or(gen_ec_key(Nid::SECP521R1)?);
|
||||
let prot_key = prot_key
|
||||
.into()
|
||||
.unwrap_or(SymKey::random(SymKeyType::Aes256Gcm)?);
|
||||
Ok(Self {
|
||||
iv,
|
||||
priv_key,
|
||||
prot_key,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new encryption context with random input values.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not generate a random value.
|
||||
pub fn random(key_tp: SymKeyType) -> Result<Self> {
|
||||
match key_tp {
|
||||
SymKeyType::Aes256Gcm => Self::new_aes_256(None, None, None),
|
||||
SymKeyType::Aes256Xts => Err(Error::NoAeadKey),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the authenticated data for a request.
|
||||
/// # Returns
|
||||
/// ```none
|
||||
/// _______________________________________________________________
|
||||
/// | MAGIC (8) Version Number (4) Size (4)|
|
||||
/// | IV (12) Reserved (4)|
|
||||
/// | Reserved (7) Num keyslots (1) Reserved(4) Encr Size (4)|
|
||||
/// | --------------------------------------------------- |
|
||||
/// | Request type dependent AAD data |
|
||||
/// |-------------------------------------------------------------|
|
||||
/// ```
|
||||
pub fn build_aad<O>(
|
||||
&self,
|
||||
version: RequestVersion,
|
||||
aad: &Vec<Aad>,
|
||||
encr_size: usize,
|
||||
magic: O,
|
||||
) -> Result<Vec<u8>>
|
||||
where
|
||||
O: Into<Option<RequestMagic>>,
|
||||
{
|
||||
self.build_aad_impl(version, aad, encr_size, magic.into())
|
||||
}
|
||||
|
||||
/// Concrete implementation for [`ReqEncrCtx::build_aad`].
|
||||
fn build_aad_impl(
|
||||
&self,
|
||||
version: RequestVersion,
|
||||
aad: &Vec<Aad>,
|
||||
encr_size: usize,
|
||||
magic: Option<RequestMagic>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let nks = aad.iter().filter(|a| matches!(a, Aad::Ks(_))).count();
|
||||
let nks: u8 = match nks {
|
||||
0 => Err(Error::NoHostkey),
|
||||
n if n > u8::MAX as usize => Err(Error::ManyHostkeys),
|
||||
n => Ok(n as u8),
|
||||
}?;
|
||||
let mut auth_data: Vec<u8> = Vec::with_capacity(2048);
|
||||
|
||||
// reserve space for the request header
|
||||
auth_data.resize(size_of::<RequestHdr>(), 0);
|
||||
|
||||
for a in aad {
|
||||
match a {
|
||||
Aad::Plain(p) => auth_data.extend_from_slice(p),
|
||||
Aad::Ks(ks) => {
|
||||
ks.encrypt_to(self.prot_key.value(), &self.priv_key, &mut auth_data)?
|
||||
}
|
||||
Aad::Encr(e) => {
|
||||
e.encrypt_to(self.prot_key.value(), &self.priv_key, &mut auth_data)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(|| 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
|
||||
auth_data[..size_of::<RequestHdr>()].copy_from_slice(req_hdr.as_bytes());
|
||||
Ok(auth_data)
|
||||
}
|
||||
|
||||
/// Get the public coordinates from the private key (Customer private key)
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the public key could not be extracted by OpenSSL.
|
||||
/// Very unlikely.
|
||||
pub fn key_coords(&self) -> Result<EcPubKeyCoord> {
|
||||
self.priv_key.as_ref().try_into().map_err(Error::Crypto)
|
||||
}
|
||||
|
||||
/// Encrypt confidential Data with this encryption context and provide a GCM tag.
|
||||
///
|
||||
/// * `aad` - additional authentic data
|
||||
/// * `conf` - data to be encrypted
|
||||
///
|
||||
/// # Returns
|
||||
/// [`Vec<u8>`] with the following content:
|
||||
/// 1. `aad`
|
||||
/// 2. `encr(conf)`
|
||||
/// 3. `aes gcm tag`
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the data could not be encrypted by OpenSSL.
|
||||
pub(crate) fn encrypt_aead(&self, aad: &[u8], conf: &[u8]) -> Result<AeadEncryptionResult> {
|
||||
encrypt_aead(&self.prot_key, &self.iv, aad, conf)
|
||||
}
|
||||
|
||||
/// Returns a reference to the request protection key of this [`ReqEncrCtx`].
|
||||
pub fn prot_key(&self) -> &SymKey {
|
||||
&self.prot_key
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::get_test_asset;
|
||||
use crate::req::hostkey::HostKey;
|
||||
use crate::req::keyslot::Keyslot;
|
||||
use crate::request::SymKey;
|
||||
use crate::test_utils::*;
|
||||
|
||||
static TEST_MAGIC: [u8; 8] = 0x12345689abcdef00u64.to_be_bytes();
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad() {
|
||||
let (cust_key, host_key) = get_test_keys();
|
||||
let ks = Keyslot::new(HostKey::V1(host_key));
|
||||
let ctx = ReqEncrCtx::new_aes_256(
|
||||
Some([0x11; 12]),
|
||||
Some(cust_key),
|
||||
Some(SymKey::Aes256([0x17; 32].into())),
|
||||
)
|
||||
.unwrap();
|
||||
let v = [0x55; 8];
|
||||
let aad = Aad::Plain(&v);
|
||||
let aad = ctx
|
||||
.build_aad(0x200, &vec![aad, Aad::Ks(&ks)], 16, Some(TEST_MAGIC))
|
||||
.unwrap();
|
||||
|
||||
let mut aad_exp = vec![
|
||||
0x12, 0x34, 0x56, 0x89, 0xab, 0xcd, 0xef, 0, // progr
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0, 168, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
1, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 16, // sea
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // aad
|
||||
];
|
||||
aad_exp.extend_from_slice(get_test_asset!("exp/keyslot.bin"));
|
||||
assert_eq!(&aad, &aad_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad_nks_no() {
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let aad = Vec::<Aad>::new();
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
|
||||
assert!(matches!(aad, Err(Error::NoHostkey)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad_nks_many() {
|
||||
let (_, host_key) = get_test_keys();
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let ks: Vec<Keyslot> = (0..257)
|
||||
.map(|_| Keyslot::new(HostKey::V1(host_key.clone())))
|
||||
.collect();
|
||||
let mut aad = Vec::<Aad>::new();
|
||||
ks.iter().for_each(|ks| aad.push(Aad::Ks(ks)));
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
|
||||
assert!(matches!(aad, Err(Error::ManyHostkeys)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad_nks() {
|
||||
let (_, host_key) = get_test_keys();
|
||||
let host_key = HostKey::V1(host_key);
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let ks = [
|
||||
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)));
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC)).unwrap();
|
||||
|
||||
assert_eq!(aad.get(39).unwrap(), &3u8);
|
||||
}
|
||||
}
|
||||
154
rust/pv/src/req/ec_coord.rs
Normal file
154
rust/pv/src/req/ec_coord.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
//! EC public key coordinate utilities and conversions.
|
||||
|
||||
use openssl::bn::{BigNum, BigNumContext};
|
||||
use openssl::ec::{EcGroup, EcGroupRef, EcKey, EcPointRef};
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::hash::{DigestBytes, MessageDigest};
|
||||
use openssl::nid::Nid;
|
||||
use openssl::pkey::{PKey, PKeyRef, Private, Public};
|
||||
|
||||
use crate::crypto::hash;
|
||||
use crate::Result;
|
||||
|
||||
/// Public key components of an [`openssl::ec::EcKey`] key.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EcPubKeyCoord([u8; 160]);
|
||||
|
||||
impl AsRef<[u8]> for EcPubKeyCoord {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
const ECDH_PUB_KEY_COORD_POINT_SIZE: usize = 0x50;
|
||||
|
||||
impl EcPubKeyCoord {
|
||||
/// Returns the SHA256 hash of the [`EcPubKeyCoord`].
|
||||
///
|
||||
/// If [`EcPubKeyCoord`] was built from a host-key, this value is the public host-key hash.
|
||||
pub fn sha256(&self) -> Result<DigestBytes> {
|
||||
hash(MessageDigest::sha256(), self.as_ref())
|
||||
}
|
||||
|
||||
/// Construct a [`EcPubKeyCoord`]
|
||||
///
|
||||
/// # Safety
|
||||
/// This function is marked unsafe, because data not representing two EC points violates the
|
||||
/// invariant of this struct.
|
||||
pub unsafe fn from_data(data: [u8; 160]) -> Self {
|
||||
EcPubKeyCoord(data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the pub ECDH coordinates in the format the Ultravisor expects it:
|
||||
/// The two coordinates are padded to 80 bytes each.
|
||||
fn get_pub_ecdh_points(pkey: &EcPointRef, grp: &EcGroupRef) -> Result<[u8; 160], ErrorStack> {
|
||||
let mut x = BigNum::new()?;
|
||||
let mut y = BigNum::new()?;
|
||||
let mut bn_ctx = BigNumContext::new()?;
|
||||
pkey.affine_coordinates(grp, &mut x, &mut y, &mut bn_ctx)?;
|
||||
let mut coord: Vec<u8> = x.to_vec_padded(ECDH_PUB_KEY_COORD_POINT_SIZE as i32)?;
|
||||
coord.append(&mut y.to_vec_padded(ECDH_PUB_KEY_COORD_POINT_SIZE as i32)?);
|
||||
Ok(coord.try_into().unwrap())
|
||||
}
|
||||
|
||||
impl TryFrom<EcPubKeyCoord> for PKey<Public> {
|
||||
type Error = ErrorStack;
|
||||
|
||||
fn try_from(value: EcPubKeyCoord) -> Result<Self, Self::Error> {
|
||||
let ecdh = value.as_ref();
|
||||
let grp = EcGroup::from_curve_name(Nid::SECP521R1)?;
|
||||
let x = BigNum::from_slice(&ecdh[..ECDH_PUB_KEY_COORD_POINT_SIZE])?;
|
||||
let y = BigNum::from_slice(&ecdh[ECDH_PUB_KEY_COORD_POINT_SIZE..])?;
|
||||
let ec_key = EcKey::from_public_key_affine_coordinates(&grp, &x, &y)?;
|
||||
Self::from_ec_key(ec_key)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! ecdh_from {
|
||||
($type: ty) => {
|
||||
impl TryFrom<&PKeyRef<$type>> for EcPubKeyCoord {
|
||||
type Error = ErrorStack;
|
||||
|
||||
fn try_from(key: &PKeyRef<$type>) -> Result<Self, Self::Error> {
|
||||
let k = key.ec_key()?;
|
||||
k.check_key()?;
|
||||
let grp = k.group();
|
||||
let pub_key = k.public_key();
|
||||
let coord = get_pub_ecdh_points(pub_key, grp)?;
|
||||
Ok(Self(coord))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PKey<$type>> for EcPubKeyCoord {
|
||||
type Error = ErrorStack;
|
||||
|
||||
fn try_from(key: PKey<$type>) -> Result<Self, Self::Error> {
|
||||
let key_ref = key.as_ref();
|
||||
key_ref.try_into()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ecdh_from!(Private);
|
||||
ecdh_from!(Public);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::get_test_asset;
|
||||
use crate::test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn ec_pub_ec_coord_from() {
|
||||
let (cust_key, _) = get_test_keys();
|
||||
let pub_key = get_test_asset!("keys/public_cust.bin");
|
||||
assert_eq!(pub_key.len(), 160);
|
||||
|
||||
let ec_coord: EcPubKeyCoord = cust_key.as_ref().try_into().unwrap();
|
||||
assert_eq!(ec_coord.as_ref(), pub_key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ec_pub_ec_coord_hash() {
|
||||
let exp = [
|
||||
0x5e, 0xe9, 0x05, 0xa9, 0xbe, 0x70, 0x36, 0x68, 0x15, 0xa4, 0x56, 0x41, 0xaf, 0xae,
|
||||
0x00, 0x97, 0x3b, 0x1f, 0x45, 0x29, 0x2f, 0x43, 0xbc, 0xd7, 0x63, 0x8e, 0xe2, 0xa7,
|
||||
0x3f, 0xd7, 0xc4, 0x5e,
|
||||
];
|
||||
let (cust_key, _) = get_test_keys();
|
||||
let ec_coord: EcPubKeyCoord = cust_key.as_ref().try_into().unwrap();
|
||||
let hash = ec_coord.sha256().unwrap();
|
||||
|
||||
assert_eq!(hash.as_ref(), &exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_ecdh_and_vice_versa() {
|
||||
let (_, cust_pub) = get_test_keys();
|
||||
let phk: EcPubKeyCoord = cust_pub.clone().try_into().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
phk.as_ref(),
|
||||
&[
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 118, 136, 28, 216, 75, 139, 109, 231,
|
||||
18, 60, 126, 144, 14, 223, 120, 231, 247, 182, 132, 153, 145, 70, 177, 38, 59, 168,
|
||||
184, 108, 132, 71, 240, 138, 182, 212, 105, 194, 177, 40, 237, 158, 28, 53, 1, 88,
|
||||
5, 172, 211, 211, 2, 51, 211, 145, 34, 247, 226, 248, 170, 28, 43, 20, 123, 120,
|
||||
131, 180, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 69, 86, 194, 92,
|
||||
249, 47, 41, 206, 102, 189, 68, 17, 77, 107, 123, 60, 120, 225, 58, 63, 144, 189,
|
||||
185, 0, 64, 246, 135, 110, 82, 98, 247, 120, 166, 26, 147, 125, 27, 52, 128, 46,
|
||||
178, 87, 227, 78, 6, 114, 221, 95, 42, 52, 122, 221, 170, 40, 32, 53, 9, 42, 112,
|
||||
195, 92, 46, 121, 115
|
||||
]
|
||||
);
|
||||
let cust_pub_back: PKey<Public> = phk.try_into().unwrap();
|
||||
assert!(cust_pub.public_eq(&cust_pub_back));
|
||||
}
|
||||
}
|
||||
54
rust/pv/src/req/encrypt.rs
Normal file
54
rust/pv/src/req/encrypt.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
//! Encryption trait and authenticated data types for UV requests.
|
||||
|
||||
use openssl::pkey::{PKeyRef, Private};
|
||||
|
||||
use crate::req::Keyslot;
|
||||
use crate::Result;
|
||||
|
||||
/// Encrypt a _secret_ using self and a given private key.
|
||||
pub trait Encrypt {
|
||||
/// Encrypts `secret` using `self` and `priv_key` the encryption.
|
||||
///
|
||||
/// # Returns
|
||||
/// the encrypted data.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not encrypt the secret.
|
||||
fn encrypt(&self, secret: &[u8], priv_key: &PKeyRef<Private>) -> Result<Vec<u8>> {
|
||||
let mut res = Vec::with_capacity(80);
|
||||
self.encrypt_to(secret, priv_key, &mut res)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Encrypts `secret` using `self` and `priv_key` the encryption.
|
||||
/// Appends the encrypted data to `to`
|
||||
///
|
||||
/// # Returns
|
||||
/// The encrypted data.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not encrypt the secret.
|
||||
fn encrypt_to(
|
||||
&self,
|
||||
secret: &[u8],
|
||||
priv_key: &PKeyRef<Private>,
|
||||
to: &mut Vec<u8>,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Types of Authenticated Data
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub enum Aad<'a> {
|
||||
/// Authenticated Keyslot
|
||||
Ks(&'a Keyslot),
|
||||
/// Unchanged authenticated data
|
||||
Plain(&'a [u8]),
|
||||
/// Authenticated data that has to be encrypted in beforehand
|
||||
Encr(&'a dyn Encrypt),
|
||||
}
|
||||
91
rust/pv/src/req/header.rs
Normal file
91
rust/pv/src/req/header.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
//! Request header structure for UV requests.
|
||||
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, U32};
|
||||
|
||||
use crate::assert_size;
|
||||
|
||||
/// Representation of the shared parts of the request header.
|
||||
/// Used by [`ReqEncrCtx`](super::ReqEncrCtx)
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable)]
|
||||
pub struct RequestHdr {
|
||||
magic: [u8; 8],
|
||||
pub(crate) rqvn: U32<BigEndian>,
|
||||
pub(crate) rql: U32<BigEndian>,
|
||||
iv: [u8; 12],
|
||||
reserved1c: [u8; 4],
|
||||
reserved20: [u8; 7],
|
||||
nks: u8,
|
||||
reserved28: u32,
|
||||
pub(crate) sea: U32<BigEndian>,
|
||||
}
|
||||
assert_size!(RequestHdr, 48);
|
||||
|
||||
impl RequestHdr {
|
||||
pub(crate) fn new(
|
||||
rqvn: u32,
|
||||
rql: u32,
|
||||
iv: [u8; 12],
|
||||
nks: u8,
|
||||
sea: u32,
|
||||
magic: Option<[u8; 8]>,
|
||||
) -> Self {
|
||||
Self {
|
||||
magic: magic.unwrap_or_default(),
|
||||
rqvn: rqvn.into(),
|
||||
rql: rql.into(),
|
||||
iv,
|
||||
reserved1c: [0; 4],
|
||||
reserved20: [0; 7],
|
||||
nks,
|
||||
reserved28: 0,
|
||||
sea: sea.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use zerocopy::IntoBytes;
|
||||
|
||||
use super::*;
|
||||
|
||||
static TEST_MAGIC: [u8; 8] = 0x12345689abcdef00u64.to_be_bytes();
|
||||
|
||||
#[test]
|
||||
fn req_hdr() {
|
||||
let hdr = RequestHdr::new(0x200, 22, [0x11; 12], 15, 44, None);
|
||||
let hdr_bin = hdr.as_bytes();
|
||||
let hdr_bin_exp = [
|
||||
0u8, 0, 0, 0, 0, 0, 0, 0, // magic
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0, 22, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
15, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 44, // sea
|
||||
];
|
||||
assert_eq!(hdr_bin, &hdr_bin_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn req_hdr2() {
|
||||
let mut hdr = RequestHdr::new(0x200, 0x1234, [0x11; 12], 15, 44, Some(TEST_MAGIC));
|
||||
let hdr_bin = hdr.as_mut_bytes();
|
||||
let hdr_bin_exp = [
|
||||
0x12, 0x34, 0x56, 0x89, 0xab, 0xcd, 0xef, 0, // magic
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0x12, 0x34, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
15, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 44, // sea
|
||||
];
|
||||
assert_eq!(hdr_bin, &hdr_bin_exp);
|
||||
}
|
||||
}
|
||||
30
rust/pv/src/req/hostkey.rs
Normal file
30
rust/pv/src/req/hostkey.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
//! Host key types for UV requests
|
||||
|
||||
use openssl::pkey::{PKey, Public};
|
||||
|
||||
/// Versioned host keys container
|
||||
#[non_exhaustive]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum HostKey {
|
||||
/// ECDH public key
|
||||
V1(PKey<Public>),
|
||||
}
|
||||
|
||||
impl HostKey {
|
||||
/// Return the ECDH public key
|
||||
pub fn ec_key(&self) -> &PKey<Public> {
|
||||
match self {
|
||||
HostKey::V1(ec_key) => ec_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<HostKey> for HostKey {
|
||||
fn as_ref(&self) -> &HostKey {
|
||||
self
|
||||
}
|
||||
}
|
||||
150
rust/pv/src/req/keyslot.rs
Normal file
150
rust/pv/src/req/keyslot.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
//! IBM Z Host key-slot implementations.
|
||||
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkey::{PKey, PKeyRef, Private, Public};
|
||||
|
||||
use super::ec_coord::EcPubKeyCoord;
|
||||
use super::encrypt::Encrypt;
|
||||
use crate::crypto::{derive_aes256_gcm_key, encrypt_aead, hash};
|
||||
use crate::request::HostKey;
|
||||
use crate::Result;
|
||||
|
||||
/// IBM Z Host key-slot
|
||||
///
|
||||
/// Layout in binary format:
|
||||
/// ```none
|
||||
/// _______________________________________________________________
|
||||
/// | Public Host Key Hash (32) |
|
||||
/// | Wrapped(=Encrypted) Request Protection Key(32) |
|
||||
/// | Key Slot Tag (16) |
|
||||
/// |_____________________________________________________________|
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyslotV1(PKey<Public>);
|
||||
|
||||
impl KeyslotV1 {
|
||||
/// Size of a host-key hash
|
||||
pub const PHKH_SIZE: u32 = 0x20;
|
||||
/// Size of complete V1 keyslot in bytes
|
||||
pub const SIZE: usize = 80;
|
||||
|
||||
/// Creates a new Keyslot from the provided public key
|
||||
pub fn new(hostkey: PKey<Public>) -> Self {
|
||||
Self(hostkey)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encrypt for KeyslotV1 {
|
||||
/// Encrypts the given request protection key `prot_key`.
|
||||
///
|
||||
/// The AES256 encryption key is derived from `self` as public key, and `priv_key` as private
|
||||
/// key.
|
||||
///
|
||||
/// # Returns
|
||||
/// The encrypted Keyslot.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if OpenSSL could not encrypt the secret.
|
||||
fn encrypt_to(
|
||||
&self,
|
||||
prot_key: &[u8],
|
||||
priv_key: &PKeyRef<Private>,
|
||||
to: &mut Vec<u8>,
|
||||
) -> Result<()> {
|
||||
let derived_key = derive_aes256_gcm_key(priv_key, &self.0)?;
|
||||
let mut wrpk_and_kst =
|
||||
encrypt_aead(&derived_key.into(), &[0; 12], &[], prot_key)?.into_buf();
|
||||
assert_eq!(wrpk_and_kst.len(), 48);
|
||||
let phk: EcPubKeyCoord = self.0.as_ref().try_into()?;
|
||||
|
||||
to.reserve(80);
|
||||
let hash = hash(MessageDigest::sha256(), phk.as_ref())?;
|
||||
assert_eq!(hash.len(), 32);
|
||||
to.extend_from_slice(&hash);
|
||||
to.append(&mut wrpk_and_kst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Versioned keyslot container
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Keyslot {
|
||||
/// V1 key-slots with ECDH keys
|
||||
V1(KeyslotV1),
|
||||
}
|
||||
|
||||
impl Keyslot {
|
||||
/// Return a keyslot with the same key-type as the given host-key
|
||||
pub fn new(hostkey: HostKey) -> Self {
|
||||
match hostkey {
|
||||
HostKey::V1(key) => Keyslot::V1(KeyslotV1::new(key)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the public host key hash size for the given version of the key-slot in bytes
|
||||
pub fn phkh_size(&self) -> u32 {
|
||||
match self {
|
||||
Keyslot::V1(_) => KeyslotV1::PHKH_SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the size of the key-slot in bytes
|
||||
pub fn size(&self) -> usize {
|
||||
match self {
|
||||
Keyslot::V1(_) => KeyslotV1::SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether the key-slot uses hybrid keys
|
||||
pub fn is_hybrid(&self) -> bool {
|
||||
match self {
|
||||
Keyslot::V1(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encrypt for Keyslot {
|
||||
fn encrypt_to(
|
||||
&self,
|
||||
secret: &[u8],
|
||||
priv_key: &PKeyRef<Private>,
|
||||
to: &mut Vec<u8>,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
Keyslot::V1(ks) => ks.encrypt_to(secret, priv_key, to),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PKey<Public>> for Keyslot {
|
||||
fn from(key: PKey<Public>) -> Self {
|
||||
Keyslot::V1(KeyslotV1::new(key))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::get_test_asset;
|
||||
use crate::test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn keyslot() {
|
||||
let (cust_key, host_key) = get_test_keys();
|
||||
let exp_keyslot = get_test_asset!("exp/keyslot.bin").to_vec();
|
||||
|
||||
let keyslot = KeyslotV1(host_key);
|
||||
let encr_ks = keyslot.encrypt(&[0x17u8; 32], &cust_key).unwrap();
|
||||
|
||||
assert_eq!(exp_keyslot, encr_ks);
|
||||
|
||||
let encr_ks = keyslot.encrypt(&[0x16u8; 32], &cust_key).unwrap();
|
||||
assert_ne!(exp_keyslot, encr_ks);
|
||||
}
|
||||
}
|
||||
25
rust/pv/src/req/mod.rs
Normal file
25
rust/pv/src/req/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
//! Request encryption and key management for IBM Z Ultravisor.
|
||||
//!
|
||||
//! This module provides functionality for creating and encrypting requests to the
|
||||
//! IBM Z Ultravisor, including host key management, keyslot encryption, and request
|
||||
//! context handling.
|
||||
|
||||
mod context;
|
||||
mod ec_coord;
|
||||
mod encrypt;
|
||||
mod header;
|
||||
mod hostkey;
|
||||
mod keyslot;
|
||||
mod request;
|
||||
|
||||
// Re-export public types
|
||||
pub use context::ReqEncrCtx;
|
||||
pub use ec_coord::EcPubKeyCoord;
|
||||
pub use encrypt::{Aad, Encrypt};
|
||||
pub use header::RequestHdr;
|
||||
pub use hostkey::HostKey;
|
||||
pub use keyslot::{Keyslot, KeyslotV1};
|
||||
pub use request::{BinReqValues, Request};
|
||||
279
rust/pv/src/req/request.rs
Normal file
279
rust/pv/src/req/request.rs
Normal file
@@ -0,0 +1,279 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
use std::mem::size_of;
|
||||
|
||||
use zerocopy::{FromBytes, Immutable, KnownLayout};
|
||||
|
||||
use super::HostKey;
|
||||
use crate::crypto::{decrypt_aead, SymKey, SymKeyType};
|
||||
use crate::req::context::ReqEncrCtx;
|
||||
use crate::req::header::RequestHdr;
|
||||
use crate::request::Confidential;
|
||||
use crate::{Error, Result};
|
||||
|
||||
/// A trait representing a request for the Ultravisor.
|
||||
///
|
||||
/// All requests share a few things:
|
||||
/// * All requests need to be encrypted on a trusted machine
|
||||
/// * All requests have at least one Hostkeyslot
|
||||
///
|
||||
/// The encryption setup is handled by [`ReqEncrCtx`]. Implementers need to pass the data to the
|
||||
/// `ReqEncrCtx` when implementing `encrypt`. A hostkey should be represented by
|
||||
/// [`Keyslot`](super::Keyslot) during encryption.
|
||||
///
|
||||
/// An UV request consists of an authenticated area (AAD), an encrypted area (Encr) and a 16 byte
|
||||
/// tag. The AAD contains a general header and Request type defined data (including Keyslots). It
|
||||
/// is encrypted with an Request protection key (symmetric). This key is encrypted with a
|
||||
/// (generated) private key and the public key of the host system (Host key)
|
||||
/// ```none
|
||||
/// _______________________________________________________________
|
||||
/// | MAGIC (8) Version Number (4) Size (4)|
|
||||
/// | IV (12) Reserved (4)|
|
||||
/// | Reserved (7) Num keyslots (1) Reserved(4) Encr Size (4)|
|
||||
/// | --------------------------------------------------- |
|
||||
/// | Request type dependent AAD data |
|
||||
/// | ---------------------------------------------------- |
|
||||
/// | Encrypted (request type dependent) data |
|
||||
/// | ---------------------------------------------------- |
|
||||
/// | AES GCM Tag (16) |
|
||||
/// |_____________________________________________________________|
|
||||
/// ```
|
||||
pub trait Request {
|
||||
/// Encrypt the request into its binary format
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the encryption fails, the request does not have at
|
||||
/// least a hostkey, or other implementation dependent contracts are not met.
|
||||
fn encrypt(&self, ctx: &ReqEncrCtx) -> Result<Vec<u8>>;
|
||||
|
||||
/// Add a host-key to this request
|
||||
///
|
||||
/// Must be called at least once, otherwise {`Request::encrypt`} will fail
|
||||
fn add_hostkey(&mut self, hostkey: HostKey);
|
||||
}
|
||||
|
||||
/// A struct to represent some parts of a binary/encrypted request.
|
||||
#[derive(Debug)]
|
||||
#[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 = SymKeyType::AES_256_GCM_TAG_LEN;
|
||||
|
||||
/// Get the locations from this request.
|
||||
///
|
||||
/// Does minimal sanity test, just tests to prevent panics.
|
||||
/// `req` may be larger than the actual request.
|
||||
pub(crate) fn get(req: &'a [u8]) -> Result<Self> {
|
||||
let (hdr, _) = RequestHdr::read_from_prefix(req).map_err(|_| Error::BinRequestSmall)?;
|
||||
let rql = hdr.rql.get() as usize;
|
||||
let sea = hdr.sea.get() as usize;
|
||||
|
||||
if req.len() < rql || 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(crate) fn version(&self) -> u32 {
|
||||
self.version
|
||||
}
|
||||
|
||||
/// Returns the length of this [`BinReqValues`].
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Returns the size of the encrypted area
|
||||
pub(crate) fn sea(&self) -> u32 {
|
||||
self.encr.len() as u32
|
||||
}
|
||||
|
||||
/// Decrypts the encrypted area with the provided key
|
||||
pub(crate) fn decrypt(&self, key: &SymKey) -> Result<Confidential<Vec<u8>>> {
|
||||
let result = decrypt_aead(key, self.iv, self.aad, self.encr, self.tag)?;
|
||||
Ok(result.into_plain())
|
||||
}
|
||||
|
||||
/// Returns a reference to the request dependent authenticated area of this [`BinReqValues`]
|
||||
/// already interpreted.
|
||||
///
|
||||
/// If target struct is larger than the request depended-AAD None is returned. See
|
||||
/// [`FromBytes::ref_from_prefix`]
|
||||
pub(crate) fn req_dep_aad<T>(&self) -> Option<&T>
|
||||
where
|
||||
T: FromBytes + Sized + Immutable + KnownLayout,
|
||||
{
|
||||
T::ref_from_prefix(self.req_dep_aad).map(|s| s.0).ok()
|
||||
}
|
||||
|
||||
/// Returns a reference to the tag of this [`BinReqValues`].
|
||||
pub(crate) fn tag(&self) -> &[u8] {
|
||||
self.tag
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use zerocopy::IntoBytes;
|
||||
|
||||
use super::*;
|
||||
use crate::get_test_asset;
|
||||
use crate::req::header::RequestHdr;
|
||||
use crate::req::{Aad, HostKey, Keyslot, ReqEncrCtx};
|
||||
use crate::request::SymKey;
|
||||
use crate::test_utils::*;
|
||||
|
||||
static TEST_MAGIC: [u8; 8] = 0x12345689abcdef00u64.to_be_bytes();
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad() {
|
||||
let (cust_key, host_key) = get_test_keys();
|
||||
let ks = Keyslot::new(HostKey::V1(host_key));
|
||||
let ctx = ReqEncrCtx::new_aes_256(
|
||||
Some([0x11; 12]),
|
||||
Some(cust_key),
|
||||
Some(SymKey::Aes256([0x17; 32].into())),
|
||||
)
|
||||
.unwrap();
|
||||
let v = [0x55; 8];
|
||||
let aad = Aad::Plain(&v);
|
||||
let aad = ctx
|
||||
.build_aad(0x200, &vec![aad, Aad::Ks(&ks)], 16, Some(TEST_MAGIC))
|
||||
.unwrap();
|
||||
|
||||
let mut aad_exp = vec![
|
||||
0x12, 0x34, 0x56, 0x89, 0xab, 0xcd, 0xef, 0, // progr
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0, 168, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
1, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 16, // sea
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // aad
|
||||
];
|
||||
aad_exp.extend_from_slice(get_test_asset!("exp/keyslot.bin"));
|
||||
assert_eq!(&aad, &aad_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad_nks_no() {
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let aad = Vec::<Aad>::new();
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
|
||||
assert!(matches!(aad, Err(Error::NoHostkey)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encr_build_aad_nks_many() {
|
||||
let (_, host_key) = get_test_keys();
|
||||
let host_key = HostKey::V1(host_key);
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let ks: Vec<Keyslot> = (0..257).map(|_| Keyslot::new(host_key.clone())).collect();
|
||||
let mut aad = Vec::<Aad>::new();
|
||||
ks.iter().for_each(|ks| aad.push(Aad::Ks(ks)));
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC));
|
||||
assert!(matches!(aad, Err(Error::ManyHostkeys)));
|
||||
}
|
||||
#[test]
|
||||
fn encr_build_aad_nks() {
|
||||
let (_, host_key) = get_test_keys();
|
||||
let host_key = HostKey::V1(host_key);
|
||||
let ctx = ReqEncrCtx::new_aes_256(Some([0x11; 12]), None, None).unwrap();
|
||||
|
||||
let ks = [
|
||||
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)));
|
||||
|
||||
let aad = ctx.build_aad(0x200, &aad, 16, Some(TEST_MAGIC)).unwrap();
|
||||
|
||||
assert_eq!(aad.get(39).unwrap(), &3u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn req_hdr() {
|
||||
let hdr = RequestHdr::new(0x200, 22, [0x11; 12], 15, 44, None);
|
||||
let hdr_bin = hdr.as_bytes();
|
||||
let hdr_bin_exp = [
|
||||
0u8, 0, 0, 0, 0, 0, 0, 0, // magic
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0, 22, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
15, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 44, // sea
|
||||
];
|
||||
assert_eq!(hdr_bin, &hdr_bin_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn req_hdr2() {
|
||||
let mut hdr = RequestHdr::new(0x200, 0x1234, [0x11; 12], 15, 44, Some(TEST_MAGIC));
|
||||
let hdr_bin = hdr.as_mut_bytes();
|
||||
let hdr_bin_exp = [
|
||||
0x12, 0x34, 0x56, 0x89, 0xab, 0xcd, 0xef, 0, // magic
|
||||
0, 0, 2, 0, // vers
|
||||
0, 0, 0x12, 0x34, // size
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, // iv
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // res
|
||||
15, // nks
|
||||
0, 0, 0, 0, // res
|
||||
0, 0, 0, 44, // sea
|
||||
];
|
||||
assert_eq!(hdr_bin, &hdr_bin_exp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bin_req_values_buffer_too_small() {
|
||||
// Create a valid header with request length set to 200 bytes
|
||||
let hdr = RequestHdr::new(0x200, 200, [0x11; 12], 1, 32, Some(TEST_MAGIC));
|
||||
let hdr_bin = hdr.as_bytes();
|
||||
|
||||
// Create a buffer that's smaller than the declared request length (48
|
||||
// bytes)
|
||||
let small_buffer = Vec::from(hdr_bin);
|
||||
|
||||
let result = BinReqValues::get(&small_buffer);
|
||||
assert!(matches!(result, Err(Error::BinRequestSmall)));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
// Copyright IBM Corp.
|
||||
|
||||
// DO NOT USE ANY OF THESE ITEMS IN PRODUCTION CODE
|
||||
// USED FOR INTERNAL UNIT AND FVT TESTING ONLY!!!
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::ffi::c_void;
|
||||
use std::fs;
|
||||
use std::mem::{size_of, ManuallyDrop};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use openssl::{
|
||||
bn::BigNum,
|
||||
ec::{EcGroup, EcKey},
|
||||
error::ErrorStack,
|
||||
nid::Nid,
|
||||
pkey::{PKey, Private, Public},
|
||||
x509::{X509Crl, X509},
|
||||
};
|
||||
use openssl::bn::BigNum;
|
||||
use openssl::ec::{EcGroup, EcKey};
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::nid::Nid;
|
||||
use openssl::pkey::{PKey, Private, Public};
|
||||
use openssl::x509::{X509Crl, X509};
|
||||
|
||||
/// TEST ONLY! Loads the specified asset into the binary at compile time.
|
||||
///
|
||||
@@ -122,3 +121,379 @@ fn get_keypair(pub_coords: &[u8], priv_num: &[u8]) -> Result<PKey<Private>, Erro
|
||||
key.check_key()?;
|
||||
PKey::from_ec_key(key)
|
||||
}
|
||||
|
||||
// To regenerate these bindings, run:
|
||||
// bindgen bindgen_wrapper.h -o bindgen_output.rs \
|
||||
// --allowlist-function "RAND_get0_public" \
|
||||
// --allowlist-function "RAND_get0_private" --allowlist-function "EVP_RAND_fetch" \
|
||||
// --allowlist-function "EVP_RAND_free" --allowlist-function "EVP_RAND_CTX_new" \
|
||||
// --allowlist-function "EVP_RAND_CTX_free" --allowlist-function "EVP_RAND_CTX_up_ref" \
|
||||
// --allowlist-function "EVP_RAND_instantiate" --allowlist-function "RAND_set0_public" \
|
||||
// --allowlist-function "RAND_set0_private" --allowlist-type "OSSL_PARAM"
|
||||
// where bindgen_wrapper.h contains:
|
||||
// #include <openssl/provider.h>
|
||||
// #include <openssl/rand.h>
|
||||
// #include <openssl/evp.h>
|
||||
// #include <openssl/params.h>
|
||||
mod ffi {
|
||||
use std::ffi::{c_char, c_int, c_uchar, c_uint, c_void};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct OsslParam {
|
||||
pub key: *const c_char,
|
||||
pub data_type: c_uint,
|
||||
pub data: *mut c_void,
|
||||
pub data_size: usize,
|
||||
pub return_size: usize,
|
||||
}
|
||||
|
||||
pub enum OsslLibCtx {}
|
||||
pub enum OsslProvider {}
|
||||
pub enum EvpRand {}
|
||||
pub enum EvpRandCtx {}
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn RAND_get0_public(ctx: *mut OsslLibCtx) -> *mut EvpRandCtx;
|
||||
pub fn RAND_get0_private(ctx: *mut OsslLibCtx) -> *mut EvpRandCtx;
|
||||
pub fn EVP_RAND_fetch(
|
||||
libctx: *mut OsslLibCtx,
|
||||
algorithm: *const c_char,
|
||||
properties: *const c_char,
|
||||
) -> *mut EvpRand;
|
||||
pub fn EVP_RAND_free(rand: *mut EvpRand);
|
||||
pub fn EVP_RAND_CTX_new(rand: *mut EvpRand, parent: *mut EvpRandCtx) -> *mut EvpRandCtx;
|
||||
pub fn EVP_RAND_CTX_free(ctx: *mut EvpRandCtx);
|
||||
pub fn EVP_RAND_CTX_up_ref(ctx: *mut EvpRandCtx) -> c_int;
|
||||
pub fn EVP_RAND_instantiate(
|
||||
ctx: *mut EvpRandCtx,
|
||||
strength: c_uint,
|
||||
prediction_resistance: c_int,
|
||||
pstr: *const c_uchar,
|
||||
pstr_len: usize,
|
||||
params: *const OsslParam,
|
||||
) -> c_int;
|
||||
pub fn RAND_set0_public(ctx: *mut OsslLibCtx, rand: *mut EvpRandCtx) -> c_int;
|
||||
pub fn RAND_set0_private(ctx: *mut OsslLibCtx, rand: *mut EvpRandCtx) -> c_int;
|
||||
}
|
||||
}
|
||||
|
||||
// Constants for OSSL_PARAM construction
|
||||
const OSSL_PARAM_OCTET_STRING: u32 = 5;
|
||||
const OSSL_PARAM_UNSIGNED_INTEGER: u32 = 2;
|
||||
const OSSL_PARAM_END: u32 = 0;
|
||||
|
||||
fn ossl_param_end() -> ffi::OsslParam {
|
||||
ffi::OsslParam {
|
||||
key: std::ptr::null(),
|
||||
data_type: OSSL_PARAM_END,
|
||||
data: std::ptr::null_mut(),
|
||||
data_size: 0,
|
||||
return_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn ossl_param_octet_string(name: &'static [u8], data: &mut [u8]) -> ffi::OsslParam {
|
||||
// SAFETY: Constructing OSSL_PARAM for octet string.
|
||||
// - name is a static null-terminated C string, valid for 'static
|
||||
// - data is a valid mutable slice, pointer remains valid during param usage
|
||||
// - Pointer casts are safe as they preserve alignment and validity
|
||||
ffi::OsslParam {
|
||||
key: name.as_ptr().cast(),
|
||||
data_type: OSSL_PARAM_OCTET_STRING,
|
||||
data: data.as_mut_ptr().cast(),
|
||||
data_size: data.len(),
|
||||
return_size: data.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ossl_param_uint(name: &'static [u8], value: &mut u32) -> ffi::OsslParam {
|
||||
// SAFETY: Constructing OSSL_PARAM for unsigned integer.
|
||||
// - name is a static null-terminated C string, valid for 'static
|
||||
// - value is a valid mutable reference, pointer remains valid during param usage
|
||||
// - Pointer cast to c_void is safe as it preserves alignment and validity
|
||||
ffi::OsslParam {
|
||||
key: name.as_ptr().cast(),
|
||||
data_type: OSSL_PARAM_UNSIGNED_INTEGER,
|
||||
data: (value as *mut u32).cast::<c_void>(),
|
||||
data_size: size_of::<u32>(),
|
||||
return_size: size_of::<u32>(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FetchedRand(NonNull<ffi::EvpRand>);
|
||||
|
||||
impl FetchedRand {
|
||||
const TEST_RAND_NAME: &'static [u8] = b"TEST-RAND\0";
|
||||
|
||||
fn fetch_test_rand() -> Result<Self, ErrorStack> {
|
||||
// SAFETY: Calling OpenSSL C API with valid parameters.
|
||||
// - null_mut() is valid for optional OSSL_LIB_CTX parameter
|
||||
// - Self::TEST_RAND_NAME is a valid null-terminated C string
|
||||
// - null() is valid for optional properties parameter
|
||||
// - Returns null on error, which we handle via NonNull::new
|
||||
let rand = unsafe {
|
||||
ffi::EVP_RAND_fetch(
|
||||
std::ptr::null_mut(),
|
||||
Self::TEST_RAND_NAME.as_ptr().cast(),
|
||||
std::ptr::null(),
|
||||
)
|
||||
};
|
||||
NonNull::new(rand).map(Self).ok_or_else(ErrorStack::get)
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> *mut ffi::EvpRand {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FetchedRand {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: self.0 is a valid non-null EVP_RAND pointer that we own.
|
||||
// This is the only place we call free, preventing double-free.
|
||||
unsafe {
|
||||
ffi::EVP_RAND_free(self.0.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RandCtx(NonNull<ffi::EvpRandCtx>);
|
||||
|
||||
impl RandCtx {
|
||||
fn new(rand: &FetchedRand) -> Result<Self, ErrorStack> {
|
||||
// SAFETY: Calling OpenSSL C API with valid parameters.
|
||||
// - rand.as_ptr() is a valid non-null EVP_RAND pointer
|
||||
// - null_mut() is valid for optional parent parameter
|
||||
// - Returns null on error, which we handle via NonNull::new
|
||||
let ctx = unsafe { ffi::EVP_RAND_CTX_new(rand.as_ptr(), std::ptr::null_mut()) };
|
||||
NonNull::new(ctx).map(Self).ok_or_else(ErrorStack::get)
|
||||
}
|
||||
|
||||
fn up_ref(ptr: *mut ffi::EvpRandCtx) -> Result<Self, ErrorStack> {
|
||||
let ptr = NonNull::new(ptr).ok_or_else(ErrorStack::get)?;
|
||||
// SAFETY: ptr is a valid non-null EVP_RAND_CTX pointer.
|
||||
// EVP_RAND_CTX_up_ref increments the reference count.
|
||||
// Returns 1 on success, 0 on failure.
|
||||
let rc = unsafe { ffi::EVP_RAND_CTX_up_ref(ptr.as_ptr()) };
|
||||
if rc == 1 {
|
||||
Ok(Self(ptr))
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
|
||||
fn current_public() -> Result<Option<Self>, ErrorStack> {
|
||||
// SAFETY: RAND_get0_public returns a borrowed pointer (no ownership transfer).
|
||||
// Returns null if no public RNG is set, which we handle.
|
||||
let ptr = unsafe { ffi::RAND_get0_public(std::ptr::null_mut()) };
|
||||
if ptr.is_null() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Self::up_ref(ptr).map(Some)
|
||||
}
|
||||
}
|
||||
|
||||
fn current_private() -> Result<Option<Self>, ErrorStack> {
|
||||
// SAFETY: RAND_get0_private returns a borrowed pointer (no ownership transfer).
|
||||
// Returns null if no private RNG is set, which we handle.
|
||||
let ptr = unsafe { ffi::RAND_get0_private(std::ptr::null_mut()) };
|
||||
if ptr.is_null() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Self::up_ref(ptr).map(Some)
|
||||
}
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> *mut ffi::EvpRandCtx {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
|
||||
fn instantiate_test_rand(&self, entropy: &[u8], nonce: &[u8]) -> Result<(), ErrorStack> {
|
||||
// See https://docs.openssl.org/3.1/man7/EVP_RAND-TEST-RAND/#description
|
||||
// for the available parameters.
|
||||
const TEST_ENTROPY_PARAM: &[u8] = b"test_entropy\0";
|
||||
const TEST_NONCE_PARAM: &[u8] = b"test_nonce\0";
|
||||
const STRENGTH_PARAM: &[u8] = b"strength\0";
|
||||
|
||||
let mut entropy = entropy.to_vec();
|
||||
let mut nonce = nonce.to_vec();
|
||||
let mut strength = 256u32;
|
||||
let params = [
|
||||
ossl_param_uint(STRENGTH_PARAM, &mut strength),
|
||||
ossl_param_octet_string(TEST_ENTROPY_PARAM, &mut entropy),
|
||||
ossl_param_octet_string(TEST_NONCE_PARAM, &mut nonce),
|
||||
ossl_param_end(),
|
||||
];
|
||||
|
||||
// SAFETY: Calling OpenSSL C API with valid parameters.
|
||||
// - self.as_ptr() is a valid non-null EVP_RAND_CTX pointer
|
||||
// - strength is a valid u32 value
|
||||
// - prediction_resistance=0 is valid
|
||||
// - pstr=null and pstr_len=0 indicate no personalization string
|
||||
// - params points to a valid array of OSSL_PARAM with proper terminator
|
||||
// - All mutable references in params remain valid for the call duration
|
||||
let rc = unsafe {
|
||||
ffi::EVP_RAND_instantiate(
|
||||
self.as_ptr(),
|
||||
strength,
|
||||
0,
|
||||
std::ptr::null(),
|
||||
0,
|
||||
params.as_ptr(),
|
||||
)
|
||||
};
|
||||
if rc == 1 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
|
||||
fn install_as_public(self) -> Result<InstalledRandCtx, ErrorStack> {
|
||||
// SAFETY: Calling OpenSSL C API to transfer ownership.
|
||||
// - self.as_ptr() is a valid non-null EVP_RAND_CTX pointer
|
||||
// - RAND_set0_public takes ownership of the context on success (rc==1)
|
||||
// - We wrap in ManuallyDrop to prevent double-free since OpenSSL now owns it
|
||||
let rc = unsafe { ffi::RAND_set0_public(std::ptr::null_mut(), self.as_ptr()) };
|
||||
if rc == 1 {
|
||||
Ok(InstalledRandCtx(ManuallyDrop::new(self)))
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
|
||||
fn install_as_private(self) -> Result<InstalledRandCtx, ErrorStack> {
|
||||
// SAFETY: Calling OpenSSL C API to transfer ownership.
|
||||
// - self.as_ptr() is a valid non-null EVP_RAND_CTX pointer
|
||||
// - RAND_set0_private takes ownership of the context on success (rc==1)
|
||||
// - We wrap in ManuallyDrop to prevent double-free since OpenSSL now owns it
|
||||
let rc = unsafe { ffi::RAND_set0_private(std::ptr::null_mut(), self.as_ptr()) };
|
||||
if rc == 1 {
|
||||
Ok(InstalledRandCtx(ManuallyDrop::new(self)))
|
||||
} else {
|
||||
Err(ErrorStack::get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RandCtx {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: self.0 is a valid non-null EVP_RAND_CTX pointer that we own.
|
||||
// This is only called when ownership was NOT transferred to OpenSSL.
|
||||
// InstalledRandCtx uses ManuallyDrop to prevent this from running after transfer.
|
||||
unsafe {
|
||||
ffi::EVP_RAND_CTX_free(self.0.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InstalledRandCtx(ManuallyDrop<RandCtx>);
|
||||
|
||||
impl Drop for InstalledRandCtx {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: Ownership of the EVP_RAND_CTX was transferred to OpenSSL
|
||||
// via RAND_set0_public/private, so we must not call EVP_RAND_CTX_free.
|
||||
// ManuallyDrop prevents RandCtx::drop from running automatically.
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PreviousRandCtx(Option<RandCtx>);
|
||||
|
||||
impl PreviousRandCtx {
|
||||
fn capture_public() -> Result<Self, ErrorStack> {
|
||||
RandCtx::current_public().map(Self)
|
||||
}
|
||||
|
||||
fn capture_private() -> Result<Self, ErrorStack> {
|
||||
RandCtx::current_private().map(Self)
|
||||
}
|
||||
|
||||
fn restore_public(&mut self) {
|
||||
let Some(ctx) = self.0.take() else {
|
||||
return;
|
||||
};
|
||||
// SAFETY: Restoring previously captured RNG context.
|
||||
// - ctx.as_ptr() is a valid non-null EVP_RAND_CTX pointer
|
||||
// - RAND_set0_public takes ownership of the context
|
||||
// - We forget ctx to prevent double-free since OpenSSL now owns it
|
||||
// - Ignoring return value as restoration is best-effort during cleanup
|
||||
let _ = unsafe { ffi::RAND_set0_public(std::ptr::null_mut(), ctx.as_ptr()) };
|
||||
std::mem::forget(ctx);
|
||||
}
|
||||
|
||||
fn restore_private(&mut self) {
|
||||
let Some(ctx) = self.0.take() else {
|
||||
return;
|
||||
};
|
||||
// SAFETY: Restoring previously captured RNG context.
|
||||
// - ctx.as_ptr() is a valid non-null EVP_RAND_CTX pointer
|
||||
// - RAND_set0_private takes ownership of the context
|
||||
|
||||
// - We forget ctx to prevent double-free since OpenSSL now owns it
|
||||
// - Ignoring return value as restoration is best-effort during cleanup
|
||||
let _ = unsafe { ffi::RAND_set0_private(std::ptr::null_mut(), ctx.as_ptr()) };
|
||||
std::mem::forget(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeterministicTestRandGuard {
|
||||
previous_public: PreviousRandCtx,
|
||||
previous_private: PreviousRandCtx,
|
||||
_public: InstalledRandCtx,
|
||||
_private: InstalledRandCtx,
|
||||
}
|
||||
|
||||
impl DeterministicTestRandGuard {
|
||||
/// Install OpenSSL >= 3 TEST-RAND as the thread-local public/private RNG for deterministic
|
||||
/// tests.
|
||||
///
|
||||
/// The supplied entropy is consumed across generate calls. The nonce is replayed for each
|
||||
/// nonce request. Per OpenSSL documentation, the public and private DRBG instances are
|
||||
/// thread-local, so each thread can safely install its own deterministic RNG without
|
||||
/// affecting other threads.
|
||||
///
|
||||
/// # Thread Safety
|
||||
///
|
||||
/// From OpenSSL documentation (RAND_get0_primary(3)):
|
||||
/// > "The public and private DRBG are thread-local instances, which are used by
|
||||
/// > RAND_bytes() and RAND_priv_bytes(), respectively."
|
||||
///
|
||||
/// Reference: <https://docs.openssl.org/3.1/man3/RAND_get0_primary/>
|
||||
///
|
||||
/// **Note:** RAND_set0_public() and RAND_set0_private() require OpenSSL >= 3.1.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an OpenSSL error if the TEST-RAND provider cannot be configured.
|
||||
pub fn install(entropy: &[u8], nonce: &[u8]) -> Result<Self, ErrorStack> {
|
||||
let previous_public = PreviousRandCtx::capture_public()?;
|
||||
let previous_private = PreviousRandCtx::capture_private()?;
|
||||
let rand = FetchedRand::fetch_test_rand()?;
|
||||
|
||||
let public = RandCtx::new(&rand)?;
|
||||
public.instantiate_test_rand(entropy, nonce)?;
|
||||
let public = public.install_as_public()?;
|
||||
|
||||
let private = RandCtx::new(&rand)?;
|
||||
private.instantiate_test_rand(entropy, nonce)?;
|
||||
let private = private.install_as_private()?;
|
||||
|
||||
Ok(Self {
|
||||
previous_public,
|
||||
previous_private,
|
||||
_public: public,
|
||||
_private: private,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DeterministicTestRandGuard {
|
||||
fn drop(&mut self) {
|
||||
self.previous_private.restore_private();
|
||||
self.previous_public.restore_public();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::x509::{X509Crl, X509};
|
||||
|
||||
use crate::{Error, Result};
|
||||
use openssl::{
|
||||
error::ErrorStack,
|
||||
x509::{X509Crl, X509},
|
||||
};
|
||||
|
||||
/// Read all CRLs from the buffer and parse them into a vector.
|
||||
///
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use serde::Serialize;
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::req::Keyslot;
|
||||
use crate::static_assert;
|
||||
use crate::{Error, Result};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::arcb::AttestationFlags;
|
||||
use crate::req::KeyslotV1;
|
||||
use crate::{static_assert, Error, Result};
|
||||
|
||||
/// Hash for additional-data stuff used for parsing [`AdditionalData`]
|
||||
pub(super) const PHKH_SIZE: u32 = 0x20;
|
||||
static_assert!(Keyslot::PHKH_SIZE == PHKH_SIZE);
|
||||
static_assert!(KeyslotV1::PHKH_SIZE == PHKH_SIZE);
|
||||
pub(super) const SECRET_STORE_HASH_SIZE: u32 = 0x40;
|
||||
pub(super) const FW_STATE_SIZE: u32 = 0x140;
|
||||
|
||||
|
||||
@@ -2,27 +2,19 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use openssl::pkey::{PKey, Public};
|
||||
use std::mem::size_of;
|
||||
|
||||
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, U32};
|
||||
|
||||
use crate::{
|
||||
assert_size,
|
||||
attest::{AttestationMagic, AttestationMeasAlg},
|
||||
crypto::random_array,
|
||||
misc::Flags,
|
||||
req::{Aad, BinReqValues, Keyslot, ReqEncrCtx},
|
||||
request::{Confidential, MagicValue, Request, RequestVersion, SymKey, Zeroize},
|
||||
static_assert,
|
||||
uv::UvFlags,
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
use super::{
|
||||
additional::{FW_STATE_SIZE, PHKH_SIZE, SECRET_STORE_HASH_SIZE},
|
||||
AttNonce,
|
||||
};
|
||||
|
||||
use super::additional::{FW_STATE_SIZE, PHKH_SIZE, SECRET_STORE_HASH_SIZE};
|
||||
use super::AttNonce;
|
||||
use crate::attest::{AttestationMagic, AttestationMeasAlg};
|
||||
use crate::crypto::random_array;
|
||||
use crate::misc::Flags;
|
||||
use crate::req::{Aad, BinReqValues, HostKey, Keyslot, ReqEncrCtx};
|
||||
use crate::request::{Confidential, MagicValue, Request, RequestVersion, SymKey, Zeroize};
|
||||
use crate::uv::UvFlags;
|
||||
use crate::{assert_size, static_assert, Error, Result};
|
||||
#[cfg(doc)]
|
||||
use crate::{
|
||||
request::SymKeyType,
|
||||
@@ -59,7 +51,7 @@ use crate::{
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use s390_pv::attest::{AttestationFlags, AttestationMeasAlg, AttestationRequest, AttestationVersion};
|
||||
/// # use s390_pv::request::{SymKeyType, Request, ReqEncrCtx};
|
||||
/// # use s390_pv::request::{SymKeyType, Request, ReqEncrCtx, HostKey};
|
||||
/// # fn main() -> s390_pv::Result<()> {
|
||||
/// let att_version = AttestationVersion::One;
|
||||
/// let meas_alg = AttestationMeasAlg::HmacSha512;
|
||||
@@ -68,11 +60,11 @@ use crate::{
|
||||
/// let hkd = s390_pv::misc::read_certs(&std::fs::read("host-key-document.crt")?)?;
|
||||
/// // IBM issued HKD certificates typically have one X509
|
||||
/// let hkd = hkd.first().unwrap().public_key()?;
|
||||
/// arcb.add_hostkey(hkd);
|
||||
/// arcb.add_hostkey(HostKey::V1(hkd));
|
||||
/// // you can add multiple hostkeys
|
||||
/// // arcb.add_hostkey(another_hkd);
|
||||
/// // encrypt it
|
||||
/// let ctx = ReqEncrCtx::random(SymKeyType::Aes256)?;
|
||||
/// let ctx = ReqEncrCtx::random(SymKeyType::Aes256Gcm)?;
|
||||
/// let arcb = arcb.encrypt(&ctx)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -243,7 +235,7 @@ impl Request for AttestationRequest {
|
||||
ctx.encrypt_aead(&aad, conf).map(|res| res.into_buf())
|
||||
}
|
||||
|
||||
fn add_hostkey(&mut self, hostkey: PKey<Public>) {
|
||||
fn add_hostkey(&mut self, hostkey: HostKey) {
|
||||
self.keyslots.push(Keyslot::new(hostkey))
|
||||
}
|
||||
}
|
||||
@@ -419,8 +411,9 @@ impl Zeroize for ReqConfData {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use crate::{get_test_asset, request::SymKey, test_utils::get_test_keys};
|
||||
use crate::get_test_asset;
|
||||
use crate::request::SymKey;
|
||||
use crate::test_utils::get_test_keys;
|
||||
|
||||
const ARPK: [u8; 32] = [0x17; 32];
|
||||
const NONCE: [u8; 16] = [0xab; 16];
|
||||
@@ -450,7 +443,7 @@ mod test {
|
||||
arcb.conf.value_mut().nonce = NONCE;
|
||||
arcb.conf.value_mut().meas_key = MEAS;
|
||||
|
||||
arcb.add_hostkey(host_key);
|
||||
arcb.add_hostkey(HostKey::V1(host_key));
|
||||
arcb.encrypt(&ctx).unwrap()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,20 +2,21 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use super::AttNonce;
|
||||
use crate::{
|
||||
attest::AttestationMeasAlg, brcb::BootHdrTags, crypto::calculate_hmac, request::Confidential,
|
||||
uv::ConfigUid, Result,
|
||||
};
|
||||
use openssl::{
|
||||
hash::MessageDigest,
|
||||
pkey::{PKeyRef, Private},
|
||||
};
|
||||
use std::mem::size_of;
|
||||
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkey::{PKeyRef, Private};
|
||||
use zerocopy::{BigEndian, IntoBytes, U16, U32};
|
||||
|
||||
use super::AttNonce;
|
||||
use crate::attest::AttestationMeasAlg;
|
||||
#[cfg(doc)]
|
||||
use crate::attest::AttestationRequest;
|
||||
use crate::brcb::BootHdrTags;
|
||||
use crate::crypto::calculate_hmac;
|
||||
use crate::request::Confidential;
|
||||
use crate::uv::ConfigUid;
|
||||
use crate::Result;
|
||||
|
||||
/// Holds the data to be measured.
|
||||
///
|
||||
@@ -151,9 +152,10 @@ impl From<Vec<u8>> for AttestationMeasurement {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use openssl::pkey::PKey;
|
||||
|
||||
use super::*;
|
||||
|
||||
const M_KEY: [u8; 64] = [0x41; 64];
|
||||
const BOOT_HDR_TAGS: BootHdrTags = BootHdrTags::new([1; 64], [2; 64], [3; 64], [4; 16]);
|
||||
const CUID: [u8; 16] = [5; 16];
|
||||
|
||||
@@ -2,24 +2,23 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use super::{guest_secret::ListableSecretHdr, user_data::UserData};
|
||||
use crate::{
|
||||
assert_size,
|
||||
crypto::{hkdf_rfc_5869, AeadEncryptionResult},
|
||||
misc::Flags,
|
||||
req::{Aad, BinReqValues, Keyslot, ReqEncrCtx},
|
||||
request::{BootHdrTags, Confidential, Request},
|
||||
secret::{ExtSecret, GuestSecret},
|
||||
uv::{ConfigUid, UvFlags},
|
||||
Result,
|
||||
};
|
||||
use openssl::{
|
||||
md::Md,
|
||||
pkey::{PKey, Private, Public},
|
||||
};
|
||||
use pv_core::{request::RequestVersion, secret::AddSecretMagic, uv::SecretId};
|
||||
use openssl::md::Md;
|
||||
use openssl::pkey::{PKey, Private};
|
||||
use pv_core::request::RequestVersion;
|
||||
use pv_core::secret::AddSecretMagic;
|
||||
use pv_core::uv::SecretId;
|
||||
use zerocopy::{Immutable, IntoBytes};
|
||||
|
||||
use super::guest_secret::ListableSecretHdr;
|
||||
use super::user_data::UserData;
|
||||
use crate::crypto::{hkdf_rfc_5869, AeadEncryptionResult};
|
||||
use crate::misc::Flags;
|
||||
use crate::req::{Aad, BinReqValues, HostKey, Keyslot, ReqEncrCtx};
|
||||
use crate::request::{BootHdrTags, Confidential, Request};
|
||||
use crate::secret::{ExtSecret, GuestSecret};
|
||||
use crate::uv::{ConfigUid, UvFlags};
|
||||
use crate::{assert_size, Result};
|
||||
|
||||
/// Authenticated data w/o user data
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, IntoBytes, Immutable)]
|
||||
@@ -310,7 +309,7 @@ impl Request for AddSecretRequest {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_hostkey(&mut self, hostkey: PKey<Public>) {
|
||||
fn add_hostkey(&mut self, hostkey: HostKey) {
|
||||
self.keyslots.push(Keyslot::new(hostkey))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,31 +2,25 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
#[allow(unused_imports)] // used for more convenient docstring
|
||||
use super::asrcb::AddSecretRequest;
|
||||
use crate::{
|
||||
assert_size,
|
||||
crypto::{hash, random_array, SymKeyType},
|
||||
request::{
|
||||
openssl::{NID_ED25519, NID_ED448},
|
||||
Confidential,
|
||||
},
|
||||
uv::{
|
||||
AesSizes, AesXtsSizes, EcCurves, HmacShaSizes, ListableSecretType, RetrievableSecret,
|
||||
RetrieveCmd, SecretId,
|
||||
},
|
||||
Error, Result,
|
||||
};
|
||||
use openssl::{
|
||||
hash::MessageDigest,
|
||||
nid::Nid,
|
||||
pkey::{Id, PKey, PKeyRef, Private},
|
||||
};
|
||||
use std::fmt::Display;
|
||||
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::nid::Nid;
|
||||
use openssl::pkey::{Id, PKey, PKeyRef, Private};
|
||||
use pv_core::static_assert;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use zerocopy::{BigEndian, KnownLayout};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, U16, U32};
|
||||
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, U16, U32};
|
||||
|
||||
#[allow(unused_imports)] // used for more convenient docstring
|
||||
use super::asrcb::AddSecretRequest;
|
||||
use crate::crypto::{hash, random_array, SymKeyType};
|
||||
use crate::request::openssl::{NID_ED25519, NID_ED448};
|
||||
use crate::request::Confidential;
|
||||
use crate::uv::{
|
||||
AesSizes, AesXtsSizes, EcCurves, HmacShaSizes, ListableSecretType, RetrievableSecret,
|
||||
RetrieveCmd, SecretId,
|
||||
};
|
||||
use crate::{assert_size, Error, Result};
|
||||
|
||||
const ASSOC_SECRET_SIZE: usize = 32;
|
||||
const CCK_SIZE: usize = 32;
|
||||
@@ -476,13 +470,13 @@ impl UpdateCckHdr {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::HmacShaSizes as HmacSizes;
|
||||
use super::RetrievableSecret::*;
|
||||
use super::*;
|
||||
use openssl::ec::{EcGroup, EcKey};
|
||||
use pv_core::uv::AesSizes;
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
use super::RetrievableSecret::*;
|
||||
use super::{HmacShaSizes as HmacSizes, *};
|
||||
|
||||
#[test]
|
||||
fn association() {
|
||||
let secret_value = [0x11; 32];
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use crate::{crypto::SymKeyType, pem::Pem, uvsecret::guest_secret::MAX_SIZE_PLAIN_PAYLOAD, Result};
|
||||
|
||||
use log::warn;
|
||||
use pv_core::{
|
||||
request::Confidential,
|
||||
uv::{ListableSecretType, RetrievableSecret, RetrieveCmd},
|
||||
};
|
||||
use zerocopy::BigEndian;
|
||||
use zerocopy::{FromBytes, U16};
|
||||
use pv_core::request::Confidential;
|
||||
use pv_core::uv::{ListableSecretType, RetrievableSecret, RetrieveCmd};
|
||||
use zerocopy::{BigEndian, FromBytes, U16};
|
||||
|
||||
use crate::crypto::SymKeyType;
|
||||
use crate::pem::Pem;
|
||||
use crate::uvsecret::guest_secret::MAX_SIZE_PLAIN_PAYLOAD;
|
||||
use crate::Result;
|
||||
|
||||
/// An IBM Protected Key
|
||||
///
|
||||
@@ -72,8 +72,8 @@ impl From<RetrieveCmd> for RetrievedSecret {
|
||||
|
||||
match kind {
|
||||
ListableSecretType::Retrievable(RetrievableSecret::PlainText) => {
|
||||
// Will not run into default, retrieve has a granularity of 16 bytes and 16 bytes is the
|
||||
// minimum size
|
||||
// Will not run into default, retrieve has a granularity of 16 bytes and 16 bytes is
|
||||
// the minimum size
|
||||
let len = U16::<BigEndian>::read_from_prefix(key.value())
|
||||
.unwrap_or_default()
|
||||
.0
|
||||
@@ -81,8 +81,8 @@ impl From<RetrieveCmd> for RetrievedSecret {
|
||||
|
||||
// Test if the plain text secret has a size:
|
||||
// 1. len <= 8190
|
||||
// 2. first two bytes are max 15 less than buffer-size+2 i.e. smaller than the
|
||||
// block length
|
||||
// 2. first two bytes are max 15 less than buffer-size+2 i.e. smaller than the block
|
||||
// length
|
||||
// 3. bytes after len + 2 are zero
|
||||
match len <= MAX_SIZE_PLAIN_PAYLOAD
|
||||
&& key.value().len() - (len + 2) < SymKeyType::AES_256_GCM_BLOCK_LEN
|
||||
@@ -148,9 +148,10 @@ impl RetrievedSecret {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use pv_core::uv::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn mk_retr(secret: &[u8]) -> RetrievedSecret {
|
||||
let entry = SecretEntry::new(
|
||||
0,
|
||||
|
||||
@@ -2,21 +2,17 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use crate::assert_size;
|
||||
use crate::{
|
||||
crypto::{sign_msg, verify_signature},
|
||||
req::BinReqValues,
|
||||
request::{
|
||||
openssl::pkey::{HasParams, HasPublic, Id, PKey, PKeyRef, Private, Public},
|
||||
RequestMagic,
|
||||
},
|
||||
secret::{AddSecretMagic, AddSecretRequest, AddSecretVersion, UserDataType},
|
||||
Error, Result,
|
||||
};
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::nid::Nid;
|
||||
use zerocopy::{BigEndian, FromBytes, IntoBytes, KnownLayout, U16};
|
||||
|
||||
use crate::crypto::{sign_msg, verify_signature};
|
||||
use crate::req::BinReqValues;
|
||||
use crate::request::openssl::pkey::{HasParams, HasPublic, Id, PKey, PKeyRef, Private, Public};
|
||||
use crate::request::RequestMagic;
|
||||
use crate::secret::{AddSecretMagic, AddSecretRequest, AddSecretVersion, UserDataType};
|
||||
use crate::{assert_size, Error, Result};
|
||||
|
||||
/// User data.
|
||||
///
|
||||
/// User defined data can be:
|
||||
@@ -380,7 +376,8 @@ impl From<VerifiedUserData> for Vec<u8> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{get_test_asset, test_utils::get_test_keys};
|
||||
use crate::get_test_asset;
|
||||
use crate::test_utils::get_test_keys;
|
||||
|
||||
#[test]
|
||||
fn sign_null() {
|
||||
|
||||
@@ -2,22 +2,18 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use crate::openssl_extensions::{StackableX509Crl, X509StoreContextExtension, X509StoreExtension};
|
||||
use core::slice;
|
||||
use std::path::Path;
|
||||
|
||||
use helper::{download_first_crl_from_x509, StoreSetupMode};
|
||||
use log::{debug, trace};
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::stack::Stack;
|
||||
use openssl::x509::store::X509Store;
|
||||
use openssl::x509::{CrlStatus, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, X509};
|
||||
use std::path::Path;
|
||||
|
||||
#[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};
|
||||
use crate::openssl_extensions::{StackableX509Crl, X509StoreContextExtension, X509StoreExtension};
|
||||
use crate::Result;
|
||||
|
||||
mod helper;
|
||||
@@ -167,7 +163,8 @@ impl CertVerifier {
|
||||
/// * `cert_paths` - Paths to certificates for the chain of trust
|
||||
/// * `crl_paths` - Paths to certificate revocation lists for the chain of trust
|
||||
/// * `root_ca_path` - Path to the root of trust
|
||||
/// * `offline` - if set to true the verification process will not try to download CRLs from the internet.
|
||||
/// * `offline` - if set to true the verification process will not try to download CRLs from the
|
||||
/// internet.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -183,26 +180,51 @@ impl CertVerifier {
|
||||
Q: AsRef<Path>,
|
||||
R: AsRef<Path>,
|
||||
{
|
||||
let mut store = helper::store_setup(root_ca_path, crl_paths, cert_paths)?;
|
||||
let mut untr_certs = Vec::with_capacity(cert_paths.len());
|
||||
for path in cert_paths {
|
||||
let mut crt = read_certs(&read_file(path, "certificate")?)?;
|
||||
if !offline {
|
||||
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);
|
||||
}
|
||||
let (ibm_z_sign_key, chain) = helper::extract_ibm_sign_key(untr_certs.clone())?;
|
||||
let root_ca_verification = match root_ca_path {
|
||||
Some(_) => helper::RootCaVerification::SkipPinning,
|
||||
None => helper::RootCaVerification::RootCaOrganizationPinning("DigiCert"),
|
||||
};
|
||||
|
||||
// remove the IBM signing certificate from chain.
|
||||
// We have to verify them separately as they are not marked as intermediate certs
|
||||
let (ibm_z_sign_key, chain) = helper::extract_ibm_sign_key(untr_certs)?;
|
||||
// Two-round verification:
|
||||
//
|
||||
// Round 1: Verify chain without CRL checks before downloading files
|
||||
// from URLs from (yet) untrusted certificates.
|
||||
let store_builder = helper::store_setup(
|
||||
root_ca_path.as_ref(),
|
||||
crl_paths,
|
||||
cert_paths,
|
||||
StoreSetupMode::WithoutCrlCheck,
|
||||
)?;
|
||||
helper::verify_chain(
|
||||
&store_builder.build(),
|
||||
&chain,
|
||||
&[&ibm_z_sign_key],
|
||||
&root_ca_verification,
|
||||
)?;
|
||||
|
||||
let store = store.build();
|
||||
helper::verify_chain(&store, &chain, slice::from_ref(&ibm_z_sign_key))?;
|
||||
// Round 2: Download CRLs and verify again, but this time with CRL checks
|
||||
let mut store_builder = helper::store_setup(
|
||||
root_ca_path,
|
||||
crl_paths,
|
||||
cert_paths,
|
||||
StoreSetupMode::WithCrlCheck,
|
||||
)?;
|
||||
if !offline {
|
||||
for cert in &untr_certs {
|
||||
if let Some(crls) = download_first_crl_from_x509(cert)? {
|
||||
crls.iter().try_for_each(|c| store_builder.add_crl(c))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let store = store_builder.build();
|
||||
helper::verify_chain(&store, &chain, &[&ibm_z_sign_key], &root_ca_verification)?;
|
||||
|
||||
Ok(Self {
|
||||
store,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,32 +4,14 @@
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use super::{helper, helper::*, *};
|
||||
use crate::{utils::read_crls, Error, HkdVerifyErrorType::*};
|
||||
use openssl::{stack::Stack, x509::X509Crl};
|
||||
use std::path::Path;
|
||||
use openssl::stack::Stack;
|
||||
|
||||
use super::helper::*;
|
||||
use super::{helper, *};
|
||||
use crate::test_utils::*;
|
||||
|
||||
// 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)?)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
use crate::verify::helper::StoreSetupMode;
|
||||
use crate::Error;
|
||||
use crate::HkdVerifyErrorType::*;
|
||||
|
||||
#[test]
|
||||
fn store_setup() {
|
||||
@@ -37,7 +19,12 @@ fn store_setup() {
|
||||
let inter_path = get_cert_asset_path("inter.crt");
|
||||
let crls: [String; 0] = [];
|
||||
|
||||
let store = helper::store_setup(None::<String>, &crls, &[&ibm_path, &inter_path]);
|
||||
let store = helper::store_setup(
|
||||
None::<String>,
|
||||
&crls,
|
||||
&[&ibm_path, &inter_path],
|
||||
StoreSetupMode::WithCrlCheck,
|
||||
);
|
||||
assert!(store.is_ok());
|
||||
}
|
||||
|
||||
@@ -60,20 +47,51 @@ fn verify_chain_offline() {
|
||||
let root_crt = get_cert_asset_path("root_ca.chained.crt");
|
||||
let certs: [String; 0] = [];
|
||||
|
||||
let store = helper::store_setup(Some(&root_crt), &[&inter_crl], &certs)
|
||||
.unwrap()
|
||||
.build();
|
||||
let store = helper::store_setup(
|
||||
Some(&root_crt),
|
||||
&[&inter_crl],
|
||||
&certs,
|
||||
StoreSetupMode::WithCrlCheck,
|
||||
)
|
||||
.unwrap()
|
||||
.build();
|
||||
|
||||
let mut sk = Stack::<X509>::new().unwrap();
|
||||
sk.push(inter_crt).unwrap();
|
||||
assert!(verify_chain(&store, &sk, &[ibm_crt]).is_ok());
|
||||
assert!(verify_chain(
|
||||
&store,
|
||||
&sk,
|
||||
&[&ibm_crt],
|
||||
&RootCaVerification::RootCaOrganizationPinning(
|
||||
"International Business Machines Corporationn"
|
||||
)
|
||||
)
|
||||
.is_err());
|
||||
assert!(verify_chain(
|
||||
&store,
|
||||
&sk,
|
||||
&[&ibm_crt],
|
||||
&RootCaVerification::RootCaOrganizationPinning("International")
|
||||
)
|
||||
.is_err());
|
||||
assert!(verify_chain(
|
||||
&store,
|
||||
&sk,
|
||||
&[&ibm_crt],
|
||||
&RootCaVerification::RootCaOrganizationPinning(
|
||||
"International Business Machines Corporation"
|
||||
)
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
assert!(verify_chain(&store, &sk, &[&ibm_crt], &RootCaVerification::SkipPinning).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_points() {
|
||||
let crt = load_gen_cert("ibm.crt");
|
||||
let res = x509_dist_points(&crt);
|
||||
let exp = vec!["inter_ca.crl"];
|
||||
let exp = vec!["http://inter_ca.crl"];
|
||||
assert_eq!(res, exp);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,25 +3,18 @@
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
#![allow(missing_docs)]
|
||||
use openssl::{
|
||||
ec::{EcGroup, EcKey},
|
||||
nid::Nid,
|
||||
pkey::Private,
|
||||
};
|
||||
use s390_pv::{
|
||||
get_test_asset,
|
||||
request::{
|
||||
openssl::pkey::{PKey, Public},
|
||||
BootHdrTags, ReqEncrCtx, Request, SymKey,
|
||||
},
|
||||
secret::{
|
||||
verify_asrcb_and_get_user_data, AddSecretFlags, AddSecretRequest, AddSecretVersion,
|
||||
ExtSecret, GuestSecret,
|
||||
},
|
||||
test_utils::get_test_keys,
|
||||
uv::ConfigUid,
|
||||
Result,
|
||||
use openssl::ec::{EcGroup, EcKey};
|
||||
use openssl::nid::Nid;
|
||||
use openssl::pkey::Private;
|
||||
use s390_pv::request::openssl::pkey::{PKey, Public};
|
||||
use s390_pv::request::{BootHdrTags, HostKey, ReqEncrCtx, Request, SymKey};
|
||||
use s390_pv::secret::{
|
||||
verify_asrcb_and_get_user_data, AddSecretFlags, AddSecretRequest, AddSecretVersion, ExtSecret,
|
||||
GuestSecret,
|
||||
};
|
||||
use s390_pv::test_utils::get_test_keys;
|
||||
use s390_pv::uv::ConfigUid;
|
||||
use s390_pv::{get_test_asset, Result};
|
||||
|
||||
const TAGS: BootHdrTags = BootHdrTags::new([1; 64], [2; 64], [3; 64], [4; 16]);
|
||||
const CUID: ConfigUid = [0x42u8; 16];
|
||||
@@ -33,7 +26,7 @@ fn create_asrcb(
|
||||
ext_secret: Option<ExtSecret>,
|
||||
flags: AddSecretFlags,
|
||||
cuid: Option<ConfigUid>,
|
||||
hkd: PKey<Public>,
|
||||
hkd: HostKey,
|
||||
ctx: &ReqEncrCtx,
|
||||
) -> Result<Vec<u8>> {
|
||||
let mut asrcb = AddSecretRequest::new(AddSecretVersion::One, guest_secret, TAGS, flags);
|
||||
@@ -74,7 +67,14 @@ where
|
||||
true => Some(CUID),
|
||||
false => None,
|
||||
};
|
||||
create_asrcb(guest_secret, ext_secret.into(), flags, cuid, host_key, &ctx)
|
||||
create_asrcb(
|
||||
guest_secret,
|
||||
ext_secret.into(),
|
||||
flags,
|
||||
cuid,
|
||||
HostKey::V1(host_key),
|
||||
&ctx,
|
||||
)
|
||||
}
|
||||
|
||||
fn association() -> GuestSecret {
|
||||
@@ -98,7 +98,7 @@ fn create_signed_asrcb(skey: PKey<Private>, user_data: Vec<u8>) -> Vec<u8> {
|
||||
let mut asrcb =
|
||||
AddSecretRequest::new(AddSecretVersion::One, GuestSecret::Null, TAGS, no_flag());
|
||||
|
||||
asrcb.add_hostkey(host_key);
|
||||
asrcb.add_hostkey(HostKey::V1(host_key));
|
||||
asrcb.set_user_data(user_data, Some(skey)).unwrap();
|
||||
asrcb.encrypt(&ctx).unwrap()
|
||||
}
|
||||
@@ -110,7 +110,7 @@ fn null_none_default_ncuid_one_user_unsgn() {
|
||||
let mut asrcb =
|
||||
AddSecretRequest::new(AddSecretVersion::One, GuestSecret::Null, TAGS, no_flag());
|
||||
|
||||
asrcb.add_hostkey(host_key);
|
||||
asrcb.add_hostkey(HostKey::V1(host_key));
|
||||
asrcb.set_user_data(user_data_orig.clone(), None).unwrap();
|
||||
let asrcb = asrcb.encrypt(&ctx).unwrap();
|
||||
|
||||
@@ -243,7 +243,7 @@ fn null_none_default_cuid_seven() {
|
||||
let (hkd, ctx) = get_crypto();
|
||||
let mut asrcb =
|
||||
AddSecretRequest::new(AddSecretVersion::One, GuestSecret::Null, TAGS, no_flag());
|
||||
(0..7).for_each(|_| asrcb.add_hostkey(hkd.clone()));
|
||||
(0..7).for_each(|_| asrcb.add_hostkey(HostKey::V1(hkd.clone())));
|
||||
asrcb.set_cuid(CUID);
|
||||
let asrcb = asrcb.encrypt(&ctx).unwrap();
|
||||
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE/TCCAuWgAwIBAgIUWT/F3gP9fOTTq3yOMVskcXM8vOAwDQYJKoZIhvcNAQEN
|
||||
MIIFBDCCAuygAwIBAgIUD2bTT6yk21U+ojAQnf3iw5w2EEowDQYJKoZIhvcNAQEN
|
||||
BQAwgcwxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
|
||||
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
|
||||
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
|
||||
azEVMBMGA1UEBwwMUG91Z2hrZWVwc2llMScwJQYDVQQLDB5JQk0gWiBIb3N0IEtl
|
||||
eSBTaWduaW5nIFNlcnZpY2UwIBcNMjQwMzIxMTQ1MjM5WhgPMjM4ODEyMjMxNDUy
|
||||
MzlaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp
|
||||
eSBTaWduaW5nIFNlcnZpY2UwIBcNMjYwNzAyMDg0NzQ4WhgPMjM5MTA0MDUwODQ3
|
||||
NDhaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp
|
||||
bmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrSW50ZXJuYXRpb25h
|
||||
bCBCdXNpbmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjERMA8GA1UECAwITmV3IFlv
|
||||
cmsxDzANBgNVBAcMBkFybW9uazEXMBUGA1UECwwOSUJNIFogSG9zdCBLZXkwgZsw
|
||||
EAYHKoZIzj0CAQYFK4EEACMDgYYABAAT1zpBNemPCT0tEx2S9qnlPxyBgxKl6BSX
|
||||
ghqf3MfOqQKIUdKEbxP0nr2QtIR/MwvBp4YhjxZ9AZtzVtXbQrULTAGlKK4qcf1I
|
||||
W1rYZ5S0b4dmvh2HbIv9wZLWKaZ/ovnvAJk949WDCbBzC3Dy1E3zCaYPefLHHNve
|
||||
dWX8RtFUhnTqm6NxMG8wHQYDVR0fBBYwFDASoBCgDoYMZmFrZV9pYm0uY3J0MA4G
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAXR6FCIgd+fjhO/WJ
|
||||
KwLTP01mBDtYkWbVE71jshjLLpZHunRpsYKbQKCwaDmMYLRrQnTxPgZH1PVKzguI
|
||||
7M7n9zyhgYkDgYYABAAT1zpBNemPCT0tEx2S9qnlPxyBgxKl6BSXghqf3MfOqQKI
|
||||
UdKEbxP0nr2QtIR/MwvBp4YhjxZ9AZtzVtXbQrULTAGlKK4qcf1IW1rYZ5S0b4dm
|
||||
vh2HbIv9wZLWKaZ/ovnvAJk949WDCbBzC3Dy1E3zCaYPefLHHNvedWX8RtFUhnTq
|
||||
mw==
|
||||
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBoV15DZCYEBy2dx5Q
|
||||
7PjcNBni/J3FXBka2MZdy402KKrrW6mZI554n4IlpNeyL9Tb4bMp4glYdDsoHLp/
|
||||
jbZ4K4ChgYkDgYYABAGXMdZTHQ6O1boDC7ncHiILfFqHBRkOaEPsNTntrxSdyWj7
|
||||
CCAa/VkUKVxq3CnyXqbUv8V/fNncU/ibw0o1m/T3SABExiXKfuKl1rUm99FfFeZO
|
||||
2uuIcg0pzbGf+opPttIyR+zp1LLbF3eDo0PEovBLT1J1s6iUIbx8hyfMwUG5Jmxd
|
||||
iA==
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -3,18 +3,18 @@ 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=
|
||||
MScwJQYDVQQLDB5JQk0gWiBIb3N0IEtleSBTaWduaW5nIFNlcnZpY2UXDTI2MDYy
|
||||
MjEwNDc0OFoYDzIzOTEwNDA1MTA0NzQ4WjAVMBMCAgIrFw0yNjA3MDExMDQ3NDha
|
||||
oCMwITAfBgNVHSMEGDAWgBRWnIhXOCFjqLnM9VMe9E7HEhbxKzANBgkqhkiG9w0B
|
||||
AQ0FAAOCAgEAQIp0vuCpPifq82vs30SfcTn0ppIeM2s7TSpGL8AVC0+56x8RXl+O
|
||||
1QUw4gOWtlO4m7legzGbCu1Wh3gXFb+6nUhWhT0egtAneoNDXRSHGXdo0nWAoH3J
|
||||
XUN/PaipGvDIEZF/UnehYoRrLG307CgJBQkCErFVvI6XJxqGtc6wgsQM2a5A72zV
|
||||
jlPEAbCsj5k+y7XzJ+vFVA531IHjdtYrEVMh2T0dN821n/yCwwecuMP4semlqYx0
|
||||
xJNm2y4whvyQnDpg4YIfLw5LUc9otvztLYW8h3Si34TO0ApJ6TpEdBdFx23jm/jJ
|
||||
VbfM+g2wFoqsW621BiHn9S1KYD0ENSsbaG6BVRm/CTbPNYw6AdgZS1ggZ+a30NCn
|
||||
ktg6wxVmXK0I3fzgTcOnaspr/rxkBjDi16sfob9yUuaBuTBOgMO0suq7BEFIl97Q
|
||||
tpkVVz9mb53Ixt/ZuF6QpB4DqOyksS8YehBJc9nOGMknOxcS1zYrWJzVJyyrKrlB
|
||||
3VHQ4aYE0WsmP+dpX/QE+gj9/Mp6cvTywVSjW/d9zGOyrSvS/ViU1qsMWrr2iy23
|
||||
tIOaWRVJBi0TX8S8om4ACgi/qwYGTAcH32Hde0nKy07Bm7JJjGUtJbfLzkM/2rjW
|
||||
qvmPlmmPWJxMyVYoY9+mamuDd2jRtJyoULrE5hCIupFKVV7Di8RQJJc=
|
||||
-----END X509 CRL-----
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGrTCCBJWgAwIBAgIUMCRfNPXX7mCzJea1P3mCUDqZdB0wDQYJKoZIhvcNAQEL
|
||||
MIIGtDCCBJygAwIBAgIUJvPxAmw0HNfQtDlcHDQQXvh5AegwDQYJKoZIhvcNAQEL
|
||||
BQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
|
||||
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
|
||||
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
|
||||
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI0
|
||||
MDMyMTE0NTIzOVoYDzIzODgxMjIzMTQ1MjM5WjCBzDELMAkGA1UEBhMCVVMxNDAy
|
||||
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI2
|
||||
MDcwMjA4NDc0OFoYDzIzOTEwNDA1MDg0NzQ4WjCBzDELMAkGA1UEBhMCVVMxNDAy
|
||||
BgNVBAoMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29ycG9yYXRp
|
||||
b24xNDAyBgNVBAMMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29y
|
||||
cG9yYXRpb24xETAPBgNVBAgMCE5ldyBZb3JrMRUwEwYDVQQHDAxQb3VnaGtlZXBz
|
||||
aWUxJzAlBgNVBAsMHklCTSBaIEhvc3QgS2V5IFNpZ25pbmcgU2VydmljZTCCAiIw
|
||||
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALIvcLAKt2DM5rTc1nOhyVT2EbNy
|
||||
CA1Sy+l1mSloBRVqjyk464mvlqq9p/CDO1e6tWiFhdEFChuTYzzDOxHazLjPc2Y5
|
||||
U+r0QYYY8KK6jLQDj4crChPMJoJ0HZbmlWe/3uMl7lmrVMyHgqqOftQ52etBCGDn
|
||||
d/RV7U4OC+MJ01ePYUcABxPh3APA+DDV5eZ2b1k74JzLvXa+SGA82MPDQYc70Waf
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
vpiaRjhZtk5MLPJs9mTHq1STrzL9
|
||||
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
|
||||
Lt5nZ3XPsdhCctZyYGqQjq5YsoGNU1yr
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -3,18 +3,18 @@ MIIDRjCCAS4CAQEwDQYJKoZIhvcNAQENBQAwgb0xCzAJBgNVBAYTAlVTMTQwMgYD
|
||||
VQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9u
|
||||
MTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBv
|
||||
cmF0aW9uMREwDwYDVQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMR4wHAYD
|
||||
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=
|
||||
VQQLDBVJQk0gWiBJbnRlcm1lZGlhdGUgQ0EXDTI2MDYyMjEwNDc0N1oYDzIzOTEw
|
||||
NDA1MTA0NzQ3WjAVMBMCAgG8Fw0yNjA3MDExMDQ3NDdaoCMwITAfBgNVHSMEGDAW
|
||||
gBRBgPq0WBDRF/Zb2D4wpASJVmNL5TANBgkqhkiG9w0BAQ0FAAOCAgEAhEMl0/XK
|
||||
3bLp1PMsjB4QrgfAqm8DV5I2WXxrHc0anooAlEqIPEGea5FO4UkL0oxz3Ffxo09O
|
||||
Blh9xwAZOOfvjp1mkRucpd2QEdznOlIikL9NXWNMM7Bm9Lljla8pdBrIZQSrBAoi
|
||||
WC3StSccD88Evoua87YH98MyO2md4zeDfDdICzZTrYqWWRhbghiJ/vPQwFY/SM+4
|
||||
uGp47egoxt8lTMNpPbqBV9+ptZvarvICIQmlRTU4ncWKVb2LmNYJ7zJXeJqEqtsX
|
||||
Ti/fIhnZd26IHXfmEp2VNJOp9ODZATiSCZ9od90y/Dhbi2ZmR3hFTU/VrKgzeqzb
|
||||
Qbi+dLKvaVf4HGWVxOUuSY9279W3aLkCbP5iL9qGtjE6hL0XncCDR0ifADTN7zye
|
||||
1o/OcZr7VT4V6a4dBm/5kNJh3RB8fcLGgrn1Rfa+2GSniFOCMjZCjdMlGHq4WmPb
|
||||
yvOLLF2AD8P7PwLxMJ28Elbg9TN7OiV19ALB5ZgEFoBwan4zIWtkekw+pafEqQma
|
||||
cDGx197fUf39bYWxGSpALsP3pptNrTsNmUNdhJuLxO2kq5jFQMXRq+yl5VG7JTms
|
||||
b/VhB86fOt16hHZQto3gKvd0wXvjCRGiYvOJLjbDQG3e8ghTCGU+40CwWhdC0q0A
|
||||
5k1z1ruYUj1mI0+TMGkz5MbyJ3dmgh3JTmQ=
|
||||
-----END X509 CRL-----
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGjDCCBHSgAwIBAgIUKp3mjstxJ9gXt3S7lpKjri2dEUwwDQYJKoZIhvcNAQEL
|
||||
MIIGkzCCBHugAwIBAgIUd+Tu7LLVqsmeGQbJ5IAjvORmZzAwDQYJKoZIhvcNAQEL
|
||||
BQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
|
||||
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
|
||||
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
|
||||
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI0
|
||||
MDMyMTE0NTIzOFoYDzIzODgxMjIzMTQ1MjM4WjCBvTELMAkGA1UEBhMCVVMxNDAy
|
||||
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI2
|
||||
MDcwMjA4NDc0N1oYDzIzOTEwNDA1MDg0NzQ3WjCBvTELMAkGA1UEBhMCVVMxNDAy
|
||||
BgNVBAoMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29ycG9yYXRp
|
||||
b24xNDAyBgNVBAMMK0ludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29y
|
||||
cG9yYXRpb24xETAPBgNVBAgMCE5ldyBZb3JrMQ8wDQYDVQQHDAZBcm1vbmsxHjAc
|
||||
BgNVBAsMFUlCTSBaIEludGVybWVkaWF0ZSBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggIPADCCAgoCggIBAK+kNJHAUL4dcMnjElivyuzkO2UwTUlJcKQCBmWRHYQjRbP5
|
||||
akJx8SZ+wI0Spo00hG4sV2BxA83J+Yrked53DEzlR+RxojA16vXzlUO8c9KH2dJQ
|
||||
E17PgZnu7/hECmQcT69ZJAOh78ILEXRYk+2ixSTaZRTtchJdzfXIQ0633O2Mi/7z
|
||||
z5idQmQeXbitC3QIZeNzwitl2FLXPIw6MUnktOKNjQSNxMr9AU8q1cfOoICJQs0J
|
||||
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
|
||||
ZLaX284IyQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
M9Wd2js5nPPh0AN3Px1643vFYcAQ
|
||||
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
|
||||
xToCDsY72xtSlqKcRx1Jyo5xXSPvd68=
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -3,18 +3,18 @@ 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
|
||||
VQQLDA1JQk0gWiBSb290IENBFw0yNjA2MjIxMDQ3NDZaGA8yMzkxMDQwNTEwNDc0
|
||||
NlowFTATAgIBTRcNMjYwNzAxMTA0NzQ2WqAjMCEwHwYDVR0jBBgwFoAUDz/nhP/+
|
||||
DIPql2WnuHiBw1W1pCowDQYJKoZIhvcNAQENBQADggIBAMZqebVQ5uXrSOjIbzH8
|
||||
RJCo9JjUH3XQJaKQrZW8QWpZKzY2rpLU1Ag6C8jM8qHAEPpkaLbwcpZUOV3g4AEw
|
||||
K5ezIe8VVJK7aHH96XYoIuYVXmohk0M39IEf14sIB5BkCX8aDC8dFekyZf23Uv/T
|
||||
zwjl7RDc4MAaeV4zKGZ0TBAOT9w1Rfek/U4jwQfvuOvY1Mw5wn7SJrrfE4waaPwK
|
||||
Nklpd6VsxvMgmLKV7BU3rEwndkbtkAWyWJw2F1L6p93ZNUBILDFc5o2f5qnLp6Yj
|
||||
qvEZmWUWO7+Y0qNdsOjljmX0XfuWhLuWB2zq6LceR1hr52XABvJAFIDuFnelfgeh
|
||||
c1rXpZThZSNwNhTVcZr4eLIJ/uR3UtIdl5uTkWY8Gsm3jaC9IoPADlSN+fOMV9eR
|
||||
1u0q2XBj0DafadDjeAevxM9xw8S/ToklqgYPRQSA3nq38EVE8c7Klkv9x/Ar2U3M
|
||||
5GGeDIphX93dzi7j1VAWw0fuylY8Bg69NJ9+889K+shDzIL3xBbXEC8RhmiHFi3H
|
||||
We2O2dtrVb62gUd/WgSTxu3OG3mqWPwPU94zK38zPyndDF41YGp70ur7wHkFPcfJ
|
||||
0WopCMqdEWBrUc8ZPZ1EBw9cAd44i+hVQB4x7qzNCmHJWi2942kpGv1vJ+IfUr9/
|
||||
0MtaUK+nInHcSPuyxhdlb6BE
|
||||
-----END X509 CRL-----
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGXzCCBEegAwIBAgIUC2OH79tloDOfMBeyDBA84epTMKYwDQYJKoZIhvcNAQEL
|
||||
MIIGXzCCBEegAwIBAgIULbCWZUfOIiRXCiGx8jr2mhqjQrswDQYJKoZIhvcNAQEL
|
||||
BQAwgbUxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
|
||||
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
|
||||
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
|
||||
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI0
|
||||
MDMyMTE0NTIzOFoYDzIzODgxMjIzMTQ1MjM4WjCBtTELMAkGA1UEBhMCVVMxNDAy
|
||||
azEPMA0GA1UEBwwGQXJtb25rMRYwFAYDVQQLDA1JQk0gWiBSb290IENBMCAXDTI2
|
||||
MDcwMjA4NDc0NloYDzIzOTEwNDA1MDg0NzQ2WjCBtTELMAkGA1UEBhMCVVMxNDAy
|
||||
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
|
||||
AoICAQDgdpk9Tu3dKO1O2orgftU2GkgARccHONa/NqnTcqaw5vbgWU8CiC99ejvC
|
||||
z5ER0R3xldjU3uTh2UXgQCY2Qf51lsYNx7CgjFVzTaoJ9FhD96mEIYtMWPMoF1SR
|
||||
mxxeGQCJHfMtB3ammatkXKV8ia9GlGQFtQU6Mh0CmNZelrvs7zXvYRMfW4oQX1zb
|
||||
9s4n1E+gxErTRw+PlK2LmOPO7AAMrrGn2sbxaoqJijMWOysekYZaNfaKkOOzyuXn
|
||||
fa8bcG6qAQWmQX56aUYTiwPNtyovFvUancgDg4bP5hD4hEsl2NRSQZQggt663NWK
|
||||
ALQBbL6qeJDI+WlAf83TbDVV8wGPuwGKE79+ES+TnT0GhhanEJ2J2swm3IcEVuya
|
||||
pEay0NAfoEfuzgyYYerekeAvqHbvRIxFjR1Hh5QvkGjmmr376E4CkeyXaqjFSl6o
|
||||
XamS0gSVfvnT/jYm9SGVFafA38ZGx2iEOMtybwJM+frp5F6DqwRG/dKgJ0W4nW/N
|
||||
E2iB2JJhVR9iaR973d/4G5vL5WVFUGv3b6VyZZAPftSzPoqPqGEaKGaHprECPUDQ
|
||||
fR1wdLYUuQfqgVnj1sKWT8YWNNc+11idVU/hPF3Yu9dSPVaEdYIQiQ0NNqnhneO/
|
||||
IVsOz4xBbh++frq8H16k0xqkOJuC6mCZaU4YxWy8SZ7jukyCywIDAQABo2MwYTAP
|
||||
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQPP+eE
|
||||
//4Mg+qXZae4eIHDVbWkKjAdBgNVHQ4EFgQUDz/nhP/+DIPql2WnuHiBw1W1pCow
|
||||
DQYJKoZIhvcNAQELBQADggIBADxbNKDguPbfyhUOmrXcOPdzNWGvr51Cm0OZLOod
|
||||
nUcP9rkmEZYMZkmAGYCMkiK/HCd22iOXyHW+OYvq7zdLlaWuMfE6wxwWZ8bK3NQC
|
||||
3w0HPyAOcxknvGnHLnmi4+sKz+ZwVn816EgYv2iytVdfjclVK0Zvoa6COc0C085e
|
||||
kWe0hWFuqbVRzmtqoQauwxU9+rfY21/GtiZbkOiAo6VP9qqfrq3hDBoF/WT2gGVT
|
||||
GPuz6j+m2D2ai2s1rWLJfLfcSIySZ67tMmg3lL/8FrxLVmZ15XjuX8Y1M4XhjdV3
|
||||
G+9XSeuvyqWBrN1l99U3BvAVozqI0rEx7PqH8dpirwuYWRrJM7bZbuOvdVAT3wpE
|
||||
ypfXOkjVmTCkvJH2wrupywiVIu7vANJ6poV4zo+f6GJvM8iv2z8S3NmM7vt7NFFX
|
||||
1Q6HFmlAgAW5SRQ49ClKZAftW5fiOCwkpWsRY6REeKz/bF4anm0vVZpPutM1BYRx
|
||||
yw4xZihWcfxipzeX+HRuxYZIpuQaUnTKWl9QgCxKzUwNitSL/bp1uI/H+TgRR29w
|
||||
6ns+M9ZufO7oiuAPBAjw1TTQ8f4C+8qxJIxqKZxqk9TkmDK2+hLkbdBx1hcIBJHY
|
||||
ClfQLQOBEL1l3nZd2wnZRkdaVPKj235CB05PTeAlrmYHGmhAKhmBpV2eY0J8EFf5
|
||||
STAx
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
2lXPecP5/ilaLLUhs7SijqHzcKiNL80=
|
||||
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
|
||||
DFiJLuJwaQVArPexRziXnDrbb0bQkBe2
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -3,18 +3,18 @@ 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
|
||||
VQQLDA1JQk0gWiBSb290IENBFw0yNjA2MjIxMDQ3NDZaGA8yMzkxMDQwNTEwNDc0
|
||||
NlowFTATAgIBTRcNMjYwNzAxMTA0NzQ2WqAjMCEwHwYDVR0jBBgwFoAUIlsT6zAF
|
||||
eYbpsFsGeGMQDoofNl4wDQYJKoZIhvcNAQENBQADggIBACnVIJGdrqX0b2vUQ9Oc
|
||||
DTfN6KMlmt5mKD9c7c24OPOVo7y1lGEGcanGsZ8/0mZ7G5dIqWU0yxXnMD1U3cbm
|
||||
nKGHkor/gyvP6hdozFUWIc5EVebDJvnIfj4L0kEVFE+wUO3iqtNnbQjvBo90iq9W
|
||||
j+TTD+QQAMGKQyi3AwEL6nVrOZiUwjaJCdaV41zXxn7hiyfN89T4xM/f1TnRZ+xw
|
||||
5ELqGN77PBWaEWf3XyLIbxt/2xJL03zmV8cEHmdPG37i/p82mcYxqkwRlU6iCJeQ
|
||||
CQ39GNQd9avGm5+cUchAmdZf+tQLVcKsKqjZ7Cq0yihxKoYwOngeOZswF3NueGIP
|
||||
jXi3jnA8f0vr1uDilleYkIs5At9IAMq2oA8czKelcIIqQLiTaj03m6u0ehb4VWmA
|
||||
T9LWR6RtuBS0d2Lx8cYapzU0tnnU9mOemixljqLqnURmhfI2yRuh9f2FuzD2n5Pv
|
||||
H4WHpc2a2Uoz4ub+v93j1ZScDCb+xTmOJ6HfJ2V6A8FYIaD21X1n8n4yc+WeV4Ta
|
||||
aBqoWI3TihzwJGvc67Zjfdkt7KhUZ6heJZHRrPVKWbDIVL7NVFnx53ANkOZ18pWt
|
||||
IzJb2xWQlP3u9e1JX4yqVw75woZxQKE3v60F0UGofamRB375lGDYrsufD5Sz1XOl
|
||||
Cwl/78PBFBOkcvgVCubeR9cU
|
||||
-----END X509 CRL-----
|
||||
|
||||
@@ -12,7 +12,7 @@ from cryptography.x509.oid import NameOID
|
||||
ONE_DAY = datetime.timedelta(1, 0, 0)
|
||||
|
||||
|
||||
def createEcKeyPair(curve=ec.SECP521R1):
|
||||
def createEcKeyPair(curve=ec.SECP521R1()):
|
||||
return ec.generate_private_key(curve=curve, backend=default_backend())
|
||||
|
||||
|
||||
@@ -72,8 +72,8 @@ def createCert(
|
||||
pub_key=None,
|
||||
):
|
||||
sha = hashes.SHA256
|
||||
not_before = not_before or datetime.datetime.utcnow()
|
||||
not_after = not_after or datetime.datetime.utcnow() + datetime.timedelta(
|
||||
not_before = not_before or datetime.datetime.now(datetime.UTC)
|
||||
not_after = not_after or datetime.datetime.now(datetime.UTC) + datetime.timedelta(
|
||||
days=365 * 365
|
||||
)
|
||||
crl_dp = None
|
||||
@@ -216,7 +216,7 @@ def getPrivKey(path, create_priv_key):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
MOCKUP_CRL_DIST = ""
|
||||
MOCKUP_CRL_DIST = "http://"
|
||||
|
||||
# create root CA
|
||||
root_ca_subject = x509.Name(
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE+DCCAuCgAwIBAgIUBSLhuGTvxPbggG70ISL2R6DDGZcwDQYJKoZIhvcNAQEN
|
||||
MIIE/zCCAuegAwIBAgIURQZKxfTuf0H43V0uJcBaFGTxwfMwDQYJKoZIhvcNAQEN
|
||||
BQAwgcwxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
|
||||
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
|
||||
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
|
||||
azEVMBMGA1UEBwwMUG91Z2hrZWVwc2llMScwJQYDVQQLDB5JQk0gWiBIb3N0IEtl
|
||||
eSBTaWduaW5nIFNlcnZpY2UwIBcNMjQwMzIxMTQ1MjM5WhgPMjM4ODEyMjMxNDUy
|
||||
MzlaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp
|
||||
eSBTaWduaW5nIFNlcnZpY2UwIBcNMjYwNzAyMDg0NzQ4WhgPMjM5MTA0MDUwODQ3
|
||||
NDhaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp
|
||||
bmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrSW50ZXJuYXRpb25h
|
||||
bCBCdXNpbmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjERMA8GA1UECAwITmV3IFlv
|
||||
cmsxDzANBgNVBAcMBkFybW9uazEXMBUGA1UECwwOSUJNIFogSG9zdCBLZXkwgZsw
|
||||
EAYHKoZIzj0CAQYFK4EEACMDgYYABAHGO0MnpQa6Q2IxgqV7AGwd3OwBnYOJjYJF
|
||||
hzrwY+wQacmJjWeNyHahBCxu4bM8vDr70SF5vZFrWpcWpc9JTY5AagFCFDqIfSvL
|
||||
J6lKJuCog5RfMsWJpG2j/MnK7MxG+Ph0R+ItmLFbWFxCV5YOT43olhwYZr/pd9qH
|
||||
PAD96UEDM8JanKNsMGowGAYDVR0fBBEwDzANoAugCYYHaWJtLmNybDAOBgNVHQ8B
|
||||
Af8EBAMCAwgwHwYDVR0jBBgwFoAUw4weXbTWAZisD86gZSugZ6V1FNkwHQYDVR0O
|
||||
BBYEFL4m5UxVbUdEl9yg4sjiWKO/EAxyMA0GCSqGSIb3DQEBDQUAA4ICAQBwaPG5
|
||||
Mg3iKtxR6ncteH+YmtMHW4/wB/341pTKFsKBYsMNWuCC5AKbNrshCNbFbctqhLrB
|
||||
LmEpmza3/Pk6izO4AozHNl0tRec/HnQr2gonfI48HBDRiV2f40x0gJG9gGCiJy7o
|
||||
6iKZDYUnjfnhXVC67RwLMEiIKbeOAWQ9hHqegUjYdaaIlhyiHLMuWMceidvG76nN
|
||||
2eyJUNEouT4+UvquD2oqSitB3ZLhWRqPOQn57ME1b0QYF240PN8r21YtzPmSI+s/
|
||||
ej04EcQZrlJId6GtU7YwD1767hVw84v/QjPbMqnYQbxX8n3IvOf541rQ0UdjBFc9
|
||||
UhbnSn32IGFrRlL1y3MPBF6hLPcpW4P0QrUijc6gZ+x6SNFho8n+dk53F7RvMi1l
|
||||
SLgJl7x8pUeqBn5QKMcYYsZG39oZmQj4xHjAABx2hRWayDscvROiQpvLHRtLVmk7
|
||||
+hq4Q/jalc2cNHZSwLX6Tv5P+8waTnXg8YNEHeAAgcw1lD+uw5HgusjGD4USE7Hq
|
||||
Q6EDGzC+Ny3u2+35XWbNaKWVthtKAIcZ9B4LjdJXeQFGcOMr6yV5rKfOFQwXo8bS
|
||||
rNy57tiva8KM2weSfRil4f146Rsb3TJzUdlkaN+NVIY0YImiC+rR0qa6Iv6JCio1
|
||||
F2lu8m/aRHQQF5J5fD7ge6v7F2D6K3qT9tTlrw==
|
||||
EAYHKoZIzj0CAQYFK4EEACMDgYYABADmnrO8fwhFRmvTAeT91LiGJatTUNRhTr+S
|
||||
Pf9glpJGFemv1amiV89qBYij6IuYJDhSYAQNllegWfntvzDbCOhDvAH0SY9Ivhd7
|
||||
7nA20M0Z9FuUNaFBRAkUB8VhVPC+lMM7i/0QA3FCWQEP1V28oXSyIOO7SF77GAb8
|
||||
U8dobSvrGtb7dKNzMHEwHwYDVR0fBBgwFjAUoBKgEIYOaHR0cDovL2libS5jcmww
|
||||
DgYDVR0PAQH/BAQDAgMIMB8GA1UdIwQYMBaAFP4r9a6YMGLiFEhK51N4O3+mmIbt
|
||||
MB0GA1UdDgQWBBTLpumJYUrj5XZpdF8A3HUH8Iz3yjANBgkqhkiG9w0BAQ0FAAOC
|
||||
AgEAPoZhxpmjEf2mv+Gqwt0z0yG/J3/R2UVO5tHw5L/WWgr8zKWtdVPca9fIFFiT
|
||||
bRam+m59hDVZ1nIg0SGmxEfsdJmxfk2h3cI9IJDF3CfELKmfUaVISL1zykdSBzIG
|
||||
J4PO3WmUo3W/F41OzaRiSqY4I+8gOXwZmX4bTAFFNYQ9KI9JEJbY5ZM7oKd9Ts57
|
||||
lPDWgKf9luN3Teuw+8tj+3G3lzfZ8hO7RThNLi2qr8t0VPecps7ZwNLR+AXLs0F8
|
||||
Olx3IIhe7REHZnMqTaVJVlHPUi4REpoI7A3jT6S8AnNsEVjxsIbmJtwJEwwlVMU2
|
||||
E3e046RhNUqyHY5ahBPrgBUVadO0/b8QDW+vLAwbm5yr6E//h7Ygit8grA2l2LtS
|
||||
vuMEOnsLec1vTcDaeTtDpDJePP6naAc/ZXM+N1riebOYleKlsCylSAEZsoHT0unu
|
||||
jRCSTtr5YlWHIP7cQbn9YS8gmvMFU+M+0iNsKqs85o3hbcqchRm8DcLGiDD+FC4k
|
||||
2soTE2K3OaVsfYvfxUcA8vvGOeO13gZplpdL0iw+r1aMm7jhiljf6buF8ZwvsAVC
|
||||
o1N7uHuOr7Z3hONSbw4GWHFkWy82SIlbM3xNL3geDl7TX3VZFR4OTeIXSskuVOSg
|
||||
tLwBY1/RM2ZkDnraxi0XDfNJZRiFK4WVZz/tJSGgrF0YT4M=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIA8rPNC6rxZR+GxSxb
|
||||
qWRreFGnWRQGd22nHWKAvQmrA5GlXTtWQMoL8il9Jb1OnrQPPo620nQpzA1GXo4U
|
||||
BUqgYoShgYkDgYYABAHGO0MnpQa6Q2IxgqV7AGwd3OwBnYOJjYJFhzrwY+wQacmJ
|
||||
jWeNyHahBCxu4bM8vDr70SF5vZFrWpcWpc9JTY5AagFCFDqIfSvLJ6lKJuCog5Rf
|
||||
MsWJpG2j/MnK7MxG+Ph0R+ItmLFbWFxCV5YOT43olhwYZr/pd9qHPAD96UEDM8Ja
|
||||
nA==
|
||||
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIA0FE54XL97lOXcJa0
|
||||
hM+jtHL3zaUQ1up5GOlzcU/4YJ1zGvyXuhOPoC0+tO+Tm6FyVpr5kuYvnix+ixRP
|
||||
Kbq0q6ihgYkDgYYABADmnrO8fwhFRmvTAeT91LiGJatTUNRhTr+SPf9glpJGFemv
|
||||
1amiV89qBYij6IuYJDhSYAQNllegWfntvzDbCOhDvAH0SY9Ivhd77nA20M0Z9FuU
|
||||
NaFBRAkUB8VhVPC+lMM7i/0QA3FCWQEP1V28oXSyIOO7SF77GAb8U8dobSvrGtb7
|
||||
dA==
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE+DCCAuCgAwIBAgIUC3KzCH9KUb8ZaY6J/97gqebLoIYwDQYJKoZIhvcNAQEN
|
||||
MIIE/zCCAuegAwIBAgIUZ2LzT6AgSHsm2Y0wV0byf4dkroswDQYJKoZIhvcNAQEN
|
||||
BQAwgcwxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu
|
||||
ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs
|
||||
IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y
|
||||
azEVMBMGA1UEBwwMUG91Z2hrZWVwc2llMScwJQYDVQQLDB5JQk0gWiBIb3N0IEtl
|
||||
eSBTaWduaW5nIFNlcnZpY2UwIBcNMjQwMzIxMTQ1MjM5WhgPMjM4ODEyMjMxNDUy
|
||||
MzlaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp
|
||||
eSBTaWduaW5nIFNlcnZpY2UwIBcNMjYwNzAyMDg0NzQ4WhgPMjM5MTA0MDUwODQ3
|
||||
NDhaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp
|
||||
bmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrSW50ZXJuYXRpb25h
|
||||
bCBCdXNpbmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjERMA8GA1UECAwITmV3IFlv
|
||||
cmsxDzANBgNVBAcMBkFybW9uazEXMBUGA1UECwwOSUJNIFogSG9zdCBLZXkwgZsw
|
||||
EAYHKoZIzj0CAQYFK4EEACMDgYYABAE3KDrdCdVeBV34NicA8AoP7hItcwxgXHOQ
|
||||
F+V02N6b5AR7w3YDHE/JSzSoZZIYiqdy8SmeD5GtwHLV8tLQ8xnadgHT0BesGS02
|
||||
w0H5foGzzZOHZW3AfbdH4MpssR4Bf1jqL0jw6eV+oiMStDuZ44zri7PFjvVByt6M
|
||||
oeSvh5qAXCQG/6NsMGowGAYDVR0fBBEwDzANoAugCYYHaWJtLmNybDAOBgNVHQ8B
|
||||
Af8EBAMCAwgwHwYDVR0jBBgwFoAUw4weXbTWAZisD86gZSugZ6V1FNkwHQYDVR0O
|
||||
BBYEFL8FyjCu1iRcjwx4pzfo+VIQ5NdbMA0GCSqGSIb3DQEBDQUAA4ICAQASxSXu
|
||||
RxNw/kSwqedNq9jOTHb5FATNykBIVSuXS9BB2qkjcTVDXNnlsSBrPL/CumRp/TFD
|
||||
5VsB2rLhESmUrpghQrODeFvyFE52yVhxvcNCyjz7yIQZvc4qofMQMsg3o0rSqp2s
|
||||
lu1PUbcrL2aCG1yxB3isObVqiWaiRdnPxL8aX3Qt6BszlwWUgaFoaH0uZxlgVGKV
|
||||
C+dXrn5WkNRVd2ouHSLQE6fIUYIf/TrV+AKu804IEoFRIvMUCqQRUHsj5toKhfDb
|
||||
6tl/Xd+EiPCYbnhR2J01I08yxMExvYXfXapY7JJjlWTHKFKaxLoqv++NZRM1bW6s
|
||||
uyLWP735Qb+0AmhZ6TfeJM7H77LpQK0WCylaNVJWWjXt9UsnNdirCbp/jpKF8bnG
|
||||
2PkjBHKruvCakqw1bDq8eDv9In1Ki+Um4gp7OfjYvcN8zxvGQofgj++UaCy982iX
|
||||
WSq14iUyrRDVu8zWghL/F1lUx7ab8UV+OrmZuCALVHZ76YVdwmJXGYll1OBbJbgL
|
||||
5xze6p77vKzbgNyABWmR6TlHq/nFDhj9kKirpQaI7WHyOtsGpc7sqd0tT+CeOhNf
|
||||
l3xXyFPb6N58aSC2cY0W0Nq6X/mWIgMqHY9lzYLmoLBFFZlIjqWzwyVcajmjrtaK
|
||||
rlfs0e9f9DvVV8bMTXFMUBlWrmYDrROKpYLqhg==
|
||||
EAYHKoZIzj0CAQYFK4EEACMDgYYABAE69tLPv1D4DIFTgQo+P57ZABDoxe6x5Rjy
|
||||
+NYiRi/Nfir11CxVGQDaYDfUFsb4peQJz6haxqXfXmm4MWlIbdWa1gHMf3GQl/xt
|
||||
IGGbJURxnBIR3rj2pqd0DqbONj8blnQTCWLSHsLsgyI6WWK4RHd9ZtER0UQDxoQc
|
||||
c8Htsuh1+SKo6qNzMHEwHwYDVR0fBBgwFjAUoBKgEIYOaHR0cDovL2libS5jcmww
|
||||
DgYDVR0PAQH/BAQDAgMIMB8GA1UdIwQYMBaAFP4r9a6YMGLiFEhK51N4O3+mmIbt
|
||||
MB0GA1UdDgQWBBTjTQZrKFQ5geqc4+9zl31SO5w4DTANBgkqhkiG9w0BAQ0FAAOC
|
||||
AgEAFvvK0+jphYgn93vZDB06EG7wH4EsEe6dDmG8E2N+SCbjWigTYElemKOl5ION
|
||||
i3G1Wluc2SEN2gHX4MRnHQNE7bxUAX8IhbKNW0+xcQX3BOT/mPbWsrrHkvkBTzO0
|
||||
wQPIUVtGjRe1igL4b/Pv29fWsphOjHm1ZyqIr9V5Qk0hhOWsQ8i4zspTks0OGSml
|
||||
OPIY4iB/DyvUWcwsI5ZhdyK1l0ZKKS8zxWWKT4BgRtR4WGFUArkb+7fWYpIl91CE
|
||||
xE+TVTIhjuTyajZG1/wPtzI3TrQPjB5LKv5OvqroLMamuMeQG+CydFEOUb7z05Zk
|
||||
f4PU6ryvB2hPAwnzqKtf+TNWimiuqPM06pEZRSpUKcoXzJiNIweICkoOllQDrx4m
|
||||
g5pvjVT23FeDuEQWLiB9XMFmx46Thv1AGkP+gKbaLIjkxrfWEomEoY6/6VDeFjFl
|
||||
FxEYSvnazQ5K5tBQ2rA46OvpdpbIifI+x1aaP45snKQ/wvoeRfXySV9B5S/ESzrM
|
||||
xVgAY++/lteSzvUJaC+ZVKkvjIIznxNHnHG8GrFKPFZqoUS10zGKiYve9yXQITK2
|
||||
n32heLzy+SM4Qcso43f+3n0R0KrdjOn3peXakfNEFaGkJQvMdeYQpZkALDHXpbGi
|
||||
TA4C4qSTGP89TrEpGWpuAKuMHP5Vqf7y/EDr8Y4xP1TPRFo=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user