diff --git a/CHANGES b/CHANGES index 164787c4..a5d6950a 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,17 @@ Changes between 1.1.1 and 3.0.0 [xx XXX xxxx] + *) Added command 'openssl kdf' that uses the EVP_KDF API. + [Shane Lontis] + + *) Added command 'openssl mac' that uses the EVP_MAC API. + [Shane Lontis] + + *) Added OPENSSL_info() to get diverse built-in OpenSSL data, such + as default directories. Also added the command 'openssl info' + for scripting purposes. + [Richard Levitte] + *) The functions AES_ige_encrypt() and AES_bi_ige_encrypt() have been deprecated. These undocumented functions were never integrated into the EVP layer and implement the AES Infinite Garble Extension (IGE) mode and AES diff --git a/Configurations/shared-info.pl b/Configurations/shared-info.pl index f821ad7e..83f28bd3 100644 --- a/Configurations/shared-info.pl +++ b/Configurations/shared-info.pl @@ -32,7 +32,10 @@ my %shared_info; return { %{$shared_info{'gnu-shared'}}, shared_defflag => '-Wl,--version-script=', - dso_ldflags => '-z defs', + dso_ldflags => + $disabled{asan} && $disabled{msan} && $disabled{ubsan} + ? '-z defs' + : '', }; }, 'bsd-gcc-shared' => sub { return $shared_info{'linux-shared'}; }, diff --git a/Configure b/Configure index 3b7ca360..8b6d2379 100755 --- a/Configure +++ b/Configure @@ -892,9 +892,6 @@ while (@argvcopy) elsif (/^-static$/) { push @{$useradd{LDFLAGS}}, $_; - $disabled{"pic"} = "forced"; - $disabled{"shared"} = "forced"; - $disabled{"threads"} = "forced"; } elsif (/^-D(.*)$/) { @@ -1006,20 +1003,30 @@ if (grep { /-rpath\b/ } ($user{LDFLAGS} ? @{$user{LDFLAGS}} : ()) "***** any of asan, msan or ubsan\n"; } -my @tocheckfor = (keys %disabled); -while (@tocheckfor) { - my %new_tocheckfor = (); - my @cascade_copy = (@disable_cascades); - while (@cascade_copy) { - my ($test, $descendents) = (shift @cascade_copy, shift @cascade_copy); - if (ref($test) eq "CODE" ? $test->() : defined($disabled{$test})) { - foreach(grep { !defined($disabled{$_}) } @$descendents) { - $new_tocheckfor{$_} = 1; $disabled{$_} = "forced"; +sub disable { + my $disable_type = shift; + + for (@_) { + $disabled{$_} = $disable_type; + } + + my @tocheckfor = (@_ ? @_ : keys %disabled); + while (@tocheckfor) { + my %new_tocheckfor = (); + my @cascade_copy = (@disable_cascades); + while (@cascade_copy) { + my ($test, $descendents) = + (shift @cascade_copy, shift @cascade_copy); + if (ref($test) eq "CODE" ? $test->() : defined($disabled{$test})) { + foreach (grep { !defined($disabled{$_}) } @$descendents) { + $new_tocheckfor{$_} = 1; $disabled{$_} = "cascade"; + } } } + @tocheckfor = (keys %new_tocheckfor); } - @tocheckfor = (keys %new_tocheckfor); } +disable(); # First cascade run our $die = sub { die @_; }; if ($target eq "TABLE") { @@ -1144,6 +1151,8 @@ $target{module_ldflags} = $target{shared_ldflag} unless defined $target{module_l my %conf_files = map { $_ => 1 } (@{$target{_conf_fname_int}}); $config{conf_files} = [ sort keys %conf_files ]; +# Using sub disable within these loops may prove fragile, so we run +# a cascade afterwards foreach my $feature (@{$target{disable}}) { if (exists $deprecated_disablables{$feature}) { warn "***** config $target disables deprecated feature $feature\n"; @@ -1162,6 +1171,7 @@ foreach my $feature (@{$target{enable}}) { delete $disabled{$feature}; } } +disable(); # Run a cascade now $target{CXXFLAGS}//=$target{CFLAGS} if $target{CXX}; $target{cxxflags}//=$target{cflags} if $target{CXX}; @@ -1202,6 +1212,22 @@ foreach (keys %user) { delete $config{$_} unless defined $config{$_}; } +# Finish up %config by appending things the user gave us on the command line +# apart from "make variables" +foreach (keys %useradd) { + # The must all be lists, so we assert that here + die "internal error: \$useradd{$_} isn't an ARRAY\n" + unless ref $useradd{$_} eq 'ARRAY'; + + if (defined $config{$_}) { + push @{$config{$_}}, @{$useradd{$_}}; + } else { + $config{$_} = [ @{$useradd{$_}} ]; + } +} +# At this point, we can forget everything about %user and %useradd, +# because it's now all been merged into the corresponding $config entry + # Allow overriding the build file name $config{build_file} = env('BUILDFILE') || $target{build_file} || "Makefile"; @@ -1281,8 +1307,7 @@ if ($target =~ /^mingw/ && `$config{CC} --target-help 2>&1` =~ m/-mno-cygwin/m) } if ($target =~ /linux.*-mips/ && !$disabled{asm} - && !grep { $_ !~ /-m(ips|arch=)/ } (@{$user{CFLAGS}}, - @{$useradd{CFLAGS}})) { + && !grep { $_ !~ /-m(ips|arch=)/ } (@{$config{CFLAGS}})) { # minimally required architecture flags for assembly modules my $value; $value = '-mips2' if ($target =~ /mips32/); @@ -1296,7 +1321,7 @@ unless ($disabled{threads}) { if ($auto_threads) { # Enabled by default, disable it forcibly if unavailable if ($target{thread_scheme} eq "(unknown)") { - $disabled{threads} = "unavailable"; + disable("unavailable", 'threads'); } } else { # The user chose to enable threads explicitly, let's see @@ -1307,8 +1332,7 @@ unless ($disabled{threads}) { # system-dependent compiler options that are necessary. We # can't truly check that the given options are correct, but # we expect the user to know what [s]He is doing. - if (!@{$user{CFLAGS}} && !@{$useradd{CFLAGS}} - && !@{$user{CPPDEFINES}} && !@{$useradd{CPPDEFINES}}) { + if (!@{$config{CFLAGS}} && !@{$config{CPPDEFINES}}) { die "You asked for multi-threading support, but didn't\n" ,"provide any system-specific compiler options\n"; } @@ -1316,6 +1340,27 @@ unless ($disabled{threads}) { } } +# Find out if clang's sanitizers have been enabled with -fsanitize +# flags and ensure that the corresponding %disabled elements area +# removed to reflect that the sanitizers are indeed enabled. +my %detected_sanitizers = (); +foreach (grep /^-fsanitize=/, @{$config{CFLAGS} || []}) { + (my $checks = $_) =~ s/^-fsanitize=//; + foreach (split /,/, $checks) { + my $d = { address => 'asan', + undefined => 'ubsan', + memory => 'msan' } -> {$_}; + next unless defined $d; + + $detected_sanitizers{$d} = 1; + if (defined $disabled{$d}) { + die "***** Conflict between disabling $d and enabling $_ sanitizer" + if $disabled{$d} ne "default"; + delete $disabled{$d}; + } + } +} + # If threads still aren't disabled, add a C macro to ensure the source # code knows about it. Any other flag is taken care of by the configs. unless($disabled{threads}) { @@ -1332,8 +1377,7 @@ if ($target{shared_target} eq "") { $no_shared_warn = 1 if (!$disabled{shared} || !$disabled{"dynamic-engine"}); - $disabled{pic} = $disabled{shared} = $disabled{"dynamic-engine"} = - $disabled{module} = "no-shared-target"; + disable('no-shared-target', 'pic'); } if ($disabled{"dynamic-engine"}) { @@ -1344,12 +1388,12 @@ if ($disabled{"dynamic-engine"}) { $config{dynamic_engines} = 1; } -unless ($disabled{asan}) { +unless ($disabled{asan} || defined $detected_sanitizers{asan}) { push @{$config{cflags}}, "-fsanitize=address"; push @{$config{cxxflags}}, "-fsanitize=address" if $config{CXX}; } -unless ($disabled{ubsan}) { +unless ($disabled{ubsan} || defined $detected_sanitizers{ubsan}) { # -DPEDANTIC or -fnosanitize=alignment may also be required on some # platforms. push @{$config{cflags}}, "-fsanitize=undefined", "-fno-sanitize-recover=all"; @@ -1357,7 +1401,7 @@ unless ($disabled{ubsan}) { if $config{CXX}; } -unless ($disabled{msan}) { +unless ($disabled{msan} || defined $detected_sanitizers{msan}) { push @{$config{cflags}}, "-fsanitize=memory"; push @{$config{cxxflags}}, "-fsanitize=memory" if $config{CXX}; } @@ -1482,7 +1526,7 @@ if (!$disabled{makedepend}) { # In all other cases, we look for 'makedepend', and disable the # capability if not found. $config{makedepprog} = which('makedepend'); - $disabled{makedepend} = "unavailable" unless $config{makedepprog}; + disable('unavailable', 'makedepend') unless $config{makedepprog}; } } @@ -1569,12 +1613,17 @@ if ($strict_warnings) @{$clang_devteam_warn{CXXFLAGS}} if (defined($predefined_CXX{__clang__})); } + +if (grep { $_ eq '-static' } @{$config{LDFLAGS}}) { + disable('static', 'pic', 'threads'); +} + foreach my $idx (qw(CFLAGS CXXFLAGS)) { - $useradd{$idx} = [ map { $_ eq '--ossl-strict-warnings' - ? @{$strict_warnings_collection{$idx}} - : ( $_ ) } - @{$useradd{$idx}} ]; + $config{$idx} = [ map { $_ eq '--ossl-strict-warnings' + ? @{$strict_warnings_collection{$idx}} + : ( $_ ) } + @{$config{$idx}} ]; } unless ($disabled{"crypto-mdebug-backtrace"}) @@ -1603,15 +1652,15 @@ unless ($disabled{afalgeng}) { ($mi2) = $mi2 =~ /(\d+)/; my $ver = $ma*10000 + $mi1*100 + $mi2; if ($ver < $minver) { - $disabled{afalgeng} = "too-old-kernel"; + disable('too-old-kernel', 'afalgeng'); } else { push @{$config{engdirs}}, "afalg"; } } else { - $disabled{afalgeng} = "cross-compiling"; + disable('cross-compiling', 'afalgeng'); } } else { - $disabled{afalgeng} = "not-linux"; + disable('not-linux', 'afalgeng'); } } @@ -1629,29 +1678,15 @@ unless ($disabled{ktls}) { my @verstr = split(" ",`cat $usr/include/linux/version.h | grep LINUX_VERSION_CODE`); if ($verstr[2] < $minver) { - $disabled{ktls} = "too-old-kernel"; + disable('too-old-kernel', 'ktls'); } } else { - $disabled{ktls} = "not-linux"; + disable('not-linux', 'ktls'); } } push @{$config{openssl_other_defines}}, "OPENSSL_NO_KTLS" if ($disabled{ktls}); -# Finish up %config by appending things the user gave us on the command line -# apart from "make variables" -foreach (keys %useradd) { - # The must all be lists, so we assert that here - die "internal error: \$useradd{$_} isn't an ARRAY\n" - unless ref $useradd{$_} eq 'ARRAY'; - - if (defined $config{$_}) { - push @{$config{$_}}, @{$useradd{$_}}; - } else { - $config{$_} = [ @{$useradd{$_}} ]; - } -} - # ALL MODIFICATIONS TO %config and %target MUST BE DONE FROM HERE ON # If we use the unified build, collect information from build.info files diff --git a/NEWS b/NEWS index 3c38c782..6c79bc24 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,9 @@ Major changes between OpenSSL 1.1.1 and OpenSSL 3.0.0 [under development] + o Added 'openssl mac' that uses the EVP_MAC API. + o Added 'openssl kdf' that uses the EVP_KDF API. + o Add OPENSSL_info() and 'openssl info' to get built-in data. o Add support for enabling instrumentation through trace and debug output. o Changed our version number scheme and set the next major release to @@ -14,6 +17,8 @@ o Added EVP_MAC, an EVP layer MAC API, and a generic EVP_PKEY to EVP_MAC bridge. o Removed the heartbeat message in DTLS feature. + o Added EVP_KDF, an EVP layer KDF API, and a generic EVP_PKEY to EVP_KDF + bridge. Major changes between OpenSSL 1.1.1 and OpenSSL 1.1.1a [20 Nov 2018] diff --git a/apps/asn1pars.c b/apps/asn1pars.c index 4c1ce485..14f1dcad 100644 --- a/apps/asn1pars.c +++ b/apps/asn1pars.c @@ -170,17 +170,17 @@ int asn1parse_main(int argc, char **argv) if (derfile && (derout = bio_open_default(derfile, 'w', FORMAT_ASN1)) == NULL) goto end; + if ((buf = BUF_MEM_new()) == NULL) + goto end; if (strictpem) { - if (PEM_read_bio(in, &name, &header, &str, &num) != - 1) { + if (PEM_read_bio(in, &name, &header, &str, &num) != 1) { BIO_printf(bio_err, "Error reading PEM file\n"); ERR_print_errors(bio_err); goto end; } + buf->data = (char *)str; + buf->length = buf->max = num; } else { - - if ((buf = BUF_MEM_new()) == NULL) - goto end; if (!BUF_MEM_grow(buf, BUFSIZ * 8)) goto end; /* Pre-allocate :-) */ @@ -303,8 +303,6 @@ int asn1parse_main(int argc, char **argv) BUF_MEM_free(buf); OPENSSL_free(name); OPENSSL_free(header); - if (strictpem) - OPENSSL_free(str); ASN1_TYPE_free(at); sk_OPENSSL_STRING_free(osk); return ret; diff --git a/apps/build.info b/apps/build.info index ad14038a..cbb70fc7 100644 --- a/apps/build.info +++ b/apps/build.info @@ -2,10 +2,11 @@ qw(openssl.c asn1pars.c ca.c ciphers.c cms.c crl.c crl2p7.c dgst.c dhparam.c dsa.c dsaparam.c ec.c ecparam.c enc.c engine.c errstr.c gendsa.c - genpkey.c genrsa.c mac.c nseq.c ocsp.c passwd.c pkcs12.c pkcs7.c + genpkey.c genrsa.c kdf.c mac.c nseq.c ocsp.c passwd.c pkcs12.c pkcs7.c pkcs8.c pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c rsa.c rsautl.c s_client.c s_server.c s_time.c sess_id.c smime.c speed.c - spkac.c srp.c ts.c verify.c version.c x509.c rehash.c storeutl.c); + spkac.c srp.c ts.c verify.c version.c x509.c rehash.c storeutl.c + info.c); our @apps_lib_src = ( qw(apps.c apps_ui.c opt.c fmt.c s_cb.c s_socket.c app_rand.c bf_prefix.c), diff --git a/apps/info.c b/apps/info.c new file mode 100644 index 00000000..aa019ad1 --- /dev/null +++ b/apps/info.c @@ -0,0 +1,97 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include "apps.h" +#include "progs.h" + +typedef enum OPTION_choice { + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_CONFIGDIR, OPT_ENGINESDIR, OPT_MODULESDIR, OPT_DSOEXT, OPT_DIRNAMESEP, + OPT_LISTSEP +} OPTION_CHOICE; + +const OPTIONS info_options[] = { + {"help", OPT_HELP, '-', "Display this summary"}, + {"configdir", OPT_CONFIGDIR, '-', "Default configuration file directory"}, + {"c", OPT_CONFIGDIR, '-', "Default configuration file directory"}, + {"enginesdir", OPT_ENGINESDIR, '-', "Default engine module directory"}, + {"e", OPT_ENGINESDIR, '-', "Default engine module directory"}, + {"modulesdir", OPT_ENGINESDIR, '-', + "Default module directory (other than engine modules)"}, + {"m", OPT_ENGINESDIR, '-', + "Default module directory (other than engine modules)"}, + {"dsoext", OPT_DSOEXT, '-', "Configured extension for modules"}, + {"dirnamesep", OPT_DIRNAMESEP, '-', "Directory-filename separator"}, + {"listsep", OPT_LISTSEP, '-', "List separator character"}, + {NULL} +}; + +int info_main(int argc, char **argv) +{ + int ret = 1, dirty = 0, type = 0; + char *prog; + OPTION_CHOICE o; + + prog = opt_init(argc, argv, info_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: + case OPT_ERR: +opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto end; + case OPT_HELP: + opt_help(info_options); + ret = 0; + goto end; + case OPT_CONFIGDIR: + type = OPENSSL_INFO_CONFIG_DIR; + dirty++; + break; + case OPT_ENGINESDIR: + type = OPENSSL_INFO_ENGINES_DIR; + dirty++; + break; + case OPT_MODULESDIR: + type = OPENSSL_INFO_MODULES_DIR; + dirty++; + break; + case OPT_DSOEXT: + type = OPENSSL_INFO_DSO_EXTENSION; + dirty++; + break; + case OPT_DIRNAMESEP: + type = OPENSSL_INFO_DIR_FILENAME_SEPARATOR; + dirty++; + break; + case OPT_LISTSEP: + type = OPENSSL_INFO_LIST_SEPARATOR; + dirty++; + break; + } + } + if (opt_num_rest() != 0) { + BIO_printf(bio_err, "%s: Extra parameters given.\n", prog); + goto opthelp; + } + if (dirty > 1) { + BIO_printf(bio_err, "%s: Only one item allowed\n", prog); + goto opthelp; + } + if (dirty == 0) { + BIO_printf(bio_err, "%s: No items chosen\n", prog); + goto opthelp; + } + + BIO_printf(bio_out, "%s\n", OPENSSL_info(type)); + ret = 0; + end: + return ret; +} diff --git a/apps/kdf.c b/apps/kdf.c new file mode 100644 index 00000000..684fd44c --- /dev/null +++ b/apps/kdf.c @@ -0,0 +1,158 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include + +#include "apps.h" +#include "progs.h" +#include +#include +#include +#include + +typedef enum OPTION_choice { + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_KDFOPT, OPT_BIN, OPT_KEYLEN, OPT_OUT +} OPTION_CHOICE; + +const OPTIONS kdf_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: %s [options] kdf_name\n"}, + {OPT_HELP_STR, 1, '-', "kdf_name\t KDF algorithm.\n"}, + {"help", OPT_HELP, '-', "Display this summary"}, + {"kdfopt", OPT_KDFOPT, 's', "KDF algorithm control parameters in n:v form. " + "See 'Supported Controls' in the EVP_KDF_ docs"}, + {"keylen", OPT_KEYLEN, 's', "The size of the output derived key"}, + {"out", OPT_OUT, '>', "Output to filename rather than stdout"}, + {"binary", OPT_BIN, '-', "Output in binary format (Default is hexadecimal " + "output)"}, + {NULL} +}; + +static int kdf_ctrl_string(EVP_KDF_CTX *ctx, const char *value) +{ + int rv; + char *stmp, *vtmp = NULL; + + stmp = OPENSSL_strdup(value); + if (stmp == NULL) + return -1; + vtmp = strchr(stmp, ':'); + if (vtmp != NULL) { + *vtmp = 0; + vtmp++; + } + rv = EVP_KDF_ctrl_str(ctx, stmp, vtmp); + OPENSSL_free(stmp); + return rv; +} + +int kdf_main(int argc, char **argv) +{ + int ret = 1, i, id, out_bin = 0; + OPTION_CHOICE o; + STACK_OF(OPENSSL_STRING) *opts = NULL; + char *prog, *hexout = NULL; + const char *outfile = NULL; + unsigned char *dkm_bytes = NULL; + size_t dkm_len = 0; + BIO *out = NULL; + EVP_KDF_CTX *ctx = NULL; + + prog = opt_init(argc, argv, kdf_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + default: +opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto err; + case OPT_HELP: + opt_help(kdf_options); + ret = 0; + goto err; + case OPT_BIN: + out_bin = 1; + break; + case OPT_KEYLEN: + dkm_len = (size_t)atoi(opt_arg()); + break; + case OPT_OUT: + outfile = opt_arg(); + break; + case OPT_KDFOPT: + if (opts == NULL) + opts = sk_OPENSSL_STRING_new_null(); + if (opts == NULL || !sk_OPENSSL_STRING_push(opts, opt_arg())) + goto opthelp; + break; + } + } + argc = opt_num_rest(); + argv = opt_rest(); + + if (argc != 1) { + BIO_printf(bio_err, "Invalid number of extra arguments\n"); + goto opthelp; + } + + id = OBJ_sn2nid(argv[0]); + if (id == NID_undef) { + BIO_printf(bio_err, "Invalid KDF name %s\n", argv[0]); + goto opthelp; + } + + ctx = EVP_KDF_CTX_new_id(id); + if (ctx == NULL) + goto err; + + if (opts != NULL) { + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (kdf_ctrl_string(ctx, opt) <= 0) { + BIO_printf(bio_err, "KDF parameter error '%s'\n", opt); + ERR_print_errors(bio_err); + goto err; + } + } + } + + out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT); + if (out == NULL) + goto err; + + if (dkm_len <= 0) { + BIO_printf(bio_err, "Invalid derived key length.\n"); + goto err; + } + dkm_bytes = app_malloc(dkm_len, "out buffer"); + if (dkm_bytes == NULL) + goto err; + + if (!EVP_KDF_derive(ctx, dkm_bytes, dkm_len)) { + BIO_printf(bio_err, "EVP_KDF_derive failed\n"); + goto err; + } + + if (out_bin) { + BIO_write(out, dkm_bytes, dkm_len); + } else { + hexout = OPENSSL_buf2hexstr(dkm_bytes, dkm_len); + BIO_printf(out, "%s\n\n", hexout); + } + + ret = 0; +err: + if (ret != 0) + ERR_print_errors(bio_err); + OPENSSL_clear_free(dkm_bytes, dkm_len); + sk_OPENSSL_STRING_free(opts); + EVP_KDF_CTX_free(ctx); + BIO_free(out); + OPENSSL_free(hexout); + return ret; +} diff --git a/apps/progs.pl b/apps/progs.pl index ab1a729f..3aec7562 100644 --- a/apps/progs.pl +++ b/apps/progs.pl @@ -51,6 +51,9 @@ print <<"EOF"; * https://www.openssl.org/source/license.html */ +#include +#include "opt.h" + typedef enum FUNC_TYPE { FT_none, FT_general, FT_md, FT_cipher, FT_pkey, FT_md_alg, FT_cipher_alg diff --git a/apps/version.c b/apps/version.c index f9d280c7..279aeff2 100644 --- a/apps/version.c +++ b/apps/version.c @@ -33,7 +33,7 @@ typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_B, OPT_D, OPT_E, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R + OPT_B, OPT_D, OPT_E, OPT_M, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R } OPTION_CHOICE; const OPTIONS version_options[] = { @@ -42,6 +42,7 @@ const OPTIONS version_options[] = { {"b", OPT_B, '-', "Show build date"}, {"d", OPT_D, '-', "Show configuration directory"}, {"e", OPT_E, '-', "Show engines directory"}, + {"m", OPT_M, '-', "Show modules directory"}, {"f", OPT_F, '-', "Show compiler flags used"}, {"o", OPT_O, '-', "Show some internal datatype options"}, {"p", OPT_P, '-', "Show target build platform"}, @@ -64,7 +65,7 @@ int version_main(int argc, char **argv) { int ret = 1, dirty = 0, seed = 0; int cflags = 0, version = 0, date = 0, options = 0, platform = 0, dir = 0; - int engdir = 0; + int engdir = 0, moddir = 0; char *prog; OPTION_CHOICE o; @@ -89,6 +90,9 @@ opthelp: case OPT_E: dirty = engdir = 1; break; + case OPT_M: + dirty = moddir = 1; + break; case OPT_F: dirty = cflags = 1; break; @@ -105,7 +109,8 @@ opthelp: dirty = version = 1; break; case OPT_A: - seed = options = cflags = version = date = platform = dir = engdir + seed = options = cflags = version = date = platform + = dir = engdir = moddir = 1; break; } @@ -155,6 +160,8 @@ opthelp: printf("%s\n", OpenSSL_version(OPENSSL_DIR)); if (engdir) printf("%s\n", OpenSSL_version(OPENSSL_ENGINES_DIR)); + if (moddir) + printf("%s\n", OpenSSL_version(OPENSSL_MODULES_DIR)); if (seed) { printf("Seeding source:"); #ifdef OPENSSL_RAND_SEED_RTDSC diff --git a/build.info b/build.info index a0ecb218..ce5dfd05 100644 --- a/build.info +++ b/build.info @@ -3,7 +3,7 @@ SUBDIRS=crypto ssl apps test util tools fuzz engines providers LIBS=libcrypto libssl -INCLUDE[libcrypto]=. crypto/include include +INCLUDE[libcrypto]=. crypto/include include providers/common/include INCLUDE[libssl]=. include DEPEND[libssl]=libcrypto diff --git a/crypto/aes/asm/aesv8-armx.pl b/crypto/aes/asm/aesv8-armx.pl index 81bc1cbf..3b3a53bf 100755 --- a/crypto/aes/asm/aesv8-armx.pl +++ b/crypto/aes/asm/aesv8-armx.pl @@ -27,18 +27,34 @@ # CBC encrypt case. On Cortex-A57 parallelizable mode performance # seems to be limited by sheer amount of NEON instructions... # +# April 2019 +# +# Key to performance of parallelize-able modes is round instruction +# interleaving. But which factor to use? There is optimal one for +# each combination of instruction latency and issue rate, beyond +# which increasing interleave factor doesn't pay off. While on cons +# side we have code size increase and resource waste on platforms for +# which interleave factor is too high. In other words you want it to +# be just right. So far interleave factor of 3x was serving well all +# platforms. But for ThunderX2 optimal interleave factor was measured +# to be 5x... +# # Performance in cycles per byte processed with 128-bit key: # # CBC enc CBC dec CTR # Apple A7 2.39 1.20 1.20 -# Cortex-A53 1.32 1.29 1.46 -# Cortex-A57(*) 1.95 0.85 0.93 -# Denver 1.96 0.86 0.80 -# Mongoose 1.33 1.20 1.20 -# Kryo 1.26 0.94 1.00 +# Cortex-A53 1.32 1.17/1.29(**) 1.36/1.46 +# Cortex-A57(*) 1.95 0.82/0.85 0.89/0.93 +# Cortex-A72 1.33 0.85/0.88 0.92/0.96 +# Denver 1.96 0.65/0.86 0.76/0.80 +# Mongoose 1.33 1.23/1.20 1.30/1.20 +# Kryo 1.26 0.87/0.94 1.00/1.00 +# ThunderX2 5.95 1.25 1.30 # # (*) original 3.64/1.34/1.32 results were for r0p0 revision # and are still same even for updated module; +# (**) numbers after slash are for 32-bit code, which is 3x- +# interleaved; $flavour = shift; $output = shift; @@ -523,6 +539,13 @@ $code.=<<___; ___ { my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9)); + +my ($dat3,$in3,$tmp3); # used only in 64-bit mode +my ($dat4,$in4,$tmp4); +if ($flavour =~ /64/) { + ($dat2,$dat3,$dat4,$in2,$in3,$in4,$tmp3,$tmp4)=map("q$_",(16..23)); +} + $code.=<<___; .align 5 .Lcbc_dec: @@ -539,7 +562,196 @@ $code.=<<___; vorr $in0,$dat,$dat vorr $in1,$dat1,$dat1 vorr $in2,$dat2,$dat2 +___ +$code.=<<___ if ($flavour =~ /64/); + cmp $len,#32 + b.lo .Loop3x_cbc_dec + vld1.8 {$dat3},[$inp],#16 + vld1.8 {$dat4},[$inp],#16 + sub $len,$len,#32 // bias + mov $cnt,$rounds + vorr $in3,$dat3,$dat3 + vorr $in4,$dat4,$dat4 + +.Loop5x_cbc_dec: + aesd $dat0,q8 + aesimc $dat0,$dat0 + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + aesd $dat3,q8 + aesimc $dat3,$dat3 + aesd $dat4,q8 + aesimc $dat4,$dat4 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aesd $dat0,q9 + aesimc $dat0,$dat0 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + aesd $dat3,q9 + aesimc $dat3,$dat3 + aesd $dat4,q9 + aesimc $dat4,$dat4 + vld1.32 {q9},[$key_],#16 + b.gt .Loop5x_cbc_dec + + aesd $dat0,q8 + aesimc $dat0,$dat0 + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + aesd $dat3,q8 + aesimc $dat3,$dat3 + aesd $dat4,q8 + aesimc $dat4,$dat4 + cmp $len,#0x40 // because .Lcbc_tail4x + sub $len,$len,#0x50 + + aesd $dat0,q9 + aesimc $dat0,$dat0 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + aesd $dat3,q9 + aesimc $dat3,$dat3 + aesd $dat4,q9 + aesimc $dat4,$dat4 + csel x6,xzr,$len,gt // borrow x6, $cnt, "gt" is not typo + mov $key_,$key + + aesd $dat0,q10 + aesimc $dat0,$dat0 + aesd $dat1,q10 + aesimc $dat1,$dat1 + aesd $dat2,q10 + aesimc $dat2,$dat2 + aesd $dat3,q10 + aesimc $dat3,$dat3 + aesd $dat4,q10 + aesimc $dat4,$dat4 + add $inp,$inp,x6 // $inp is adjusted in such way that + // at exit from the loop $dat1-$dat4 + // are loaded with last "words" + add x6,$len,#0x60 // because .Lcbc_tail4x + + aesd $dat0,q11 + aesimc $dat0,$dat0 + aesd $dat1,q11 + aesimc $dat1,$dat1 + aesd $dat2,q11 + aesimc $dat2,$dat2 + aesd $dat3,q11 + aesimc $dat3,$dat3 + aesd $dat4,q11 + aesimc $dat4,$dat4 + + aesd $dat0,q12 + aesimc $dat0,$dat0 + aesd $dat1,q12 + aesimc $dat1,$dat1 + aesd $dat2,q12 + aesimc $dat2,$dat2 + aesd $dat3,q12 + aesimc $dat3,$dat3 + aesd $dat4,q12 + aesimc $dat4,$dat4 + + aesd $dat0,q13 + aesimc $dat0,$dat0 + aesd $dat1,q13 + aesimc $dat1,$dat1 + aesd $dat2,q13 + aesimc $dat2,$dat2 + aesd $dat3,q13 + aesimc $dat3,$dat3 + aesd $dat4,q13 + aesimc $dat4,$dat4 + + aesd $dat0,q14 + aesimc $dat0,$dat0 + aesd $dat1,q14 + aesimc $dat1,$dat1 + aesd $dat2,q14 + aesimc $dat2,$dat2 + aesd $dat3,q14 + aesimc $dat3,$dat3 + aesd $dat4,q14 + aesimc $dat4,$dat4 + + veor $tmp0,$ivec,$rndlast + aesd $dat0,q15 + veor $tmp1,$in0,$rndlast + vld1.8 {$in0},[$inp],#16 + aesd $dat1,q15 + veor $tmp2,$in1,$rndlast + vld1.8 {$in1},[$inp],#16 + aesd $dat2,q15 + veor $tmp3,$in2,$rndlast + vld1.8 {$in2},[$inp],#16 + aesd $dat3,q15 + veor $tmp4,$in3,$rndlast + vld1.8 {$in3},[$inp],#16 + aesd $dat4,q15 + vorr $ivec,$in4,$in4 + vld1.8 {$in4},[$inp],#16 + cbz x6,.Lcbc_tail4x + vld1.32 {q8},[$key_],#16 // re-pre-load rndkey[0] + veor $tmp0,$tmp0,$dat0 + vorr $dat0,$in0,$in0 + veor $tmp1,$tmp1,$dat1 + vorr $dat1,$in1,$in1 + veor $tmp2,$tmp2,$dat2 + vorr $dat2,$in2,$in2 + veor $tmp3,$tmp3,$dat3 + vorr $dat3,$in3,$in3 + veor $tmp4,$tmp4,$dat4 + vst1.8 {$tmp0},[$out],#16 + vorr $dat4,$in4,$in4 + vst1.8 {$tmp1},[$out],#16 + mov $cnt,$rounds + vst1.8 {$tmp2},[$out],#16 + vld1.32 {q9},[$key_],#16 // re-pre-load rndkey[1] + vst1.8 {$tmp3},[$out],#16 + vst1.8 {$tmp4},[$out],#16 + b.hs .Loop5x_cbc_dec + + add $len,$len,#0x50 + cbz $len,.Lcbc_done + + add $cnt,$rounds,#2 + subs $len,$len,#0x30 + vorr $dat0,$in2,$in2 + vorr $in0,$in2,$in2 + vorr $dat1,$in3,$in3 + vorr $in1,$in3,$in3 + vorr $dat2,$in4,$in4 + vorr $in2,$in4,$in4 + b.lo .Lcbc_dec_tail + + b .Loop3x_cbc_dec + +.align 4 +.Lcbc_tail4x: + veor $tmp1,$tmp0,$dat1 + veor $tmp2,$tmp2,$dat2 + veor $tmp3,$tmp3,$dat3 + veor $tmp4,$tmp4,$dat4 + vst1.8 {$tmp1},[$out],#16 + vst1.8 {$tmp2},[$out],#16 + vst1.8 {$tmp3},[$out],#16 + vst1.8 {$tmp4},[$out],#16 + + b .Lcbc_done +.align 4 +___ +$code.=<<___; .Loop3x_cbc_dec: aesd $dat0,q8 aesimc $dat0,$dat0 @@ -700,6 +912,9 @@ my $step="x12"; # aliases with $tctr2 my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7)); my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9)); +# used only in 64-bit mode... +my ($dat3,$dat4,$in3,$in4)=map("q$_",(16..23)); + my ($dat,$tmp)=($dat0,$tmp0); ### q8-q15 preloaded key schedule @@ -752,6 +967,175 @@ $code.=<<___; rev $tctr2, $ctr sub $len,$len,#3 // bias vmov.32 ${dat2}[3],$tctr2 +___ +$code.=<<___ if ($flavour =~ /64/); + cmp $len,#2 + b.lo .Loop3x_ctr32 + + add w13,$ctr,#1 + add w14,$ctr,#2 + vorr $dat3,$dat0,$dat0 + rev w13,w13 + vorr $dat4,$dat0,$dat0 + rev w14,w14 + vmov.32 ${dat3}[3],w13 + sub $len,$len,#2 // bias + vmov.32 ${dat4}[3],w14 + add $ctr,$ctr,#2 + b .Loop5x_ctr32 + +.align 4 +.Loop5x_ctr32: + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + aese $dat2,q8 + aesmc $dat2,$dat2 + aese $dat3,q8 + aesmc $dat3,$dat3 + aese $dat4,q8 + aesmc $dat4,$dat4 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + aese $dat2,q9 + aesmc $dat2,$dat2 + aese $dat3,q9 + aesmc $dat3,$dat3 + aese $dat4,q9 + aesmc $dat4,$dat4 + vld1.32 {q9},[$key_],#16 + b.gt .Loop5x_ctr32 + + mov $key_,$key + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + aese $dat2,q8 + aesmc $dat2,$dat2 + aese $dat3,q8 + aesmc $dat3,$dat3 + aese $dat4,q8 + aesmc $dat4,$dat4 + vld1.32 {q8},[$key_],#16 // re-pre-load rndkey[0] + + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + aese $dat2,q9 + aesmc $dat2,$dat2 + aese $dat3,q9 + aesmc $dat3,$dat3 + aese $dat4,q9 + aesmc $dat4,$dat4 + vld1.32 {q9},[$key_],#16 // re-pre-load rndkey[1] + + aese $dat0,q12 + aesmc $dat0,$dat0 + add $tctr0,$ctr,#1 + add $tctr1,$ctr,#2 + aese $dat1,q12 + aesmc $dat1,$dat1 + add $tctr2,$ctr,#3 + add w13,$ctr,#4 + aese $dat2,q12 + aesmc $dat2,$dat2 + add w14,$ctr,#5 + rev $tctr0,$tctr0 + aese $dat3,q12 + aesmc $dat3,$dat3 + rev $tctr1,$tctr1 + rev $tctr2,$tctr2 + aese $dat4,q12 + aesmc $dat4,$dat4 + rev w13,w13 + rev w14,w14 + + aese $dat0,q13 + aesmc $dat0,$dat0 + aese $dat1,q13 + aesmc $dat1,$dat1 + aese $dat2,q13 + aesmc $dat2,$dat2 + aese $dat3,q13 + aesmc $dat3,$dat3 + aese $dat4,q13 + aesmc $dat4,$dat4 + + aese $dat0,q14 + aesmc $dat0,$dat0 + vld1.8 {$in0},[$inp],#16 + aese $dat1,q14 + aesmc $dat1,$dat1 + vld1.8 {$in1},[$inp],#16 + aese $dat2,q14 + aesmc $dat2,$dat2 + vld1.8 {$in2},[$inp],#16 + aese $dat3,q14 + aesmc $dat3,$dat3 + vld1.8 {$in3},[$inp],#16 + aese $dat4,q14 + aesmc $dat4,$dat4 + vld1.8 {$in4},[$inp],#16 + + aese $dat0,q15 + veor $in0,$in0,$rndlast + aese $dat1,q15 + veor $in1,$in1,$rndlast + aese $dat2,q15 + veor $in2,$in2,$rndlast + aese $dat3,q15 + veor $in3,$in3,$rndlast + aese $dat4,q15 + veor $in4,$in4,$rndlast + + veor $in0,$in0,$dat0 + vorr $dat0,$ivec,$ivec + veor $in1,$in1,$dat1 + vorr $dat1,$ivec,$ivec + veor $in2,$in2,$dat2 + vorr $dat2,$ivec,$ivec + veor $in3,$in3,$dat3 + vorr $dat3,$ivec,$ivec + veor $in4,$in4,$dat4 + vorr $dat4,$ivec,$ivec + + vst1.8 {$in0},[$out],#16 + vmov.32 ${dat0}[3],$tctr0 + vst1.8 {$in1},[$out],#16 + vmov.32 ${dat1}[3],$tctr1 + vst1.8 {$in2},[$out],#16 + vmov.32 ${dat2}[3],$tctr2 + vst1.8 {$in3},[$out],#16 + vmov.32 ${dat3}[3],w13 + vst1.8 {$in4},[$out],#16 + vmov.32 ${dat4}[3],w14 + + mov $cnt,$rounds + cbz $len,.Lctr32_done + + add $ctr,$ctr,#5 + subs $len,$len,#5 + b.hs .Loop5x_ctr32 + + add $len,$len,#5 + sub $ctr,$ctr,#5 + + cmp $len,#2 + mov $step,#16 + cclr $step,lo + b.ls .Lctr32_tail + + sub $len,$len,#3 // bias + add $ctr,$ctr,#3 +___ +$code.=<<___; b .Loop3x_ctr32 .align 4 diff --git a/crypto/aes/asm/vpaes-armv8.pl b/crypto/aes/asm/vpaes-armv8.pl index f08ae583..c7839b32 100755 --- a/crypto/aes/asm/vpaes-armv8.pl +++ b/crypto/aes/asm/vpaes-armv8.pl @@ -30,6 +30,7 @@ # Denver(***) 16.6(**) 15.1/17.8(**) [8.80/9.93 ] # Apple A7(***) 22.7(**) 10.9/14.3 [8.45/10.0 ] # Mongoose(***) 26.3(**) 21.0/25.0(**) [13.3/16.8 ] +# ThunderX2(***) 39.4(**) 33.8/48.6(**) # # (*) ECB denotes approximate result for parallelizable modes # such as CBC decrypt, CTR, etc.; diff --git a/crypto/bio/bss_mem.c b/crypto/bio/bss_mem.c index 89c54b2d..a7f2bfba 100644 --- a/crypto/bio/bss_mem.c +++ b/crypto/bio/bss_mem.c @@ -57,7 +57,12 @@ static const BIO_METHOD secmem_method = { NULL, /* mem_callback_ctrl */ }; -/* BIO memory stores buffer and read pointer */ +/* + * BIO memory stores buffer and read pointer + * however the roles are different for read only BIOs. + * In that case the readp just stores the original state + * to be used for reset. + */ typedef struct bio_buf_mem_st { struct buf_mem_st *buf; /* allocated buffer */ struct buf_mem_st *readp; /* read pointer */ @@ -192,11 +197,14 @@ static int mem_read(BIO *b, char *out, int outl) BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; BUF_MEM *bm = bbm->readp; + if (b->flags & BIO_FLAGS_MEM_RDONLY) + bm = bbm->buf; BIO_clear_retry_flags(b); ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl; if ((out != NULL) && (ret > 0)) { memcpy(out, bm->data, ret); bm->length -= ret; + bm->max -= ret; bm->data += ret; } else if (bm->length == 0) { ret = b->num; @@ -241,29 +249,36 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; BUF_MEM *bm; + if (b->flags & BIO_FLAGS_MEM_RDONLY) + bm = bbm->buf; + else + bm = bbm->readp; + switch (cmd) { case BIO_CTRL_RESET: bm = bbm->buf; if (bm->data != NULL) { - /* For read only case reset to the start again */ - if ((b->flags & BIO_FLAGS_MEM_RDONLY) || (b->flags & BIO_FLAGS_NONCLEAR_RST)) { - bm->length = bm->max; + if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) { + if (b->flags & BIO_FLAGS_NONCLEAR_RST) { + bm->length = bm->max; + } else { + memset(bm->data, 0, bm->max); + bm->length = 0; + } + *bbm->readp = *bbm->buf; } else { - memset(bm->data, 0, bm->max); - bm->length = 0; + /* For read only case just reset to the start again */ + *bbm->buf = *bbm->readp; } - *bbm->readp = *bbm->buf; } break; case BIO_CTRL_EOF: - bm = bbm->readp; ret = (long)(bm->length == 0); break; case BIO_C_SET_BUF_MEM_EOF_RETURN: b->num = (int)num; break; case BIO_CTRL_INFO: - bm = bbm->readp; ret = (long)bm->length; if (ptr != NULL) { pptr = (char **)ptr; @@ -278,8 +293,9 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) break; case BIO_C_GET_BUF_MEM_PTR: if (ptr != NULL) { - mem_buf_sync(b); - bm = bbm->readp; + if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) + mem_buf_sync(b); + bm = bbm->buf; pptr = (char **)ptr; *pptr = (char *)bm; } @@ -294,7 +310,6 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) ret = 0L; break; case BIO_CTRL_PENDING: - bm = bbm->readp; ret = (long)bm->length; break; case BIO_CTRL_DUP: @@ -318,6 +333,8 @@ static int mem_gets(BIO *bp, char *buf, int size) BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr; BUF_MEM *bm = bbm->readp; + if (bp->flags & BIO_FLAGS_MEM_RDONLY) + bm = bbm->buf; BIO_clear_retry_flags(bp); j = bm->length; if ((size - 1) < j) diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c index 2c9f89d9..03402c2c 100644 --- a/crypto/bn/bn_prime.c +++ b/crypto/bn/bn_prime.c @@ -329,8 +329,6 @@ int bn_miller_rabin_is_prime(const BIGNUM *w, int iterations, BN_CTX *ctx, if (BN_is_one(z)) goto composite; } - if (!BN_GENCB_call(cb, 1, i)) - goto err; /* At this point z = b^((w-1)/2) mod w */ /* (Steps 4.8 - 4.9) x = z, z = x^2 mod w */ if (!BN_copy(x, z) || !BN_mod_mul(z, x, x, w, ctx)) @@ -358,6 +356,8 @@ composite: goto err; outer_loop: ; /* (Step 4.1.5) */ + if (!BN_GENCB_call(cb, 1, i)) + goto err; } /* (Step 5) */ *status = BN_PRIMETEST_PROBABLY_PRIME; diff --git a/crypto/build.info b/crypto/build.info index 77dcffb9..30dcf8c9 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -14,7 +14,7 @@ SOURCE[../libcrypto]=provider_core.c provider_predefined.c provider_conf.c \ # Central utilities SOURCE[../libcrypto]=\ - cryptlib.c mem.c mem_dbg.c cversion.c ex_data.c cpt_err.c \ + cryptlib.c mem.c mem_dbg.c cversion.c info.c ex_data.c cpt_err.c \ ebcdic.c uid.c o_time.c o_str.c o_dir.c o_fopen.c ctype.c \ threads_pthread.c threads_win.c threads_none.c getenv.c \ o_init.c o_fips.c mem_sec.c init.c context.c sparse_array.c \ diff --git a/crypto/chacha/asm/chacha-armv8.pl b/crypto/chacha/asm/chacha-armv8.pl index 56ba1c36..1f510173 100755 --- a/crypto/chacha/asm/chacha-armv8.pl +++ b/crypto/chacha/asm/chacha-armv8.pl @@ -18,22 +18,31 @@ # # ChaCha20 for ARMv8. # +# April 2019 +# +# Replace 3xNEON+1xIALU code path with 4+1. 4+1 is actually fastest +# option on most(*), but not all, processors, yet 6+2 is retained. +# This is because penalties are considered tolerable in comparison to +# improvement on processors where 6+2 helps. Most notably +37% on +# ThunderX2. It's server-oriented processor which will have to serve +# as many requests as possible. While others are mostly clients, when +# performance doesn't have to be absolute top-notch, just fast enough, +# as majority of time is spent "entertaining" relatively slow human. +# # Performance in cycles per byte out of large buffer. # -# IALU/gcc-4.9 3xNEON+1xIALU 6xNEON+2xIALU +# IALU/gcc-4.9 4xNEON+1xIALU 6xNEON+2xIALU # -# Apple A7 5.50/+49% 3.33 1.70 -# Cortex-A53 8.40/+80% 4.72 4.72(*) -# Cortex-A57 8.06/+43% 4.90 4.43(**) -# Denver 4.50/+82% 2.63 2.67(*) -# X-Gene 9.50/+46% 8.82 8.89(*) -# Mongoose 8.00/+44% 3.64 3.25 -# Kryo 8.17/+50% 4.83 4.65 +# Apple A7 5.50/+49% 2.72 1.60 +# Cortex-A53 8.40/+80% 4.06 4.45(*) +# Cortex-A57 8.06/+43% 4.15 4.40(*) +# Denver 4.50/+82% 2.30 2.70(*) +# X-Gene 9.50/+46% 8.20 8.90(*) +# Mongoose 8.00/+44% 2.74 3.12(*) +# Kryo 8.17/+50% 4.47 4.65(*) +# ThunderX2 7.22/+48% 5.64 4.10 # -# (*) it's expected that doubling interleave factor doesn't help -# all processors, only those with higher NEON latency and -# higher instruction issue rate; -# (**) expected improvement was actually higher; +# (*) slower than 4+1:-( $flavour=shift; $output=shift; @@ -120,18 +129,21 @@ my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2)); } $code.=<<___; -#include "arm_arch.h" +#ifndef __KERNEL__ +# include "arm_arch.h" +.extern OPENSSL_armcap_P +#endif .text -.extern OPENSSL_armcap_P - .align 5 .Lsigma: .quad 0x3320646e61707865,0x6b20657479622d32 // endian-neutral .Lone: -.long 1,0,0,0 -.asciz "ChaCha20 for ARMv8, CRYPTOGAMS by " +.long 1,2,3,4 +.Lrot24: +.long 0x02010003,0x06050407,0x0a09080b,0x0e0d0c0f +.asciz "ChaCha20 for ARMv8, CRYPTOGAMS by \@dot-asm" .globl ChaCha20_ctr32 .type ChaCha20_ctr32,%function @@ -141,10 +153,12 @@ ChaCha20_ctr32: cmp $len,#192 b.lo .Lshort +#ifndef __KERNEL__ adrp x17,OPENSSL_armcap_P ldr w17,[x17,#:lo12:OPENSSL_armcap_P] tst w17,#ARMV7_NEON b.ne .LChaCha20_neon +#endif .Lshort: .inst 0xd503233f // paciasp @@ -163,7 +177,7 @@ ChaCha20_ctr32: ldp @d[2],@d[3],[$key] // load key ldp @d[4],@d[5],[$key,#16] ldp @d[6],@d[7],[$ctr] // load counter -#ifdef __ARMEB__ +#ifdef __AARCH64EB__ ror @d[2],@d[2],#32 ror @d[3],@d[3],#32 ror @d[4],@d[4],#32 @@ -232,7 +246,7 @@ $code.=<<___; add @x[14],@x[14],@x[15],lsl#32 ldp @x[13],@x[15],[$inp,#48] add $inp,$inp,#64 -#ifdef __ARMEB__ +#ifdef __AARCH64EB__ rev @x[0],@x[0] rev @x[2],@x[2] rev @x[4],@x[4] @@ -289,7 +303,7 @@ $code.=<<___; add @x[10],@x[10],@x[11],lsl#32 add @x[12],@x[12],@x[13],lsl#32 add @x[14],@x[14],@x[15],lsl#32 -#ifdef __ARMEB__ +#ifdef __AARCH64EB__ rev @x[0],@x[0] rev @x[2],@x[2] rev @x[4],@x[4] @@ -330,43 +344,87 @@ $code.=<<___; ___ {{{ -my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,$T0,$T1,$T2,$T3) = - map("v$_.4s",(0..7,16..23)); -my (@K)=map("v$_.4s",(24..30)); -my $ONE="v31.4s"; +my @K = map("v$_.4s",(0..3)); +my ($xt0,$xt1,$xt2,$xt3, $CTR,$ROT24) = map("v$_.4s",(4..9)); +my @X = map("v$_.4s",(16,20,24,28, 17,21,25,29, 18,22,26,30, 19,23,27,31)); +my ($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3, + $xc0,$xc1,$xc2,$xc3, $xd0,$xd1,$xd2,$xd3) = @X; -sub NEONROUND { -my $odd = pop; -my ($a,$b,$c,$d,$t)=@_; +sub NEON_lane_ROUND { +my ($a0,$b0,$c0,$d0)=@_; +my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0)); +my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1)); +my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2)); +my @x=map("'$_'",@X); ( - "&add ('$a','$a','$b')", - "&eor ('$d','$d','$a')", - "&rev32_16 ('$d','$d')", # vrot ($d,16) + "&add (@x[$a0],@x[$a0],@x[$b0])", # Q1 + "&add (@x[$a1],@x[$a1],@x[$b1])", # Q2 + "&add (@x[$a2],@x[$a2],@x[$b2])", # Q3 + "&add (@x[$a3],@x[$a3],@x[$b3])", # Q4 + "&eor (@x[$d0],@x[$d0],@x[$a0])", + "&eor (@x[$d1],@x[$d1],@x[$a1])", + "&eor (@x[$d2],@x[$d2],@x[$a2])", + "&eor (@x[$d3],@x[$d3],@x[$a3])", + "&rev32_16 (@x[$d0],@x[$d0])", + "&rev32_16 (@x[$d1],@x[$d1])", + "&rev32_16 (@x[$d2],@x[$d2])", + "&rev32_16 (@x[$d3],@x[$d3])", - "&add ('$c','$c','$d')", - "&eor ('$t','$b','$c')", - "&ushr ('$b','$t',20)", - "&sli ('$b','$t',12)", + "&add (@x[$c0],@x[$c0],@x[$d0])", + "&add (@x[$c1],@x[$c1],@x[$d1])", + "&add (@x[$c2],@x[$c2],@x[$d2])", + "&add (@x[$c3],@x[$c3],@x[$d3])", + "&eor ('$xt0',@x[$b0],@x[$c0])", + "&eor ('$xt1',@x[$b1],@x[$c1])", + "&eor ('$xt2',@x[$b2],@x[$c2])", + "&eor ('$xt3',@x[$b3],@x[$c3])", + "&ushr (@x[$b0],'$xt0',20)", + "&ushr (@x[$b1],'$xt1',20)", + "&ushr (@x[$b2],'$xt2',20)", + "&ushr (@x[$b3],'$xt3',20)", + "&sli (@x[$b0],'$xt0',12)", + "&sli (@x[$b1],'$xt1',12)", + "&sli (@x[$b2],'$xt2',12)", + "&sli (@x[$b3],'$xt3',12)", - "&add ('$a','$a','$b')", - "&eor ('$t','$d','$a')", - "&ushr ('$d','$t',24)", - "&sli ('$d','$t',8)", + "&add (@x[$a0],@x[$a0],@x[$b0])", + "&add (@x[$a1],@x[$a1],@x[$b1])", + "&add (@x[$a2],@x[$a2],@x[$b2])", + "&add (@x[$a3],@x[$a3],@x[$b3])", + "&eor ('$xt0',@x[$d0],@x[$a0])", + "&eor ('$xt1',@x[$d1],@x[$a1])", + "&eor ('$xt2',@x[$d2],@x[$a2])", + "&eor ('$xt3',@x[$d3],@x[$a3])", + "&tbl (@x[$d0],'{$xt0}','$ROT24')", + "&tbl (@x[$d1],'{$xt1}','$ROT24')", + "&tbl (@x[$d2],'{$xt2}','$ROT24')", + "&tbl (@x[$d3],'{$xt3}','$ROT24')", - "&add ('$c','$c','$d')", - "&eor ('$t','$b','$c')", - "&ushr ('$b','$t',25)", - "&sli ('$b','$t',7)", - - "&ext ('$c','$c','$c',8)", - "&ext ('$d','$d','$d',$odd?4:12)", - "&ext ('$b','$b','$b',$odd?12:4)" + "&add (@x[$c0],@x[$c0],@x[$d0])", + "&add (@x[$c1],@x[$c1],@x[$d1])", + "&add (@x[$c2],@x[$c2],@x[$d2])", + "&add (@x[$c3],@x[$c3],@x[$d3])", + "&eor ('$xt0',@x[$b0],@x[$c0])", + "&eor ('$xt1',@x[$b1],@x[$c1])", + "&eor ('$xt2',@x[$b2],@x[$c2])", + "&eor ('$xt3',@x[$b3],@x[$c3])", + "&ushr (@x[$b0],'$xt0',25)", + "&ushr (@x[$b1],'$xt1',25)", + "&ushr (@x[$b2],'$xt2',25)", + "&ushr (@x[$b3],'$xt3',25)", + "&sli (@x[$b0],'$xt0',7)", + "&sli (@x[$b1],'$xt1',7)", + "&sli (@x[$b2],'$xt2',7)", + "&sli (@x[$b3],'$xt3',7)" ); } $code.=<<___; +#ifdef __KERNEL__ +.globl ChaCha20_neon +#endif .type ChaCha20_neon,%function .align 5 ChaCha20_neon: @@ -393,8 +451,9 @@ ChaCha20_neon: ld1 {@K[1],@K[2]},[$key] ldp @d[6],@d[7],[$ctr] // load counter ld1 {@K[3]},[$ctr] - ld1 {$ONE},[@x[0]] -#ifdef __ARMEB__ + stp d8,d9,[sp] // meet ABI requirements + ld1 {$CTR,$ROT24},[@x[0]] +#ifdef __AARCH64EB__ rev64 @K[0],@K[0] ror @d[2],@d[2],#32 ror @d[3],@d[3],#32 @@ -403,115 +462,129 @@ ChaCha20_neon: ror @d[6],@d[6],#32 ror @d[7],@d[7],#32 #endif - add @K[3],@K[3],$ONE // += 1 - add @K[4],@K[3],$ONE - add @K[5],@K[4],$ONE - shl $ONE,$ONE,#2 // 1 -> 4 .Loop_outer_neon: - mov.32 @x[0],@d[0] // unpack key block - lsr @x[1],@d[0],#32 - mov $A0,@K[0] - mov.32 @x[2],@d[1] - lsr @x[3],@d[1],#32 - mov $A1,@K[0] - mov.32 @x[4],@d[2] - lsr @x[5],@d[2],#32 - mov $A2,@K[0] - mov.32 @x[6],@d[3] - mov $B0,@K[1] - lsr @x[7],@d[3],#32 - mov $B1,@K[1] - mov.32 @x[8],@d[4] - mov $B2,@K[1] - lsr @x[9],@d[4],#32 - mov $D0,@K[3] - mov.32 @x[10],@d[5] - mov $D1,@K[4] - lsr @x[11],@d[5],#32 - mov $D2,@K[5] - mov.32 @x[12],@d[6] - mov $C0,@K[2] - lsr @x[13],@d[6],#32 - mov $C1,@K[2] - mov.32 @x[14],@d[7] - mov $C2,@K[2] - lsr @x[15],@d[7],#32 + dup $xa0,@{K[0]}[0] // unpack key block + mov.32 @x[0],@d[0] + dup $xa1,@{K[0]}[1] + lsr @x[1],@d[0],#32 + dup $xa2,@{K[0]}[2] + mov.32 @x[2],@d[1] + dup $xa3,@{K[0]}[3] + lsr @x[3],@d[1],#32 + dup $xb0,@{K[1]}[0] + mov.32 @x[4],@d[2] + dup $xb1,@{K[1]}[1] + lsr @x[5],@d[2],#32 + dup $xb2,@{K[1]}[2] + mov.32 @x[6],@d[3] + dup $xb3,@{K[1]}[3] + lsr @x[7],@d[3],#32 + dup $xd0,@{K[3]}[0] + mov.32 @x[8],@d[4] + dup $xd1,@{K[3]}[1] + lsr @x[9],@d[4],#32 + dup $xd2,@{K[3]}[2] + mov.32 @x[10],@d[5] + dup $xd3,@{K[3]}[3] + lsr @x[11],@d[5],#32 + add $xd0,$xd0,$CTR + mov.32 @x[12],@d[6] + dup $xc0,@{K[2]}[0] + lsr @x[13],@d[6],#32 + dup $xc1,@{K[2]}[1] + mov.32 @x[14],@d[7] + dup $xc2,@{K[2]}[2] + lsr @x[15],@d[7],#32 + dup $xc3,@{K[2]}[3] mov $ctr,#10 - subs $len,$len,#256 + subs $len,$len,#320 .Loop_neon: sub $ctr,$ctr,#1 ___ - my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0); - my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0); - my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0); - my @thread3=&ROUND(0,4,8,12); + my @plus_one=&ROUND(0,4,8,12); + foreach (&NEON_lane_ROUND(0,4,8,12)) { eval; eval(shift(@plus_one)); } - foreach (@thread0) { - eval; eval(shift(@thread3)); - eval(shift(@thread1)); eval(shift(@thread3)); - eval(shift(@thread2)); eval(shift(@thread3)); - } - - @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1); - @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1); - @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1); - @thread3=&ROUND(0,5,10,15); - - foreach (@thread0) { - eval; eval(shift(@thread3)); - eval(shift(@thread1)); eval(shift(@thread3)); - eval(shift(@thread2)); eval(shift(@thread3)); - } + @plus_one=&ROUND(0,5,10,15); + foreach (&NEON_lane_ROUND(0,5,10,15)) { eval; eval(shift(@plus_one)); } $code.=<<___; cbnz $ctr,.Loop_neon - add.32 @x[0],@x[0],@d[0] // accumulate key block - add $A0,$A0,@K[0] - add @x[1],@x[1],@d[0],lsr#32 - add $A1,$A1,@K[0] - add.32 @x[2],@x[2],@d[1] - add $A2,$A2,@K[0] - add @x[3],@x[3],@d[1],lsr#32 - add $C0,$C0,@K[2] - add.32 @x[4],@x[4],@d[2] - add $C1,$C1,@K[2] - add @x[5],@x[5],@d[2],lsr#32 - add $C2,$C2,@K[2] - add.32 @x[6],@x[6],@d[3] - add $D0,$D0,@K[3] - add @x[7],@x[7],@d[3],lsr#32 - add.32 @x[8],@x[8],@d[4] - add $D1,$D1,@K[4] - add @x[9],@x[9],@d[4],lsr#32 - add.32 @x[10],@x[10],@d[5] - add $D2,$D2,@K[5] - add @x[11],@x[11],@d[5],lsr#32 - add.32 @x[12],@x[12],@d[6] - add $B0,$B0,@K[1] - add @x[13],@x[13],@d[6],lsr#32 - add.32 @x[14],@x[14],@d[7] - add $B1,$B1,@K[1] - add @x[15],@x[15],@d[7],lsr#32 - add $B2,$B2,@K[1] + add $xd0,$xd0,$CTR + + zip1 $xt0,$xa0,$xa1 // transpose data + zip1 $xt1,$xa2,$xa3 + zip2 $xt2,$xa0,$xa1 + zip2 $xt3,$xa2,$xa3 + zip1.64 $xa0,$xt0,$xt1 + zip2.64 $xa1,$xt0,$xt1 + zip1.64 $xa2,$xt2,$xt3 + zip2.64 $xa3,$xt2,$xt3 + + zip1 $xt0,$xb0,$xb1 + zip1 $xt1,$xb2,$xb3 + zip2 $xt2,$xb0,$xb1 + zip2 $xt3,$xb2,$xb3 + zip1.64 $xb0,$xt0,$xt1 + zip2.64 $xb1,$xt0,$xt1 + zip1.64 $xb2,$xt2,$xt3 + zip2.64 $xb3,$xt2,$xt3 + + zip1 $xt0,$xc0,$xc1 + add.32 @x[0],@x[0],@d[0] // accumulate key block + zip1 $xt1,$xc2,$xc3 + add @x[1],@x[1],@d[0],lsr#32 + zip2 $xt2,$xc0,$xc1 + add.32 @x[2],@x[2],@d[1] + zip2 $xt3,$xc2,$xc3 + add @x[3],@x[3],@d[1],lsr#32 + zip1.64 $xc0,$xt0,$xt1 + add.32 @x[4],@x[4],@d[2] + zip2.64 $xc1,$xt0,$xt1 + add @x[5],@x[5],@d[2],lsr#32 + zip1.64 $xc2,$xt2,$xt3 + add.32 @x[6],@x[6],@d[3] + zip2.64 $xc3,$xt2,$xt3 + add @x[7],@x[7],@d[3],lsr#32 + + zip1 $xt0,$xd0,$xd1 + add.32 @x[8],@x[8],@d[4] + zip1 $xt1,$xd2,$xd3 + add @x[9],@x[9],@d[4],lsr#32 + zip2 $xt2,$xd0,$xd1 + add.32 @x[10],@x[10],@d[5] + zip2 $xt3,$xd2,$xd3 + add @x[11],@x[11],@d[5],lsr#32 + zip1.64 $xd0,$xt0,$xt1 + add.32 @x[12],@x[12],@d[6] + zip2.64 $xd1,$xt0,$xt1 + add @x[13],@x[13],@d[6],lsr#32 + zip1.64 $xd2,$xt2,$xt3 + add.32 @x[14],@x[14],@d[7] + zip2.64 $xd3,$xt2,$xt3 + add @x[15],@x[15],@d[7],lsr#32 b.lo .Ltail_neon add @x[0],@x[0],@x[1],lsl#32 // pack add @x[2],@x[2],@x[3],lsl#32 ldp @x[1],@x[3],[$inp,#0] // load input + add $xa0,$xa0,@K[0] // accumulate key block add @x[4],@x[4],@x[5],lsl#32 add @x[6],@x[6],@x[7],lsl#32 ldp @x[5],@x[7],[$inp,#16] + add $xb0,$xb0,@K[1] add @x[8],@x[8],@x[9],lsl#32 add @x[10],@x[10],@x[11],lsl#32 ldp @x[9],@x[11],[$inp,#32] + add $xc0,$xc0,@K[2] add @x[12],@x[12],@x[13],lsl#32 add @x[14],@x[14],@x[15],lsl#32 ldp @x[13],@x[15],[$inp,#48] + add $xd0,$xd0,@K[3] add $inp,$inp,#64 -#ifdef __ARMEB__ +#ifdef __AARCH64EB__ rev @x[0],@x[0] rev @x[2],@x[2] rev @x[4],@x[4] @@ -521,48 +594,68 @@ $code.=<<___; rev @x[12],@x[12] rev @x[14],@x[14] #endif - ld1.8 {$T0-$T3},[$inp],#64 + ld1.8 {$xt0-$xt3},[$inp],#64 eor @x[0],@x[0],@x[1] + add $xa1,$xa1,@K[0] eor @x[2],@x[2],@x[3] + add $xb1,$xb1,@K[1] eor @x[4],@x[4],@x[5] + add $xc1,$xc1,@K[2] eor @x[6],@x[6],@x[7] + add $xd1,$xd1,@K[3] eor @x[8],@x[8],@x[9] - eor $A0,$A0,$T0 + eor $xa0,$xa0,$xt0 + movi $xt0,#5 eor @x[10],@x[10],@x[11] - eor $B0,$B0,$T1 + eor $xb0,$xb0,$xt1 eor @x[12],@x[12],@x[13] - eor $C0,$C0,$T2 + eor $xc0,$xc0,$xt2 eor @x[14],@x[14],@x[15] - eor $D0,$D0,$T3 - ld1.8 {$T0-$T3},[$inp],#64 + eor $xd0,$xd0,$xt3 + add $CTR,$CTR,$xt0 // += 5 + ld1.8 {$xt0-$xt3},[$inp],#64 stp @x[0],@x[2],[$out,#0] // store output - add @d[6],@d[6],#4 // increment counter + add @d[6],@d[6],#5 // increment counter stp @x[4],@x[6],[$out,#16] - add @K[3],@K[3],$ONE // += 4 stp @x[8],@x[10],[$out,#32] - add @K[4],@K[4],$ONE stp @x[12],@x[14],[$out,#48] - add @K[5],@K[5],$ONE add $out,$out,#64 - st1.8 {$A0-$D0},[$out],#64 - ld1.8 {$A0-$D0},[$inp],#64 + st1.8 {$xa0-$xd0},[$out],#64 + add $xa2,$xa2,@K[0] + add $xb2,$xb2,@K[1] + add $xc2,$xc2,@K[2] + add $xd2,$xd2,@K[3] + ld1.8 {$xa0-$xd0},[$inp],#64 - eor $A1,$A1,$T0 - eor $B1,$B1,$T1 - eor $C1,$C1,$T2 - eor $D1,$D1,$T3 - st1.8 {$A1-$D1},[$out],#64 + eor $xa1,$xa1,$xt0 + eor $xb1,$xb1,$xt1 + eor $xc1,$xc1,$xt2 + eor $xd1,$xd1,$xt3 + st1.8 {$xa1-$xd1},[$out],#64 + add $xa3,$xa3,@K[0] + add $xb3,$xb3,@K[1] + add $xc3,$xc3,@K[2] + add $xd3,$xd3,@K[3] + ld1.8 {$xa1-$xd1},[$inp],#64 - eor $A2,$A2,$A0 - eor $B2,$B2,$B0 - eor $C2,$C2,$C0 - eor $D2,$D2,$D0 - st1.8 {$A2-$D2},[$out],#64 + eor $xa2,$xa2,$xa0 + eor $xb2,$xb2,$xb0 + eor $xc2,$xc2,$xc0 + eor $xd2,$xd2,$xd0 + st1.8 {$xa2-$xd2},[$out],#64 + + eor $xa3,$xa3,$xa1 + eor $xb3,$xb3,$xb1 + eor $xc3,$xc3,$xc1 + eor $xd3,$xd3,$xd1 + st1.8 {$xa3-$xd3},[$out],#64 b.hi .Loop_outer_neon + ldp d8,d9,[sp] // meet ABI requirements + ldp x19,x20,[x29,#16] add sp,sp,#64 ldp x21,x22,[x29,#32] @@ -573,8 +666,10 @@ $code.=<<___; .inst 0xd50323bf // autiasp ret +.align 4 .Ltail_neon: - add $len,$len,#256 + add $len,$len,#320 + ldp d8,d9,[sp] // meet ABI requirements cmp $len,#64 b.lo .Less_than_64 @@ -591,7 +686,7 @@ $code.=<<___; add @x[14],@x[14],@x[15],lsl#32 ldp @x[13],@x[15],[$inp,#48] add $inp,$inp,#64 -#ifdef __ARMEB__ +#ifdef __AARCH64EB__ rev @x[0],@x[0] rev @x[2],@x[2] rev @x[4],@x[4] @@ -611,48 +706,68 @@ $code.=<<___; eor @x[14],@x[14],@x[15] stp @x[0],@x[2],[$out,#0] // store output - add @d[6],@d[6],#4 // increment counter + add $xa0,$xa0,@K[0] // accumulate key block stp @x[4],@x[6],[$out,#16] + add $xb0,$xb0,@K[1] stp @x[8],@x[10],[$out,#32] + add $xc0,$xc0,@K[2] stp @x[12],@x[14],[$out,#48] + add $xd0,$xd0,@K[3] add $out,$out,#64 b.eq .Ldone_neon sub $len,$len,#64 cmp $len,#64 - b.lo .Less_than_128 + b.lo .Last_neon - ld1.8 {$T0-$T3},[$inp],#64 - eor $A0,$A0,$T0 - eor $B0,$B0,$T1 - eor $C0,$C0,$T2 - eor $D0,$D0,$T3 - st1.8 {$A0-$D0},[$out],#64 + ld1.8 {$xt0-$xt3},[$inp],#64 + eor $xa0,$xa0,$xt0 + eor $xb0,$xb0,$xt1 + eor $xc0,$xc0,$xt2 + eor $xd0,$xd0,$xt3 + st1.8 {$xa0-$xd0},[$out],#64 b.eq .Ldone_neon + + add $xa0,$xa1,@K[0] + add $xb0,$xb1,@K[1] sub $len,$len,#64 + add $xc0,$xc1,@K[2] cmp $len,#64 - b.lo .Less_than_192 + add $xd0,$xd1,@K[3] + b.lo .Last_neon - ld1.8 {$T0-$T3},[$inp],#64 - eor $A1,$A1,$T0 - eor $B1,$B1,$T1 - eor $C1,$C1,$T2 - eor $D1,$D1,$T3 - st1.8 {$A1-$D1},[$out],#64 + ld1.8 {$xt0-$xt3},[$inp],#64 + eor $xa1,$xa0,$xt0 + eor $xb1,$xb0,$xt1 + eor $xc1,$xc0,$xt2 + eor $xd1,$xd0,$xt3 + st1.8 {$xa1-$xd1},[$out],#64 b.eq .Ldone_neon + + add $xa0,$xa2,@K[0] + add $xb0,$xb2,@K[1] + sub $len,$len,#64 + add $xc0,$xc2,@K[2] + cmp $len,#64 + add $xd0,$xd2,@K[3] + b.lo .Last_neon + + ld1.8 {$xt0-$xt3},[$inp],#64 + eor $xa2,$xa0,$xt0 + eor $xb2,$xb0,$xt1 + eor $xc2,$xc0,$xt2 + eor $xd2,$xd0,$xt3 + st1.8 {$xa2-$xd2},[$out],#64 + b.eq .Ldone_neon + + add $xa0,$xa3,@K[0] + add $xb0,$xb3,@K[1] + add $xc0,$xc3,@K[2] + add $xd0,$xd3,@K[3] sub $len,$len,#64 - st1.8 {$A2-$D2},[sp] - b .Last_neon - -.Less_than_128: - st1.8 {$A0-$D0},[sp] - b .Last_neon -.Less_than_192: - st1.8 {$A1-$D1},[sp] - b .Last_neon - -.align 4 .Last_neon: + st1.8 {$xa0-$xd0},[sp] + sub $out,$out,#1 add $inp,$inp,$len add $out,$out,$len @@ -685,9 +800,41 @@ $code.=<<___; .size ChaCha20_neon,.-ChaCha20_neon ___ { +my @K = map("v$_.4s",(0..6)); my ($T0,$T1,$T2,$T3,$T4,$T5)=@K; my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2, - $A3,$B3,$C3,$D3,$A4,$B4,$C4,$D4,$A5,$B5,$C5,$D5) = map("v$_.4s",(0..23)); + $A3,$B3,$C3,$D3,$A4,$B4,$C4,$D4,$A5,$B5,$C5,$D5) = map("v$_.4s",(8..31)); +my $rot24 = @K[6]; +my $ONE = "v7.4s"; + +sub NEONROUND { +my $odd = pop; +my ($a,$b,$c,$d,$t)=@_; + + ( + "&add ('$a','$a','$b')", + "&eor ('$d','$d','$a')", + "&rev32_16 ('$d','$d')", # vrot ($d,16) + + "&add ('$c','$c','$d')", + "&eor ('$t','$b','$c')", + "&ushr ('$b','$t',20)", + "&sli ('$b','$t',12)", + + "&add ('$a','$a','$b')", + "&eor ('$d','$d','$a')", + "&tbl ('$d','{$d}','$rot24')", + + "&add ('$c','$c','$d')", + "&eor ('$t','$b','$c')", + "&ushr ('$b','$t',25)", + "&sli ('$b','$t',7)", + + "&ext ('$c','$c','$c',8)", + "&ext ('$d','$d','$d',$odd?4:12)", + "&ext ('$b','$b','$b',$odd?12:4)" + ); +} $code.=<<___; .type ChaCha20_512_neon,%function @@ -707,6 +854,7 @@ ChaCha20_512_neon: .L512_or_more_neon: sub sp,sp,#128+64 + eor $ONE,$ONE,$ONE ldp @d[0],@d[1],[@x[0]] // load sigma ld1 {@K[0]},[@x[0]],#16 ldp @d[2],@d[3],[$key] // load key @@ -714,8 +862,9 @@ ChaCha20_512_neon: ld1 {@K[1],@K[2]},[$key] ldp @d[6],@d[7],[$ctr] // load counter ld1 {@K[3]},[$ctr] - ld1 {$ONE},[@x[0]] -#ifdef __ARMEB__ + ld1 {$ONE}[0],[@x[0]] + add $key,@x[0],#16 // .Lrot24 +#ifdef __AARCH64EB__ rev64 @K[0],@K[0] ror @d[2],@d[2],#32 ror @d[3],@d[3],#32 @@ -782,9 +931,10 @@ ChaCha20_512_neon: mov $C4,@K[2] stp @K[3],@K[4],[sp,#48] // off-load key block, variable part mov $C5,@K[2] - str @K[5],[sp,#80] + stp @K[5],@K[6],[sp,#80] mov $ctr,#5 + ld1 {$rot24},[$key] subs $len,$len,#512 .Loop_upper_neon: sub $ctr,$ctr,#1 @@ -857,7 +1007,7 @@ $code.=<<___; add @x[14],@x[14],@x[15],lsl#32 ldp @x[13],@x[15],[$inp,#48] add $inp,$inp,#64 -#ifdef __ARMEB__ +#ifdef __AARCH64EB__ rev @x[0],@x[0] rev @x[2],@x[2] rev @x[4],@x[4] @@ -946,6 +1096,7 @@ $code.=<<___; add.32 @x[2],@x[2],@d[1] ldp @K[4],@K[5],[sp,#64] add @x[3],@x[3],@d[1],lsr#32 + ldr @K[6],[sp,#96] add $A0,$A0,@K[0] add.32 @x[4],@x[4],@d[2] add $A1,$A1,@K[0] @@ -998,7 +1149,7 @@ $code.=<<___; add $inp,$inp,#64 add $B5,$B5,@K[1] -#ifdef __ARMEB__ +#ifdef __AARCH64EB__ rev @x[0],@x[0] rev @x[2],@x[2] rev @x[4],@x[4] @@ -1076,24 +1227,24 @@ $code.=<<___; b.hs .Loop_outer_512_neon adds $len,$len,#512 - ushr $A0,$ONE,#2 // 4 -> 1 + ushr $ONE,$ONE,#1 // 4 -> 2 ldp d8,d9,[sp,#128+0] // meet ABI requirements ldp d10,d11,[sp,#128+16] ldp d12,d13,[sp,#128+32] ldp d14,d15,[sp,#128+48] - stp @K[0],$ONE,[sp,#0] // wipe off-load area - stp @K[0],$ONE,[sp,#32] - stp @K[0],$ONE,[sp,#64] + stp @K[0],@K[0],[sp,#0] // wipe off-load area + stp @K[0],@K[0],[sp,#32] + stp @K[0],@K[0],[sp,#64] b.eq .Ldone_512_neon + sub $key,$key,#16 // .Lone cmp $len,#192 - sub @K[3],@K[3],$A0 // -= 1 - sub @K[4],@K[4],$A0 - sub @K[5],@K[5],$A0 add sp,sp,#128 + sub @K[3],@K[3],$ONE // -= 2 + ld1 {$CTR,$ROT24},[$key] b.hs .Loop_outer_neon eor @K[1],@K[1],@K[1] @@ -1123,9 +1274,11 @@ foreach (split("\n",$code)) { s/\`([^\`]*)\`/eval $1/geo; (s/\b([a-z]+)\.32\b/$1/ and (s/x([0-9]+)/w$1/g or 1)) or - (m/\b(eor|ext|mov)\b/ and (s/\.4s/\.16b/g or 1)) or + (m/\b(eor|ext|mov|tbl)\b/ and (s/\.4s/\.16b/g or 1)) or (s/\b((?:ld|st)1)\.8\b/$1/ and (s/\.4s/\.16b/g or 1)) or (m/\b(ld|st)[rp]\b/ and (s/v([0-9]+)\.4s/q$1/g or 1)) or + (m/\b(dup|ld1)\b/ and (s/\.4(s}?\[[0-3]\])/.$1/g or 1)) or + (s/\b(zip[12])\.64\b/$1/ and (s/\.4s/\.2d/g or 1)) or (s/\brev32\.16\b/rev32/ and (s/\.4s/\.8h/g or 1)); #s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo; diff --git a/crypto/chacha/asm/chacha-s390x.pl b/crypto/chacha/asm/chacha-s390x.pl index 51efe644..1f22b261 100755 --- a/crypto/chacha/asm/chacha-s390x.pl +++ b/crypto/chacha/asm/chacha-s390x.pl @@ -40,7 +40,7 @@ use strict; use FindBin qw($Bin); use lib "$Bin/../.."; -use perlasm::s390x qw(:DEFAULT :VX AUTOLOAD LABEL INCLUDE); +use perlasm::s390x qw(:DEFAULT :VX :LD AUTOLOAD LABEL INCLUDE); my $flavour = shift; diff --git a/crypto/cversion.c b/crypto/cversion.c index db25fd66..aef84e9c 100644 --- a/crypto/cversion.c +++ b/crypto/cversion.c @@ -69,6 +69,12 @@ const char *OpenSSL_version(int t) return "ENGINESDIR: \"" ENGINESDIR "\""; #else return "ENGINESDIR: N/A"; +#endif + case OPENSSL_MODULES_DIR: +#ifdef MODULESDIR + return "MODULESDIR: \"" MODULESDIR "\""; +#else + return "MODULESDIR: N/A"; #endif } return "not available"; diff --git a/crypto/ec/asm/ecp_nistz256-armv8.pl b/crypto/ec/asm/ecp_nistz256-armv8.pl index 8914f1a6..4daa8cc0 100644 --- a/crypto/ec/asm/ecp_nistz256-armv8.pl +++ b/crypto/ec/asm/ecp_nistz256-armv8.pl @@ -1488,7 +1488,7 @@ $code.=<<___; //////////////////////////////////////////////////////////////////////// // void ecp_nistz256_ord_sqr_mont(uint64_t res[4], uint64_t a[4], -// int rep); +// uint64_t rep); .globl ecp_nistz256_ord_sqr_mont .type ecp_nistz256_ord_sqr_mont,%function .align 4 diff --git a/crypto/ec/asm/ecp_nistz256-ppc64.pl b/crypto/ec/asm/ecp_nistz256-ppc64.pl index b1cd190c..c06a7c0d 100755 --- a/crypto/ec/asm/ecp_nistz256-ppc64.pl +++ b/crypto/ec/asm/ecp_nistz256-ppc64.pl @@ -1919,7 +1919,7 @@ $code.=<<___; ################################################################################ # void ecp_nistz256_ord_sqr_mont(uint64_t res[4], uint64_t a[4], -# int rep); +# uint64_t rep); .globl ecp_nistz256_ord_sqr_mont .align 5 ecp_nistz256_ord_sqr_mont: diff --git a/crypto/ec/asm/ecp_nistz256-x86_64.pl b/crypto/ec/asm/ecp_nistz256-x86_64.pl index a28ee8e9..e1e23ca9 100755 --- a/crypto/ec/asm/ecp_nistz256-x86_64.pl +++ b/crypto/ec/asm/ecp_nistz256-x86_64.pl @@ -826,7 +826,7 @@ $code.=<<___; # void ecp_nistz256_ord_sqr_mont( # uint64_t res[4], # uint64_t a[4], -# int rep); +# uint64_t rep); .globl ecp_nistz256_ord_sqr_mont .type ecp_nistz256_ord_sqr_mont,\@function,3 diff --git a/crypto/ec/ec_mult.c b/crypto/ec/ec_mult.c index 755d6440..968125f3 100644 --- a/crypto/ec/ec_mult.c +++ b/crypto/ec/ec_mult.c @@ -441,7 +441,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, * scalar multiplication implementation based on a Montgomery ladder, * with various timing attack defenses. */ - if ((scalar != NULL) && (num == 0)) { + if ((scalar != group->order) && (scalar != NULL) && (num == 0)) { /*- * In this case we want to compute scalar * GeneratorPoint: this * codepath is reached most prominently by (ephemeral) key @@ -452,7 +452,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, */ return ec_scalar_mul_ladder(group, r, scalar, NULL, ctx); } - if ((scalar == NULL) && (num == 1)) { + if ((scalar == NULL) && (num == 1) && (scalars[0] != group->order)) { /*- * In this case we want to compute scalar * VariablePoint: this * codepath is reached most prominently by the second half of ECDH, diff --git a/crypto/ec/ecp_nistz256.c b/crypto/ec/ecp_nistz256.c index 6a64bc4f..66bf4ecb 100644 --- a/crypto/ec/ecp_nistz256.c +++ b/crypto/ec/ecp_nistz256.c @@ -1467,7 +1467,7 @@ void ecp_nistz256_ord_mul_mont(BN_ULONG res[P256_LIMBS], const BN_ULONG b[P256_LIMBS]); void ecp_nistz256_ord_sqr_mont(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS], - int rep); + BN_ULONG rep); static int ecp_nistz256_inv_mod_ord(const EC_GROUP *group, BIGNUM *r, const BIGNUM *x, BN_CTX *ctx) diff --git a/crypto/err/err.c b/crypto/err/err.c index 45488545..345d2302 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -66,6 +66,7 @@ static ERR_STRING_DATA ERR_str_libraries[] = { {ERR_PACK(ERR_LIB_OSSL_STORE, 0, 0), "STORE routines"}, {ERR_PACK(ERR_LIB_SM2, 0, 0), "SM2 routines"}, {ERR_PACK(ERR_LIB_ESS, 0, 0), "ESS routines"}, + {ERR_PACK(ERR_LIB_PROV, 0, 0), "Provider routines"}, {0, NULL}, }; diff --git a/crypto/err/err_all.c b/crypto/err/err_all.c index 1166b01c..af44467e 100644 --- a/crypto/err/err_all.c +++ b/crypto/err/err_all.c @@ -41,6 +41,7 @@ #include #include #include "internal/propertyerr.h" +#include "internal/providercommonerr.h" int err_load_crypto_strings_int(void) { @@ -102,7 +103,8 @@ int err_load_crypto_strings_int(void) #endif ERR_load_KDF_strings() == 0 || ERR_load_OSSL_STORE_strings() == 0 || - ERR_load_PROP_strings() == 0) + ERR_load_PROP_strings() == 0 || + ERR_load_PROV_strings() == 0) return 0; return 1; diff --git a/crypto/err/openssl.ec b/crypto/err/openssl.ec index a204434f..b28aa491 100644 --- a/crypto/err/openssl.ec +++ b/crypto/err/openssl.ec @@ -37,6 +37,7 @@ L SM2 crypto/include/internal/sm2.h crypto/sm2/sm2_err.c L OSSL_STORE include/openssl/store.h crypto/store/store_err.c L ESS include/openssl/ess.h crypto/ess/ess_err.c L PROP include/internal/property.h crypto/property/property_err.c +L PROV providers/common/include/internal/providercommon.h providers/common/provider_err.c # additional header files to be scanned for function names L NONE include/openssl/x509_vfy.h NONE diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index f7117f16..fba529cf 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -785,6 +785,9 @@ EVP_F_EVP_CIPHER_ASN1_TO_PARAM:204:EVP_CIPHER_asn1_to_param EVP_F_EVP_CIPHER_CTX_COPY:163:EVP_CIPHER_CTX_copy EVP_F_EVP_CIPHER_CTX_CTRL:124:EVP_CIPHER_CTX_ctrl EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH:122:EVP_CIPHER_CTX_set_key_length +EVP_F_EVP_CIPHER_CTX_SET_PADDING:237:EVP_CIPHER_CTX_set_padding +EVP_F_EVP_CIPHER_FROM_DISPATCH:238:evp_cipher_from_dispatch +EVP_F_EVP_CIPHER_MODE:239:EVP_CIPHER_mode EVP_F_EVP_CIPHER_PARAM_TO_ASN1:205:EVP_CIPHER_param_to_asn1 EVP_F_EVP_DECRYPTFINAL_EX:101:EVP_DecryptFinal_ex EVP_F_EVP_DECRYPTUPDATE:166:EVP_DecryptUpdate @@ -1102,6 +1105,21 @@ PROP_F_PARSE_NUMBER:104:parse_number PROP_F_PARSE_OCT:105:parse_oct PROP_F_PARSE_STRING:106:parse_string PROP_F_PARSE_UNQUOTED:107:parse_unquoted +PROV_F_AESNI_INIT_KEY:101:aesni_init_key +PROV_F_AES_BLOCK_FINAL:102:aes_block_final +PROV_F_AES_BLOCK_UPDATE:103:aes_block_update +PROV_F_AES_CIPHER:104:aes_cipher +PROV_F_AES_CTX_GET_PARAMS:105:aes_ctx_get_params +PROV_F_AES_CTX_SET_PARAMS:106:aes_ctx_set_params +PROV_F_AES_DINIT:107:aes_dinit +PROV_F_AES_DUPCTX:108:aes_dupctx +PROV_F_AES_EINIT:109:aes_einit +PROV_F_AES_INIT_KEY:110:aes_init_key +PROV_F_AES_STREAM_UPDATE:111:aes_stream_update +PROV_F_AES_T4_INIT_KEY:112:aes_t4_init_key +PROV_F_PROV_AES_KEY_GENERIC_INIT:113:PROV_AES_KEY_generic_init +PROV_F_TRAILINGDATA:114:trailingdata +PROV_F_UNPADBLOCK:100:unpadblock RAND_F_DRBG_BYTES:101:drbg_bytes RAND_F_DRBG_CTR_INIT:125:drbg_ctr_init RAND_F_DRBG_GET_ENTROPY:105:drbg_get_entropy @@ -2381,6 +2399,7 @@ EVP_R_INVALID_FIPS_MODE:168:invalid fips mode EVP_R_INVALID_KEY:163:invalid key EVP_R_INVALID_KEY_LENGTH:130:invalid key length EVP_R_INVALID_OPERATION:148:invalid operation +EVP_R_INVALID_PROVIDER_FUNCTIONS:193:invalid provider functions EVP_R_INVALID_SALT_LENGTH:186:invalid salt length EVP_R_KEYGEN_FAILURE:120:keygen failure EVP_R_KEY_SETUP_FAILED:180:key setup failed @@ -2604,6 +2623,14 @@ PROP_R_NO_VALUE:107:no value PROP_R_PARSE_FAILED:108:parse failed PROP_R_STRING_TOO_LONG:109:string too long PROP_R_TRAILING_CHARACTERS:110:trailing characters +PROV_R_AES_KEY_SETUP_FAILED:101:aes key setup failed +PROV_R_BAD_DECRYPT:100:bad decrypt +PROV_R_CIPHER_OPERATION_FAILED:102:cipher operation failed +PROV_R_FAILED_TO_GET_PARAMETER:103:failed to get parameter +PROV_R_FAILED_TO_SET_PARAMETER:104:failed to set parameter +PROV_R_INVALID_KEYLEN:105:invalid keylen +PROV_R_OUTPUT_BUFFER_TOO_SMALL:106:output buffer too small +PROV_R_WRONG_FINAL_BLOCK_LENGTH:107:wrong final block length RAND_R_ADDITIONAL_INPUT_TOO_LONG:102:additional input too long RAND_R_ALREADY_INSTANTIATED:103:already instantiated RAND_R_ARGUMENT_OUT_OF_RANGE:105:argument out of range diff --git a/crypto/evp/cmeth_lib.c b/crypto/evp/cmeth_lib.c index 6c328c0d..0520157c 100644 --- a/crypto/evp/cmeth_lib.c +++ b/crypto/evp/cmeth_lib.c @@ -11,6 +11,7 @@ #include #include "internal/evp_int.h" +#include "internal/provider.h" #include "evp_locl.h" EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len) @@ -21,6 +22,12 @@ EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len) cipher->nid = cipher_type; cipher->block_size = block_size; cipher->key_len = key_len; + cipher->lock = CRYPTO_THREAD_lock_new(); + if (cipher->lock == NULL) { + OPENSSL_free(cipher); + return NULL; + } + cipher->refcnt = 1; } return cipher; } @@ -30,14 +37,35 @@ EVP_CIPHER *EVP_CIPHER_meth_dup(const EVP_CIPHER *cipher) EVP_CIPHER *to = EVP_CIPHER_meth_new(cipher->nid, cipher->block_size, cipher->key_len); - if (to != NULL) + if (to != NULL) { + CRYPTO_RWLOCK *lock = to->lock; + memcpy(to, cipher, sizeof(*to)); + to->lock = lock; + } return to; } void EVP_CIPHER_meth_free(EVP_CIPHER *cipher) { - OPENSSL_free(cipher); + if (cipher != NULL) { + int i; + + CRYPTO_DOWN_REF(&cipher->refcnt, &i, cipher->lock); + if (i > 0) + return; + ossl_provider_free(cipher->prov); + CRYPTO_THREAD_lock_free(cipher->lock); + OPENSSL_free(cipher); + } +} + +int EVP_CIPHER_upref(EVP_CIPHER *cipher) +{ + int ref = 0; + + CRYPTO_UP_REF(&cipher->refcnt, &ref, cipher->lock); + return 1; } int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len) diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index 527c5d66..043e4562 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -295,6 +295,7 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize) { int ret; size_t size = 0; + size_t mdsize = EVP_MD_size(ctx->digest); if (ctx->digest == NULL || ctx->digest->prov == NULL) goto legacy; @@ -304,7 +305,7 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize) return 0; } - ret = ctx->digest->dfinal(ctx->provctx, md, &size); + ret = ctx->digest->dfinal(ctx->provctx, md, &size, mdsize); if (isize != NULL) { if (size <= UINT_MAX) { @@ -321,10 +322,10 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize) /* TODO(3.0): Remove legacy code below */ legacy: - OPENSSL_assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE); + OPENSSL_assert(mdsize <= EVP_MAX_MD_SIZE); ret = ctx->digest->final(ctx, md); if (isize != NULL) - *isize = ctx->digest->md_size; + *isize = mdsize; if (ctx->digest->cleanup) { ctx->digest->cleanup(ctx); EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); @@ -516,7 +517,7 @@ static void *evp_md_from_dispatch(int mdtype, const OSSL_DISPATCH *fns, md->dinit = OSSL_get_OP_digest_init(fns); fncnt++; break; - case OSSL_FUNC_DIGEST_UPDDATE: + case OSSL_FUNC_DIGEST_UPDATE: if (md->dupdate != NULL) break; md->dupdate = OSSL_get_OP_digest_update(fns); diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index 641ad197..676eaabb 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -15,25 +15,46 @@ #include #include #include +#include +#include #include "internal/evp_int.h" +#include "internal/provider.h" #include "evp_locl.h" -int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c) +int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) { - if (c == NULL) + if (ctx == NULL) return 1; - if (c->cipher != NULL) { - if (c->cipher->cleanup && !c->cipher->cleanup(c)) + + if (ctx->cipher == NULL || ctx->cipher->prov == NULL) + goto legacy; + + if (ctx->provctx != NULL) { + if (ctx->cipher->freectx != NULL) + ctx->cipher->freectx(ctx->provctx); + ctx->provctx = NULL; + } + if (ctx->fetched_cipher != NULL) + EVP_CIPHER_meth_free(ctx->fetched_cipher); + memset(ctx, 0, sizeof(*ctx)); + + return 1; + + /* TODO(3.0): Remove legacy code below */ + legacy: + + if (ctx->cipher != NULL) { + if (ctx->cipher->cleanup && !ctx->cipher->cleanup(ctx)) return 0; /* Cleanse cipher context data */ - if (c->cipher_data && c->cipher->ctx_size) - OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size); + if (ctx->cipher_data && ctx->cipher->ctx_size) + OPENSSL_cleanse(ctx->cipher_data, ctx->cipher->ctx_size); } - OPENSSL_free(c->cipher_data); + OPENSSL_free(ctx->cipher_data); #ifndef OPENSSL_NO_ENGINE - ENGINE_finish(c->engine); + ENGINE_finish(ctx->engine); #endif - memset(c, 0, sizeof(*c)); + memset(ctx, 0, sizeof(*ctx)); return 1; } @@ -60,13 +81,30 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc) { - if (enc == -1) + EVP_CIPHER *provciph = NULL; + ENGINE *tmpimpl = NULL; + const EVP_CIPHER *tmpcipher; + + /* + * enc == 1 means we are encrypting. + * enc == 0 means we are decrypting. + * enc == -1 means, use the previously initialised value for encrypt/decrypt + */ + if (enc == -1) { enc = ctx->encrypt; - else { + } else { if (enc) enc = 1; ctx->encrypt = enc; } + + if (cipher == NULL && ctx->cipher == NULL) { + EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_NO_CIPHER_SET); + return 0; + } + + /* TODO(3.0): Legacy work around code below. Remove this */ + #ifndef OPENSSL_NO_ENGINE /* * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so @@ -77,11 +115,161 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, if (ctx->engine && ctx->cipher && (cipher == NULL || cipher->nid == ctx->cipher->nid)) goto skip_to_init; + + if (cipher != NULL && impl == NULL) { + /* Ask if an ENGINE is reserved for this job */ + tmpimpl = ENGINE_get_cipher_engine(cipher->nid); + } #endif - if (cipher) { + + /* + * If there are engines involved then we should use legacy handling for now. + */ + if (ctx->engine != NULL + || impl != NULL + || tmpimpl != NULL) { + if (ctx->cipher == ctx->fetched_cipher) + ctx->cipher = NULL; + EVP_CIPHER_meth_free(ctx->fetched_cipher); + ctx->fetched_cipher = NULL; + goto legacy; + } + + tmpcipher = (cipher == NULL) ? ctx->cipher : cipher; + + if (tmpcipher->prov == NULL) { + switch(tmpcipher->nid) { + case NID_aes_256_ecb: + case NID_aes_192_ecb: + case NID_aes_128_ecb: + case NID_aes_256_cbc: + case NID_aes_192_cbc: + case NID_aes_128_cbc: + case NID_aes_256_ofb128: + case NID_aes_192_ofb128: + case NID_aes_128_ofb128: + case NID_aes_256_cfb128: + case NID_aes_192_cfb128: + case NID_aes_128_cfb128: + case NID_aes_256_cfb1: + case NID_aes_192_cfb1: + case NID_aes_128_cfb1: + case NID_aes_256_cfb8: + case NID_aes_192_cfb8: + case NID_aes_128_cfb8: + case NID_aes_256_ctr: + case NID_aes_192_ctr: + case NID_aes_128_ctr: + break; + default: + goto legacy; + } + } + + /* + * Ensure a context left lying around from last time is cleared + * (legacy code) + */ + if (cipher != NULL && ctx->cipher != NULL) { + OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size); + ctx->cipher_data = NULL; + } + + + /* TODO(3.0): Start of non-legacy code below */ + + /* Ensure a context left lying around from last time is cleared */ + if (cipher != NULL && ctx->cipher != NULL) { + unsigned long flags = ctx->flags; + + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } + + if (cipher != NULL) + ctx->cipher = cipher; + else + cipher = ctx->cipher; + + if (cipher->prov == NULL) { + provciph = EVP_CIPHER_fetch(NULL, OBJ_nid2sn(cipher->nid), ""); + if (provciph == NULL) { + EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR); + return 0; + } + cipher = provciph; + EVP_CIPHER_meth_free(ctx->fetched_cipher); + ctx->fetched_cipher = provciph; + } + + ctx->cipher = cipher; + if (ctx->provctx == NULL) { + ctx->provctx = ctx->cipher->newctx(); + if (ctx->provctx == NULL) { + EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { /* - * Ensure a context left lying around from last time is cleared (the - * previous check attempted to avoid this if the same ENGINE and + * If this ctx was already set up for no padding then we need to tell + * the new cipher about it. + */ + if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) + return 0; + } + + switch (EVP_CIPHER_mode(ctx->cipher)) { + case EVP_CIPH_CFB_MODE: + case EVP_CIPH_OFB_MODE: + case EVP_CIPH_CBC_MODE: + /* For these modes we remember the original IV for later use */ + if (!ossl_assert(EVP_CIPHER_CTX_iv_length(ctx) <= (int)sizeof(ctx->oiv))) { + EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR); + return 0; + } + if (iv != NULL) + memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + } + + if (enc) { + if (ctx->cipher->einit == NULL) { + EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->einit(ctx->provctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_iv_length(ctx)); + } + + if (ctx->cipher->dinit == NULL) { + EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->dinit(ctx->provctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_iv_length(ctx)); + + /* TODO(3.0): Remove legacy code below */ + legacy: + + if (cipher != NULL) { + /* + * Ensure a context left lying around from last time is cleared (we + * previously attempted to avoid this if the same ENGINE and * EVP_CIPHER could be used). */ if (ctx->cipher) { @@ -92,18 +280,19 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ctx->flags = flags; } #ifndef OPENSSL_NO_ENGINE - if (impl) { + if (impl != NULL) { if (!ENGINE_init(impl)) { EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR); return 0; } - } else - /* Ask if an ENGINE is reserved for this job */ - impl = ENGINE_get_cipher_engine(cipher->nid); - if (impl) { + } else { + impl = tmpimpl; + } + if (impl != NULL) { /* There's an ENGINE for this job ... (apparently) */ const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid); - if (!c) { + + if (c == NULL) { /* * One positive side-effect of US's export control history, * is that we should at least be able to avoid using US @@ -119,8 +308,9 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, * from an ENGINE and we need to release it when done. */ ctx->engine = impl; - } else + } else { ctx->engine = NULL; + } #endif ctx->cipher = cipher; @@ -144,9 +334,6 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, return 0; } } - } else if (!ctx->cipher) { - EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_NO_CIPHER_SET); - return 0; } #ifndef OPENSSL_NO_ENGINE skip_to_init: @@ -377,12 +564,39 @@ static int evp_EncryptDecryptUpdate(EVP_CIPHER_CTX *ctx, int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) { + int ret; + size_t soutl; + int blocksize; + /* Prevent accidental use of decryption context when encrypting */ if (!ctx->encrypt) { EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_INVALID_OPERATION); return 0; } + if (ctx->cipher == NULL || ctx->cipher->prov == NULL) + goto legacy; + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (ctx->cipher->cupdate == NULL || blocksize < 1) { + EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_UPDATE_ERROR); + return 0; + } + ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, + inl + (blocksize == 1 ? 0 : blocksize), in, + (size_t)inl); + + if (soutl > INT_MAX) { + EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_UPDATE_ERROR); + return 0; + } + *outl = soutl; + return ret; + + /* TODO(3.0): Remove legacy code below */ + legacy: + return evp_EncryptDecryptUpdate(ctx, out, outl, in, inl); } @@ -397,6 +611,8 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) { int n, ret; unsigned int i, b, bl; + size_t soutl; + int blocksize; /* Prevent accidental use of decryption context when encrypting */ if (!ctx->encrypt) { @@ -404,6 +620,30 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) return 0; } + if (ctx->cipher == NULL || ctx->cipher->prov == NULL) + goto legacy; + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (blocksize < 1 || ctx->cipher->cfinal == NULL) { + EVPerr(EVP_F_EVP_ENCRYPTFINAL_EX, EVP_R_FINAL_ERROR); + return 0; + } + + ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl, + blocksize == 1 ? 0 : blocksize); + + if (soutl > INT_MAX) { + EVPerr(EVP_F_EVP_ENCRYPTFINAL_EX, EVP_R_FINAL_ERROR); + return 0; + } + *outl = soutl; + + return ret; + + /* TODO(3.0): Remove legacy code below */ + legacy: + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { ret = ctx->cipher->do_cipher(ctx, out, NULL, 0); if (ret < 0) @@ -444,8 +684,10 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) { - int fix_len, cmpl = inl; + int fix_len, cmpl = inl, ret; unsigned int b; + size_t soutl; + int blocksize; /* Prevent accidental use of encryption context when decrypting */ if (ctx->encrypt) { @@ -453,6 +695,32 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, return 0; } + if (ctx->cipher == NULL || ctx->cipher->prov == NULL) + goto legacy; + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (ctx->cipher->cupdate == NULL || blocksize < 1) { + EVPerr(EVP_F_EVP_DECRYPTUPDATE, EVP_R_UPDATE_ERROR); + return 0; + } + ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, + inl + (blocksize == 1 ? 0 : blocksize), in, + (size_t)inl); + + if (ret) { + if (soutl > INT_MAX) { + EVPerr(EVP_F_EVP_DECRYPTUPDATE, EVP_R_UPDATE_ERROR); + return 0; + } + *outl = soutl; + } + + return ret; + + /* TODO(3.0): Remove legacy code below */ + legacy: + b = ctx->cipher->block_size; if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) @@ -527,6 +795,9 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) { int i, n; unsigned int b; + size_t soutl; + int ret; + int blocksize; /* Prevent accidental use of encryption context when decrypting */ if (ctx->encrypt) { @@ -534,6 +805,32 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) return 0; } + if (ctx->cipher == NULL || ctx->cipher->prov == NULL) + goto legacy; + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + if (blocksize < 1 || ctx->cipher->cfinal == NULL) { + EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_FINAL_ERROR); + return 0; + } + + ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl, + blocksize == 1 ? 0 : blocksize); + + if (ret) { + if (soutl > INT_MAX) { + EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_FINAL_ERROR); + return 0; + } + *outl = soutl; + } + + return ret; + + /* TODO(3.0): Remove legacy code below */ + legacy: + *outl = 0; if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { @@ -590,7 +887,7 @@ int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen) { if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH) return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH, keylen, NULL); - if (c->key_len == keylen) + if (EVP_CIPHER_CTX_key_length(c) == keylen) return 1; if ((keylen > 0) && (c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) { c->key_len = keylen; @@ -606,6 +903,24 @@ int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) ctx->flags &= ~EVP_CIPH_NO_PADDING; else ctx->flags |= EVP_CIPH_NO_PADDING; + + if (ctx->cipher != NULL && ctx->cipher->prov != NULL) { + OSSL_PARAM params[] = { + OSSL_PARAM_int(OSSL_CIPHER_PARAM_PADDING, NULL), + OSSL_PARAM_END + }; + + params[0].data = &pad; + + if (ctx->cipher->ctx_set_params == NULL) { + EVPerr(EVP_F_EVP_CIPHER_CTX_SET_PADDING, EVP_R_CTRL_NOT_IMPLEMENTED); + return 0; + } + + if (!ctx->cipher->ctx_set_params(ctx->provctx, params)) + return 0; + } + return 1; } @@ -636,7 +951,7 @@ int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key) { if (ctx->cipher->flags & EVP_CIPH_RAND_KEY) return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key); - if (RAND_priv_bytes(key, ctx->key_len) <= 0) + if (RAND_priv_bytes(key, EVP_CIPHER_CTX_key_length(ctx)) <= 0) return 0; return 1; } @@ -647,6 +962,36 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, EVP_R_INPUT_NOT_INITIALIZED); return 0; } + + if (in->cipher->prov == NULL) + goto legacy; + + if (in->cipher->dupctx == NULL) { + EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, EVP_R_NOT_ABLE_TO_COPY_CTX); + return 0; + } + + EVP_CIPHER_CTX_reset(out); + + *out = *in; + out->provctx = NULL; + + if (in->fetched_cipher != NULL && !EVP_CIPHER_upref(in->fetched_cipher)) { + out->fetched_cipher = NULL; + return 0; + } + + out->provctx = in->cipher->dupctx(in->provctx); + if (out->provctx == NULL) { + EVPerr(EVP_F_EVP_CIPHER_CTX_COPY, EVP_R_NOT_ABLE_TO_COPY_CTX); + return 0; + } + + return 1; + + /* TODO(3.0): Remove legacy code below */ + legacy: + #ifndef OPENSSL_NO_ENGINE /* Make sure it's safe to copy a cipher context using an ENGINE */ if (in->engine && !ENGINE_init(in->engine)) { @@ -676,3 +1021,141 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) } return 1; } + +static void *evp_cipher_from_dispatch(int nid, const OSSL_DISPATCH *fns, + OSSL_PROVIDER *prov) +{ + EVP_CIPHER *cipher = NULL; + int fnciphcnt = 0, fnctxcnt = 0; + + if ((cipher = EVP_CIPHER_meth_new(nid, 0, 0)) == NULL) + return NULL; + + for (; fns->function_id != 0; fns++) { + switch (fns->function_id) { + case OSSL_FUNC_CIPHER_NEWCTX: + if (cipher->newctx != NULL) + break; + cipher->newctx = OSSL_get_OP_cipher_newctx(fns); + fnctxcnt++; + break; + case OSSL_FUNC_CIPHER_ENCRYPT_INIT: + if (cipher->einit != NULL) + break; + cipher->einit = OSSL_get_OP_cipher_encrypt_init(fns); + fnciphcnt++; + break; + case OSSL_FUNC_CIPHER_DECRYPT_INIT: + if (cipher->dinit != NULL) + break; + cipher->dinit = OSSL_get_OP_cipher_decrypt_init(fns); + fnciphcnt++; + break; + case OSSL_FUNC_CIPHER_UPDATE: + if (cipher->cupdate != NULL) + break; + cipher->cupdate = OSSL_get_OP_cipher_update(fns); + fnciphcnt++; + break; + case OSSL_FUNC_CIPHER_FINAL: + if (cipher->cfinal != NULL) + break; + cipher->cfinal = OSSL_get_OP_cipher_final(fns); + fnciphcnt++; + break; + case OSSL_FUNC_CIPHER_CIPHER: + if (cipher->ccipher != NULL) + break; + cipher->ccipher = OSSL_get_OP_cipher_cipher(fns); + break; + case OSSL_FUNC_CIPHER_FREECTX: + if (cipher->freectx != NULL) + break; + cipher->freectx = OSSL_get_OP_cipher_freectx(fns); + fnctxcnt++; + break; + case OSSL_FUNC_CIPHER_DUPCTX: + if (cipher->dupctx != NULL) + break; + cipher->dupctx = OSSL_get_OP_cipher_dupctx(fns); + break; + case OSSL_FUNC_CIPHER_KEY_LENGTH: + if (cipher->key_length != NULL) + break; + cipher->key_length = OSSL_get_OP_cipher_key_length(fns); + break; + case OSSL_FUNC_CIPHER_IV_LENGTH: + if (cipher->iv_length != NULL) + break; + cipher->iv_length = OSSL_get_OP_cipher_iv_length(fns); + break; + case OSSL_FUNC_CIPHER_BLOCK_SIZE: + if (cipher->blocksize != NULL) + break; + cipher->blocksize = OSSL_get_OP_cipher_block_size(fns); + break; + case OSSL_FUNC_CIPHER_GET_PARAMS: + if (cipher->get_params != NULL) + break; + cipher->get_params = OSSL_get_OP_cipher_get_params(fns); + break; + case OSSL_FUNC_CIPHER_CTX_GET_PARAMS: + if (cipher->ctx_get_params != NULL) + break; + cipher->ctx_get_params = OSSL_get_OP_cipher_ctx_get_params(fns); + break; + case OSSL_FUNC_CIPHER_CTX_SET_PARAMS: + if (cipher->ctx_set_params != NULL) + break; + cipher->ctx_set_params = OSSL_get_OP_cipher_ctx_set_params(fns); + break; + } + } + if ((fnciphcnt != 0 && fnciphcnt != 3 && fnciphcnt != 4) + || (fnciphcnt == 0 && cipher->ccipher == NULL) + || fnctxcnt != 2 + || cipher->blocksize == NULL + || cipher->iv_length == NULL + || cipher->key_length == NULL) { + /* + * In order to be a consistent set of functions we must have at least + * a complete set of "encrypt" functions, or a complete set of "decrypt" + * functions, or a single "cipher" function. In all cases we need a + * complete set of context management functions, as well as the + * blocksize, iv_length and key_length functions. + */ + EVP_CIPHER_meth_free(cipher); + EVPerr(EVP_F_EVP_CIPHER_FROM_DISPATCH, EVP_R_INVALID_PROVIDER_FUNCTIONS); + return NULL; + } + cipher->prov = prov; + if (prov != NULL) + ossl_provider_upref(prov); + + return cipher; +} + +static int evp_cipher_upref(void *cipher) +{ + return EVP_CIPHER_upref(cipher); +} + +static void evp_cipher_free(void *cipher) +{ + EVP_CIPHER_meth_free(cipher); +} + +static int evp_cipher_nid(void *vcipher) +{ + EVP_CIPHER *cipher = vcipher; + + return cipher->nid; +} + +EVP_CIPHER *EVP_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm, + const char *properties) +{ + return evp_generic_fetch(ctx, OSSL_OP_CIPHER, algorithm, properties, + evp_cipher_from_dispatch, evp_cipher_upref, + evp_cipher_free, evp_cipher_nid); +} diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index a9f8800b..3555c0e5 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -53,6 +53,11 @@ static const ERR_STRING_DATA EVP_str_functs[] = { "EVP_CIPHER_CTX_ctrl"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH, 0), "EVP_CIPHER_CTX_set_key_length"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_CIPHER_CTX_SET_PADDING, 0), + "EVP_CIPHER_CTX_set_padding"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_CIPHER_FROM_DISPATCH, 0), + "evp_cipher_from_dispatch"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_CIPHER_MODE, 0), "EVP_CIPHER_mode"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_CIPHER_PARAM_TO_ASN1, 0), "EVP_CIPHER_param_to_asn1"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, 0), @@ -246,6 +251,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_KEY), "invalid key"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_KEY_LENGTH), "invalid key length"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_OPERATION), "invalid operation"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PROVIDER_FUNCTIONS), + "invalid provider functions"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SALT_LENGTH), "invalid salt length"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYGEN_FAILURE), "keygen failure"}, diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c index 012383f0..c054f311 100644 --- a/crypto/evp/evp_fetch.c +++ b/crypto/evp/evp_fetch.c @@ -173,11 +173,15 @@ void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id, void (*free_method)(void *), int (*nid_method)(void *)) { + OSSL_METHOD_STORE *store = get_default_method_store(libctx); int nid = OBJ_sn2nid(algorithm); void *method = NULL; + if (store == NULL) + return NULL; + if (nid == NID_undef - || !ossl_method_store_cache_get(NULL, nid, properties, &method)) { + || !ossl_method_store_cache_get(store, nid, properties, &method)) { OSSL_METHOD_CONSTRUCT_METHOD mcm = { alloc_tmp_method_store, dealloc_tmp_method_store, @@ -198,7 +202,9 @@ void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id, method = ossl_method_construct(libctx, operation_id, algorithm, properties, 0 /* !force_cache */, &mcm, &mcmdata); - ossl_method_store_cache_set(NULL, nid, properties, method); + ossl_method_store_cache_set(store, nid, properties, method); + } else { + upref_method(method); } return method; diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c index 914a19cc..189c9532 100644 --- a/crypto/evp/evp_lib.c +++ b/crypto/evp/evp_lib.c @@ -11,6 +11,8 @@ #include "internal/cryptlib.h" #include #include +#include +#include #include "internal/evp_int.h" #include "internal/provider.h" #include "evp_locl.h" @@ -18,13 +20,28 @@ int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type) { int ret; + const EVP_CIPHER *cipher = c->cipher; - if (c->cipher->set_asn1_parameters != NULL) - ret = c->cipher->set_asn1_parameters(c, type); - else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) { - switch (EVP_CIPHER_CTX_mode(c)) { + if (cipher->prov != NULL) { + /* + * The cipher has come from a provider and won't have the default flags. + * Find the implicit form so we can check the flags. + * TODO(3.0): This won't work for 3rd party ciphers we know nothing about + * We'll need to think of something else for those. + */ + cipher = EVP_get_cipherbynid(cipher->nid); + if (cipher == NULL) { + EVPerr(EVP_F_EVP_CIPHER_PARAM_TO_ASN1, ASN1_R_UNSUPPORTED_CIPHER); + return -1; + } + } + + if (cipher->set_asn1_parameters != NULL) + ret = cipher->set_asn1_parameters(c, type); + else if (cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) { + switch (EVP_CIPHER_mode(cipher)) { case EVP_CIPH_WRAP_MODE: - if (EVP_CIPHER_CTX_nid(c) == NID_id_smime_alg_CMS3DESwrap) + if (EVP_CIPHER_nid(cipher) == NID_id_smime_alg_CMS3DESwrap) ASN1_TYPE_set(type, V_ASN1_NULL, NULL); ret = 1; break; @@ -53,11 +70,22 @@ int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type) int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type) { int ret; + const EVP_CIPHER *cipher = c->cipher; - if (c->cipher->get_asn1_parameters != NULL) - ret = c->cipher->get_asn1_parameters(c, type); - else if (c->cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) { - switch (EVP_CIPHER_CTX_mode(c)) { + if (cipher->prov != NULL) { + /* + * The cipher has come from a provider and won't have the default flags. + * Find the implicit form so we can check the flags. + */ + cipher = EVP_get_cipherbynid(cipher->nid); + if (cipher == NULL) + return -1; + } + + if (cipher->get_asn1_parameters != NULL) + ret = cipher->get_asn1_parameters(c, type); + else if (cipher->flags & EVP_CIPH_FLAG_DEFAULT_ASN1) { + switch (EVP_CIPHER_mode(cipher)) { case EVP_CIPH_WRAP_MODE: ret = 1; @@ -85,19 +113,23 @@ int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type) return ret; } -int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type) +int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *ctx, ASN1_TYPE *type) { int i = 0; unsigned int l; if (type != NULL) { - l = EVP_CIPHER_CTX_iv_length(c); - OPENSSL_assert(l <= sizeof(c->iv)); - i = ASN1_TYPE_get_octetstring(type, c->oiv, l); + unsigned char iv[EVP_MAX_IV_LENGTH]; + + l = EVP_CIPHER_CTX_iv_length(ctx); + if (!ossl_assert(l <= sizeof(iv))) + return -1; + i = ASN1_TYPE_get_octetstring(type, iv, l); if (i != (int)l) return -1; - else if (i > 0) - memcpy(c->iv, c->oiv, l); + + if (!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, -1)) + return -1; } return i; } @@ -175,14 +207,20 @@ int EVP_CIPHER_type(const EVP_CIPHER *ctx) } } -int EVP_CIPHER_block_size(const EVP_CIPHER *e) +int EVP_CIPHER_block_size(const EVP_CIPHER *cipher) { - return e->block_size; + if (cipher->prov != NULL) { + if (cipher->blocksize != NULL) + return cipher->blocksize(); + /* We default to a block size of 1 */ + return 1; + } + return cipher->block_size; } int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) { - return ctx->cipher->block_size; + return EVP_CIPHER_block_size(ctx->cipher); } int EVP_CIPHER_impl_ctx_size(const EVP_CIPHER *e) @@ -193,6 +231,12 @@ int EVP_CIPHER_impl_ctx_size(const EVP_CIPHER *e) int EVP_Cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl) { + if (ctx->cipher->prov != NULL) { + if (ctx->cipher->ccipher != NULL) + return ctx->cipher->ccipher(ctx->provctx, out, in, (size_t)inl); + return 0; + } + return ctx->cipher->do_cipher(ctx, out, in, inl); } @@ -238,12 +282,18 @@ void *EVP_CIPHER_CTX_set_cipher_data(EVP_CIPHER_CTX *ctx, void *cipher_data) int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher) { + if (cipher->prov != NULL) { + if (cipher->iv_length != NULL) + return (int)cipher->iv_length(); + return 0; + } + return cipher->iv_len; } int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) { - return ctx->cipher->iv_len; + return EVP_CIPHER_iv_length(ctx->cipher); } const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx) @@ -278,11 +328,23 @@ void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num) int EVP_CIPHER_key_length(const EVP_CIPHER *cipher) { + if (cipher->prov != NULL) { + if (cipher->key_length != NULL) + return (int)cipher->key_length(); + return -1; + } + return cipher->key_len; } int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) { + /* + * TODO(3.0): This may need to change if/when we introduce variable length + * key ciphers into the providers. + */ + if (ctx->cipher != NULL && ctx->cipher->prov != NULL) + return EVP_CIPHER_key_length(ctx->cipher); return ctx->key_len; } @@ -296,6 +358,33 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) return ctx->cipher->nid; } +int EVP_CIPHER_mode(const EVP_CIPHER *cipher) +{ + if (cipher->prov != NULL) { + int mode; + + /* Cipher comes from a provider - so ask the provider for the mode */ + OSSL_PARAM params[] = { + OSSL_PARAM_int(OSSL_CIPHER_PARAM_MODE, NULL), + OSSL_PARAM_END + }; + + params[0].data = &mode; + + if (cipher->get_params == NULL) { + EVPerr(EVP_F_EVP_CIPHER_MODE, EVP_R_CTRL_NOT_IMPLEMENTED); + return 0; + } + + if (!cipher->get_params(params)) + return 0; + + return mode; + } + return EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE; +} + + int EVP_MD_block_size(const EVP_MD *md) { if (md == NULL) { @@ -353,12 +442,16 @@ EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type) } return md; } + EVP_MD *EVP_MD_meth_dup(const EVP_MD *md) { EVP_MD *to = EVP_MD_meth_new(md->type, md->pkey_type); - if (to != NULL) + if (to != NULL) { + CRYPTO_RWLOCK *lock = to->lock; memcpy(to, md, sizeof(*to)); + to->lock = lock; + } return to; } diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index efa2db8f..3172c497 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -44,6 +44,10 @@ struct evp_cipher_ctx_st { int final_used; int block_mask; unsigned char final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */ + + /* Provider ctx */ + void *provctx; + EVP_CIPHER *fetched_cipher; } /* EVP_CIPHER_CTX */ ; struct evp_mac_ctx_st { diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h index c9328981..b3d96946 100644 --- a/crypto/include/internal/evp_int.h +++ b/crypto/include/internal/evp_int.h @@ -210,10 +210,14 @@ struct evp_md_st { struct evp_cipher_st { int nid; + int block_size; /* Default value for variable length ciphers */ int key_len; int iv_len; + + /* Legacy structure members */ + /* TODO(3.0): Remove these */ /* Various flags */ unsigned long flags; /* init key */ @@ -234,6 +238,26 @@ struct evp_cipher_st { int (*ctrl) (EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Application data */ void *app_data; + + /* New structure members */ + /* TODO(3.0): Remove above comment when legacy has gone */ + OSSL_PROVIDER *prov; + CRYPTO_REF_COUNT refcnt; + CRYPTO_RWLOCK *lock; + OSSL_OP_cipher_newctx_fn *newctx; + OSSL_OP_cipher_encrypt_init_fn *einit; + OSSL_OP_cipher_decrypt_init_fn *dinit; + OSSL_OP_cipher_update_fn *cupdate; + OSSL_OP_cipher_final_fn *cfinal; + OSSL_OP_cipher_cipher_fn *ccipher; + OSSL_OP_cipher_freectx_fn *freectx; + OSSL_OP_cipher_dupctx_fn *dupctx; + OSSL_OP_cipher_key_length_fn *key_length; + OSSL_OP_cipher_iv_length_fn *iv_length; + OSSL_OP_cipher_block_size_fn *blocksize; + OSSL_OP_cipher_get_params_fn *get_params; + OSSL_OP_cipher_ctx_get_params_fn *ctx_get_params; + OSSL_OP_cipher_ctx_set_params_fn *ctx_set_params; } /* EVP_CIPHER */ ; /* Macros to code block cipher wrappers */ diff --git a/crypto/info.c b/crypto/info.c new file mode 100644 index 00000000..5a929ddd --- /dev/null +++ b/crypto/info.c @@ -0,0 +1,44 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include "internal/dso_conf.h" +#include "e_os.h" + +const char *OPENSSL_info(int t) +{ + switch (t) { + case OPENSSL_INFO_CONFIG_DIR: + return OPENSSLDIR; + case OPENSSL_INFO_ENGINES_DIR: + return ENGINESDIR; + case OPENSSL_INFO_MODULES_DIR: + return MODULESDIR; + case OPENSSL_INFO_DSO_EXTENSION: + return DSO_EXTENSION; + case OPENSSL_INFO_DIR_FILENAME_SEPARATOR: +#if defined(_WIN32) + return "\\"; +#elif defined(__VMS) + return ""; +#else /* Assume POSIX */ + return "/"; +#endif + case OPENSSL_INFO_LIST_SEPARATOR: + { + static const char list_sep[] = { LIST_SEPARATOR_CHAR, '\0' }; + return list_sep; + } + default: + break; + } + /* Not an error */ + return NULL; +} diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c index aa0ca1c9..e3c7ac45 100644 --- a/crypto/lhash/lhash.c +++ b/crypto/lhash/lhash.c @@ -98,6 +98,7 @@ void OPENSSL_LH_flush(OPENSSL_LHASH *lh) OPENSSL_free(n); n = nn; } + lh->b[i] = NULL; } } diff --git a/crypto/modes/asm/ghashv8-armx.pl b/crypto/modes/asm/ghashv8-armx.pl index e8915833..fbc49d1c 100644 --- a/crypto/modes/asm/ghashv8-armx.pl +++ b/crypto/modes/asm/ghashv8-armx.pl @@ -42,6 +42,7 @@ # Denver 0.51 0.65 6.02 # Mongoose 0.65 1.10 8.06 # Kryo 0.76 1.16 8.00 +# ThunderX2 1.05 # # (*) presented for reference/comparison purposes; diff --git a/crypto/modes/ccm128.c b/crypto/modes/ccm128.c index 9edf0270..bfa2d460 100644 --- a/crypto/modes/ccm128.c +++ b/crypto/modes/ccm128.c @@ -425,7 +425,7 @@ size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len) M *= 2; M += 2; - if (len < M) + if (len != M) return 0; memcpy(tag, ctx->cmac.c, M); return M; diff --git a/crypto/perlasm/s390x.pm b/crypto/perlasm/s390x.pm index 5f3a49dd..7fb55c78 100644 --- a/crypto/perlasm/s390x.pm +++ b/crypto/perlasm/s390x.pm @@ -6,23 +6,37 @@ # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html -# Copyright IBM Corp. 2018 +# Copyright IBM Corp. 2018-2019 # Author: Patrick Steuer package perlasm::s390x; use strict; use warnings; +use bigint; use Carp qw(confess); use Exporter qw(import); our @EXPORT=qw(PERLASM_BEGIN PERLASM_END); our @EXPORT_OK=qw(AUTOLOAD LABEL INCLUDE stfle); our %EXPORT_TAGS=( + # long-displacement facility + LD => [qw(clgfi)], + # general-instruction-extension facility + GE => [qw(risbg)], + # extended-immediate facility + EI => [qw(lt)], + # miscellaneous-instruction-extensions facility 1 + MI1 => [qw(risbgn)], + # message-security assist MSA => [qw(kmac km kmc kimd klmd)], + # message-security-assist extension 4 MSA4 => [qw(kmf kmo pcc kmctr)], + # message-security-assist extension 5 MSA5 => [qw(ppno prno)], + # message-security-assist extension 8 MSA8 => [qw(kma)], + # vector facility VX => [qw(vgef vgeg vgbm vzero vone vgm vgmb vgmh vgmf vgmg vl vlr vlrep vlrepb vlreph vlrepf vlrepg vleb vleh vlef vleg vleib vleih vleif vleig vlgv vlgvb vlgvh vlgvf vlgvg vllez vllezb vllezh @@ -71,6 +85,7 @@ our %EXPORT_TAGS=( wfmadb vfms vfmsdb wfmsdb vfpso vfpsodb wfpsodb vflcdb wflcdb vflndb wflndb vflpdb wflpdb vfsq vfsqdb wfsqdb vfs vfsdb wfsdb vftci vftcidb wftcidb)], + # vector-enhancements facility 1 VXE => [qw(vbperm vllezlf vmsl vmslg vnx vnn voc vpopctb vpopcth vpopctf vpopctg vfasb wfasb wfaxb wfcsb wfcxb wfksb wfkxb vfcesb vfcesbs wfcesb wfcesbs wfcexb wfcexbs vfchsb vfchsbs wfchsb wfchsbs @@ -83,10 +98,11 @@ our %EXPORT_TAGS=( wfnmsxb vfpsosb wfpsosb vflcsb wflcsb vflnsb wflnsb vflpsb wflpsb vfpsoxb wfpsoxb vflcxb wflcxb vflnxb wflnxb vflpxb wflpxb vfsqsb wfsqsb wfsqxb vfssb wfssb wfsxb vftcisb wftcisb wftcixb)], + # vector-packed-decimal facility VXD => [qw(vlrlr vlrl vstrlr vstrl vap vcp vcvb vcvbg vcvd vcvdg vdp vlip vmp vmsp vpkz vpsop vrp vsdp vsrp vsp vtp vupkz)], ); -Exporter::export_ok_tags(qw(MSA MSA4 MSA5 MSA8 VX VXE VXD)); +Exporter::export_ok_tags(qw(LD GE EI MI1 MSA MSA4 MSA5 MSA8 VX VXE VXD)); our $AUTOLOAD; @@ -143,6 +159,28 @@ sub stfle { S(0xb2b0,@_); } +# MISC + +sub clgfi { + confess(err("ARGNUM")) if ($#_!=1); + RILa(0xc2e,@_); +} + +sub lt { + confess(err("ARGNUM")) if ($#_!=1); + RXYa(0xe312,@_); +} + +sub risbg { + confess(err("ARGNUM")) if ($#_<3||$#_>4); + RIEf(0xec55,@_); +} + +sub risbgn { + confess(err("ARGNUM")) if ($#_<3||$#_>4); + RIEf(0xec59,@_); +} + # MSA sub kmac { @@ -250,7 +288,7 @@ sub vgmg { } sub vl { - confess(err("ARGNUM")) if ($#_!=1); + confess(err("ARGNUM")) if ($#_<1||$#_>2); VRX(0xe706,@_); } @@ -345,7 +383,7 @@ sub vllezg { } sub vlm { - confess(err("ARGNUM")) if ($#_!=2); + confess(err("ARGNUM")) if ($#_<2||$#_>3); VRSa(0xe736,@_); } @@ -548,7 +586,7 @@ sub vsegf { } sub vst { - confess(err("ARGNUM")) if ($#_!=1); + confess(err("ARGNUM")) if ($#_<1||$#_>2); VRX(0xe70e,@_); } @@ -570,7 +608,7 @@ sub vsteg { } sub vstm { - confess(err("ARGNUM")) if ($#_!=2); + confess(err("ARGNUM")) if ($#_<2||$#_>3); VRSa(0xe73e,@_); } @@ -2486,6 +2524,36 @@ sub vupkz { # Instruction Formats # +sub RIEf { + confess(err("ARGNUM")) if ($#_<4||5<$#_); + my $ops=join(',',@_[1..$#_]); + my $memn=(caller(1))[3]; + $memn=~s/^.*:://; + my ($opcode,$r1,$r2,$i3,$i4,$i5)=(shift,get_R(shift),get_R(shift), + get_I(shift,8),get_I(shift,8), + get_I(shift,8)); + + $out.="\t.word\t"; + $out.=sprintf("%#06x",(($opcode>>8)<<8|$r1<<4|$r2)).","; + $out.=sprintf("%#06x",($i3<<8)|$i4).","; + $out.=sprintf("%#06x",($i5<<8)|($opcode&0xff)); + $out.="\t# $memn\t$ops\n" +} + +sub RILa { + confess(err("ARGNUM")) if ($#_!=2); + my $ops=join(',',@_[1..$#_]); + my $memn=(caller(1))[3]; + $memn=~s/^.*:://; + my ($opcode,$r1,$i2)=(shift,get_R(shift),get_I(shift,32)); + + $out.="\t.word\t"; + $out.=sprintf("%#06x",(($opcode>>4)<<8|$r1<<4|($opcode&0xf))).","; + $out.=sprintf("%#06x",($i2>>16)).","; + $out.=sprintf("%#06x",($i2&0xffff)); + $out.="\t# $memn\t$ops\n" +} + sub RRE { confess(err("ARGNUM")) if ($#_<0||2<$#_); my $ops=join(',',@_[1..$#_]); @@ -2510,6 +2578,20 @@ sub RRFb { $out.="\t# $memn\t$ops\n" } +sub RXYa { + confess(err("ARGNUM")) if ($#_!=2); + my $ops=join(',',@_[1..$#_]); + my $memn=(caller(1))[3]; + $memn=~s/^.*:://; + my ($opcode,$r1,$d2,$x2,$b2)=(shift,get_R(shift),get_DXB(shift)); + + $out.="\t.word\t"; + $out.=sprintf("%#06x",(($opcode>>8)<<8|$r1<<4|$x2)).","; + $out.=sprintf("%#06x",($b2<<12|($d2&0xfff))).","; + $out.=sprintf("%#06x",(($d2>>12)<<8|$opcode&0xff)); + $out.="\t# $memn\t$ops\n" +} + sub S { confess(err("ARGNUM")) if ($#_<0||1<$#_); my $ops=join(',',@_[1..$#_]); diff --git a/crypto/poly1305/asm/poly1305-armv8.pl b/crypto/poly1305/asm/poly1305-armv8.pl index b7aa7dc9..b5dd61e1 100755 --- a/crypto/poly1305/asm/poly1305-armv8.pl +++ b/crypto/poly1305/asm/poly1305-armv8.pl @@ -29,6 +29,7 @@ # X-Gene 2.13/+68% 2.27 # Mongoose 1.77/+75% 1.12 # Kryo 2.70/+55% 1.13 +# ThunderX2 1.17/+95% 1.36 # # (*) estimate based on resources availability is less than 1.0, # i.e. measured result is worse than expected, presumably binary diff --git a/crypto/poly1305/asm/poly1305-s390x.pl b/crypto/poly1305/asm/poly1305-s390x.pl index ea1c2d82..73efdd9e 100755 --- a/crypto/poly1305/asm/poly1305-s390x.pl +++ b/crypto/poly1305/asm/poly1305-s390x.pl @@ -45,7 +45,7 @@ use strict; use FindBin qw($Bin); use lib "$Bin/../.."; -use perlasm::s390x qw(:DEFAULT :VX AUTOLOAD LABEL INCLUDE); +use perlasm::s390x qw(:DEFAULT :LD :GE :EI :MI1 :VX AUTOLOAD LABEL INCLUDE); my $flavour = shift; diff --git a/crypto/property/property.c b/crypto/property/property.c index 1a3d0c48..a2122dc1 100644 --- a/crypto/property/property.c +++ b/crypto/property/property.c @@ -450,7 +450,7 @@ int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, int nid, return 0; } - elem.query = prop_query; + elem.query = prop_query != NULL ? prop_query : ""; r = lh_QUERY_retrieve(alg->cache, &elem); if (r == NULL) { ossl_property_unlock(store); diff --git a/crypto/rand/rand_crng_test.c b/crypto/rand/rand_crng_test.c index 74a64ee5..87f4ee1f 100644 --- a/crypto/rand/rand_crng_test.c +++ b/crypto/rand/rand_crng_test.c @@ -30,7 +30,7 @@ int rand_crngt_get_entropy_cb(unsigned char *buf) while ((n = rand_pool_acquire_entropy(crngt_pool)) != 0) if (n >= CRNGT_BUFSIZ) { p = rand_pool_detach(crngt_pool); - memcpy(crngt_prev, p, CRNGT_BUFSIZ); + memcpy(buf, p, CRNGT_BUFSIZ); rand_pool_reattach(crngt_pool, p); return 1; } diff --git a/crypto/rsa/rsa_oaep.c b/crypto/rsa/rsa_oaep.c index 9affabb9..0945d4f6 100644 --- a/crypto/rsa/rsa_oaep.c +++ b/crypto/rsa/rsa_oaep.c @@ -38,6 +38,13 @@ int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, param, plen, NULL, NULL); } +/* + * Perform ihe padding as per NIST 800-56B 7.2.2.3 + * from (K) is the key material. + * param (A) is the additional input. + * Step numbers are included here but not in the constant time inverse below + * to avoid complicating an already difficult enough function. + */ int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, const unsigned char *from, int flen, const unsigned char *param, int plen, @@ -57,6 +64,7 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, mdlen = EVP_MD_size(md); + /* step 2b: check KLen > nLen - 2 HLen - 2 */ if (flen > emlen - 2 * mdlen - 1) { RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); @@ -69,15 +77,20 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, return 0; } + /* step 3i: EM = 00000000 || maskedMGF || maskedDB */ to[0] = 0; seed = to + 1; db = to + mdlen + 1; + /* step 3a: hash the additional input */ if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL)) goto err; + /* step 3b: zero bytes array of length nLen - KLen - 2 HLen -2 */ memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1); + /* step 3c: DB = HA || PS || 00000001 || K */ db[emlen - flen - mdlen - 1] = 0x01; memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen); + /* step 3d: generate random byte string */ if (RAND_bytes(seed, mdlen) <= 0) goto err; @@ -88,13 +101,17 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, goto err; } + /* step 3e: dbMask = MGF(mgfSeed, nLen - HLen - 1) */ if (PKCS1_MGF1(dbmask, dbmask_len, seed, mdlen, mgf1md) < 0) goto err; + /* step 3f: maskedDB = DB XOR dbMask */ for (i = 0; i < dbmask_len; i++) db[i] ^= dbmask[i]; + /* step 3g: mgfSeed = MGF(maskedDB, HLen) */ if (PKCS1_MGF1(seedmask, mdlen, db, dbmask_len, mgf1md) < 0) goto err; + /* stepo 3h: maskedMGFSeed = mgfSeed XOR mgfSeedMask */ for (i = 0; i < mdlen; i++) seed[i] ^= seedmask[i]; rv = 1; @@ -270,6 +287,13 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, return constant_time_select_int(good, mlen, -1); } +/* + * Mask Generation Function corresponding to section 7.2.2.2 of NIST SP 800-56B. + * The variables are named differently to NIST: + * mask (T) and len (maskLen)are the returned mask. + * seed (mgfSeed). + * The range checking steps inm the process are performed outside. + */ int PKCS1_MGF1(unsigned char *mask, long len, const unsigned char *seed, long seedlen, const EVP_MD *dgst) { @@ -285,11 +309,14 @@ int PKCS1_MGF1(unsigned char *mask, long len, mdlen = EVP_MD_size(dgst); if (mdlen < 0) goto err; + /* step 4 */ for (i = 0; outlen < len; i++) { + /* step 4a: D = I2BS(counter, 4) */ cnt[0] = (unsigned char)((i >> 24) & 255); cnt[1] = (unsigned char)((i >> 16) & 255); cnt[2] = (unsigned char)((i >> 8)) & 255; cnt[3] = (unsigned char)(i & 255); + /* step 4b: T =T || hash(mgfSeed || D) */ if (!EVP_DigestInit_ex(c, dgst, NULL) || !EVP_DigestUpdate(c, seed, seedlen) || !EVP_DigestUpdate(c, cnt, 4)) diff --git a/crypto/sha/asm/keccak1600-armv8.pl b/crypto/sha/asm/keccak1600-armv8.pl index bd15a52a..dc72f18b 100755 --- a/crypto/sha/asm/keccak1600-armv8.pl +++ b/crypto/sha/asm/keccak1600-armv8.pl @@ -51,6 +51,7 @@ # Kryo 12 # Denver 7.8 # Apple A7 7.2 +# ThunderX2 9.7 # # (*) Corresponds to SHA3-256. No improvement coefficients are listed # because they vary too much from compiler to compiler. Newer diff --git a/crypto/sha/asm/sha1-armv8.pl b/crypto/sha/asm/sha1-armv8.pl index 7a0cbf53..12403eb7 100644 --- a/crypto/sha/asm/sha1-armv8.pl +++ b/crypto/sha/asm/sha1-armv8.pl @@ -27,6 +27,7 @@ # X-Gene 8.80 (+200%) # Mongoose 2.05 6.50 (+160%) # Kryo 1.88 8.00 (+90%) +# ThunderX2 2.64 6.36 (+150%) # # (*) Software results are presented mostly for reference purposes. # (**) Keep in mind that Denver relies on binary translation, which diff --git a/crypto/sha/asm/sha512-armv8.pl b/crypto/sha/asm/sha512-armv8.pl index f7c67219..b9ba05ba 100644 --- a/crypto/sha/asm/sha512-armv8.pl +++ b/crypto/sha/asm/sha512-armv8.pl @@ -28,6 +28,7 @@ # X-Gene 20.0 (+100%) 12.8 (+300%(***)) # Mongoose 2.36 13.0 (+50%) 8.36 (+33%) # Kryo 1.92 17.4 (+30%) 11.2 (+8%) +# ThunderX2 2.54 13.2 (+40%) 8.40 (+18%) # # (*) Software SHA256 results are of lesser relevance, presented # mostly for informational purposes. diff --git a/doc/man1/info.pod b/doc/man1/info.pod new file mode 100644 index 00000000..6eddf0fa --- /dev/null +++ b/doc/man1/info.pod @@ -0,0 +1,81 @@ +=pod + +=head1 NAME + +openssl-info, +info - print OpenSSL built-in information + +=head1 SYNOPSIS + +B +[B<-help>] +[B<-configdir> | B<-c>] +[B<-enginesdir> | B<-e>] +[B<-modulesdir> | B<-m>] +[B<-dsoext>] +[B<-dirfilesep>] +[B<-listsep]> + +=head1 DESCRIPTION + +This command is used to print out information about OpenSSL. +The information is written exactly as it is with no extra text, which +makes useful for scripts. + +As a consequence, only one item may be chosen for each run of this +command. + +=head1 OPTIONS + +=over 4 + +=item B<-help> + +Print out a usage message. + +=item B<-configdir>, B<-c> + +Outputs the default directory for OpenSSL configuration files. + +=item B<-enginesdir>, B<-e> + +Outputs the default directory for OpenSSL engine modules. + +=item B<-modulesdir>, B<-m> + +Outputs the default directory for OpenSSL dynamically loadable modules +other than engine modules. + +=item B<-dsoext> + +Outputs the DSO extension OpenSSL uses. + +=item B<-dirnamesep> + +Outputs the separator character between a directory specification and +a file name. +Note that on some operating systems, this is not the same as the +separator between directory elements. + +=item B<-listsep> + +Outputs the OpenSSL list separator character. +This is typically used to construct C<$PATH> (C<%PATH%> on Windows) +style lists. + +=back + +=head1 HISTORY + +The B command was added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man1/kdf.pod b/doc/man1/kdf.pod new file mode 100644 index 00000000..0ff7762b --- /dev/null +++ b/doc/man1/kdf.pod @@ -0,0 +1,167 @@ +=pod + +=head1 NAME + +openssl-kdf, +kdf - perform Key Derivation Function operations + +=head1 SYNOPSIS + +B +[B<-help>] +[B<-kdfopt> I] +[B<-keylen> I] +[B<-out> I] +[B<-binary>] +I + +=head1 DESCRIPTION + +The key derivation functions generate a derived key from either a secret or +password. + +=head1 OPTIONS + +=over 4 + +=item B<-help> + +Print a usage message. + +=item B<-keylen> I + +The output size of the derived key. This field is required. + +=item B<-out> I + +Filename to output to, or standard output by default. + +=item B<-binary> + +Output the derived key in binary form. Uses hexadecimal text format if not specified. + +=item B<-kdfopt> I + +Passes options to the KDF algorithm. +A comprehensive list of controls can be found in the EVP_KDF_CTX implementation +documentation. +Common control strings used by EVP_KDF_ctrl_str() are: + +=over 4 + +=item BI + +Specifies the secret key as an alphanumeric string (use if the key contains +printable characters only). +The string length must conform to any restrictions of the KDF algorithm. +A key must be specified for most KDF algorithms. + +=item BI + +Specifies the secret key in hexadecimal form (two hex digits per byte). +The key length must conform to any restrictions of the KDF algorithm. +A key must be specified for most KDF algorithms. + +=item BI + +Specifies the password as an alphanumeric string (use if the password contains +printable characters only). +The password must be specified for PBKDF2 and scrypt. + +=item BI + +Specifies the password in hexadecimal form (two hex digits per byte). +The password must be specified for PBKDF2 and scrypt. + +=item BI + +Specifies the name of a digest as an alphanumeric string. +To see the list of supported digests, use the command I. + +=back + +=item I + +Specifies the name of a supported KDF algorithm which will be used. +The supported algorithms names are TLS1-PRF, HKDF, SSKDF, PBKDF2, SSHKDF and id-scrypt. + +=back + +=head1 EXAMPLES + +Use TLS1-PRF to create a hex-encoded derived key from a secret key and seed: + + openssl kdf -keylen 16 -kdfopt digest:SHA256 -kdfopt key:secret \ + -kdfopt seed:seed TLS1-PRF + +Use HKDF to create a hex-encoded derived key from a secret key, salt and info: + + openssl kdf -keylen 10 -kdfopt digest:SHA256 -kdfopt key:secret \ + -kdfopt salt:salt -kdfopt info:label HKDF + +Use SSKDF with KMAC to create a hex-encoded derived key from a secret key, salt and info: + + openssl kdf -keylen 64 -kdfopt mac:KMAC128 -kdfopt maclen:20 \ + -kdfopt hexkey:b74a149a161545 -kdfopt hexinfo:348a37a2 \ + -kdfopt hexsalt:3638271ccd68a2 SSKDF + +Use SSKDF with HMAC to create a hex-encoded derived key from a secret key, salt and info: + + openssl kdf -keylen 16 -kdfopt mac:HMAC -kdfopt digest:SHA256 \ + -kdfopt hexkey:b74a149a -kdfopt hexinfo:348a37a2 \ + -kdfopt hexsalt:3638271c SSKDF + +Use SSKDF with Hash to create a hex-encoded derived key from a secret key, salt and info: + + openssl kdf -keylen 14 -kdfopt digest:SHA256 \ + -kdfopt hexkey:6dbdc23f045488 \ + -kdfopt hexinfo:a1b2c3d4 SSKDF + +Use SSHKDF to create a hex-encoded derived key from a secret key, hash and session_id: + + openssl kdf -keylen 16 -kdfopt digest:SHA256 \ + -kdfopt hexkey:0102030405 \ + -kdfopt hexxcghash:06090A \ + -kdfopt hexsession_id:01020304 \ + -kdfopt type:A SSHKDF + +Use PBKDF2 to create a hex-encoded derived key from a password and salt: + + openssl kdf -keylen 32 -kdfopt digest:SHA256 -kdfopt pass:password \ + -kdfopt salt:salt -kdfopt iter:2 PBKDF2 + +Use scrypt to create a hex-encoded derived key from a password and salt: + + openssl kdf -keylen 64 -kdfopt pass:password -kdfopt salt:NaCl \ + -kdfopt N:1024 -kdfopt r:8 -kdfopt p:16 \ + -kdfopt maxmem_bytes:10485760 id-scrypt + +=head1 NOTES + +The KDF mechanisms that are available will depend on the options +used when building OpenSSL. + +=head1 SEE ALSO + +L, +L +L +L +L +L +L + +=head1 HISTORY + +Added in OpenSSL 3.0 + +=head1 COPYRIGHT + +Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the OpenSSL license (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man1/openssl.pod b/doc/man1/openssl.pod index 5f6f8d3b..41d04da2 100644 --- a/doc/man1/openssl.pod +++ b/doc/man1/openssl.pod @@ -167,6 +167,14 @@ Generation of Private Key or Parameters. Generation of RSA Private Key. Superseded by L. +=item B + +Display diverse information built into the OpenSSL libraries. + +=item B + +Key Derivation Functions. + =item B Message Authentication Code Calculation. @@ -612,7 +620,7 @@ L, L, L, L, L, L, L, L, L, L, L, L, L, -L, L, L, L, +L, L, L, L, L, L, L, L, L, L, L, L, L, @@ -632,7 +640,7 @@ manual pages. =head1 COPYRIGHT -Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-2019 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man3/BIO_s_mem.pod b/doc/man3/BIO_s_mem.pod index bd0824a0..6d9e747b 100644 --- a/doc/man3/BIO_s_mem.pod +++ b/doc/man3/BIO_s_mem.pod @@ -88,6 +88,22 @@ a buffering BIO to the chain will speed up the process. Calling BIO_set_mem_buf() on a BIO created with BIO_new_secmem() will give undefined results, including perhaps a program crash. +Switching the memory BIO from read write to read only is not supported and +can give undefined results including a program crash. There are two notable +exceptions to the rule. The first one is to assign a static memory buffer +immediately after BIO creation and set the BIO as read only. + +The other supported sequence is to start with read write BIO then temporarily +switch it to read only and call BIO_reset() on the read only BIO immediately +before switching it back to read write. Before the BIO is freed it must be +switched back to the read write mode. + +Calling BIO_get_mem_ptr() on read only BIO will return a BUF_MEM that +contains only the remaining data to be read. If the close status of the +BIO is set to BIO_NOCLOSE, before freeing the BUF_MEM the data pointer +in it must be set to NULL as the data pointer does not point to an +allocated memory. + =head1 BUGS There should be an option to set the maximum size of a memory BIO. diff --git a/doc/man3/ECDSA_SIG_new.pod b/doc/man3/ECDSA_SIG_new.pod index f37005d8..e99a8237 100644 --- a/doc/man3/ECDSA_SIG_new.pod +++ b/doc/man3/ECDSA_SIG_new.pod @@ -200,7 +200,7 @@ ANSI X9.62, US Federal Information Processing Standard FIPS 186-2 =head1 SEE ALSO -L, +L, L, L diff --git a/doc/man3/EVP_KDF_CTX.pod b/doc/man3/EVP_KDF_CTX.pod index 4ca8d94b..f6465283 100644 --- a/doc/man3/EVP_KDF_CTX.pod +++ b/doc/man3/EVP_KDF_CTX.pod @@ -151,9 +151,9 @@ The value string is expected to be the name of a MAC. This control expects one argument: C For MAC implementations that use a message digest as an underlying computation -algorithm, this control set what the digest algorithm should be. +algorithm, this control sets what the digest algorithm should be. -EVP_KDF_ctrl_str() type string: "md" +EVP_KDF_ctrl_str() type string: "digest" The value string is expected to be the name of a digest. @@ -232,6 +232,7 @@ L L L L +L =head1 HISTORY diff --git a/doc/man3/EVP_chacha20.pod b/doc/man3/EVP_chacha20.pod index 7b014c26..5218ee21 100644 --- a/doc/man3/EVP_chacha20.pod +++ b/doc/man3/EVP_chacha20.pod @@ -21,7 +21,15 @@ The ChaCha20 stream cipher for EVP. =item EVP_chacha20() -The ChaCha20 stream cipher. The key length is 256 bits, the IV is 96 bits long. +The ChaCha20 stream cipher. The key length is 256 bits, the IV is 128 bits long. +The first 32 bits consists of a counter in little-endian order followed by a 96 +bit nonce. For example a nonce of: + +000000000000000000000002 + +With an initial counter of 42 (2a in hex) would be expressed as: + +2a000000000000000000000000000002 =item EVP_chacha20_poly1305() diff --git a/doc/man3/OpenSSL_version.pod b/doc/man3/OpenSSL_version.pod index 679273e6..c1ced643 100644 --- a/doc/man3/OpenSSL_version.pod +++ b/doc/man3/OpenSSL_version.pod @@ -8,8 +8,8 @@ OPENSSL_VERSION_PRE_RELEASE_STR, OPENSSL_VERSION_BUILD_METADATA_STR, OPENSSL_VERSION_TEXT, OPENSSL_version_major, OPENSSL_version_minor, OPENSSL_version_patch, OPENSSL_version_pre_release, OPENSSL_version_build_metadata, OpenSSL_version, -OPENSSL_VERSION_NUMBER, OpenSSL_version_num -- get OpenSSL version number +OPENSSL_VERSION_NUMBER, OpenSSL_version_num, OPENSSL_info +- get OpenSSL version number and other information =head1 SYNOPSIS @@ -37,6 +37,8 @@ OPENSSL_VERSION_NUMBER, OpenSSL_version_num const char *OpenSSL_version(int t); + const char *OPENSSL_info(int t); + Deprecated: /* from openssl/opensslv.h */ @@ -127,6 +129,47 @@ if available or "ENGINESDIR: N/A" otherwise. For an unknown B, the text "not available" is returned. +OPENSSL_info() also returns different strings depending on B: + +=over 4 + +=item OPENSSL_INFO_CONFIG_DIR + +The configured C, which is the default location for +OpenSSL configuration files. + +=item OPENSSL_INFO_ENGINES_DIR + +The configured C, which is the default location for +OpenSSL engines. + +=item OPENSSL_INFO_MODULES_DIR + +The configured C, which is the default location for +dynamically loadable OpenSSL modules other than engines. + +=item OPENSSL_INFO_DSO_EXTENSION + +The configured dynamically loadable module extension. + +=item OPENSSL_INFO_DIR_FILENAME_SEPARATOR + +The separator between a directory specification and a file name. +Note that on some operating systems, this is not the same as the +separator between directory elements. + +=item OPENSSL_INFO_LIST_SEPARATOR + +The OpenSSL list separator. +This is typically used in strings that are lists of items, such as the +value of the environment variable C<$PATH> on Unix (where the +separator is ":") or C<%PATH%> on Windows (where the separator is +";"). + +=back + +For an unknown B, NULL is returned. + =head1 BACKWARD COMPATIBILITY For compatibility, some older macros and functions are retained or diff --git a/doc/man3/SSL_CTX_set_client_hello_cb.pod b/doc/man3/SSL_CTX_set_client_hello_cb.pod index b8dad37a..74e168dc 100644 --- a/doc/man3/SSL_CTX_set_client_hello_cb.pod +++ b/doc/man3/SSL_CTX_set_client_hello_cb.pod @@ -65,6 +65,8 @@ both required, and on success the caller must release the storage allocated for B<*out> using OPENSSL_free(). The contents of B<*out> is an array of integers holding the numerical value of the TLS extension types in the order they appear in the ClientHello. B<*outlen> contains the number of elements in the array. +In situations when the ClientHello has no extensions, the function will return +success with B<*out> set to NULL and B<*outlen> set to 0. =head1 NOTES diff --git a/include/internal/ktls.h b/include/internal/ktls.h index 5495a8de..d7bd1f3b 100644 --- a/include/internal/ktls.h +++ b/include/internal/ktls.h @@ -90,6 +90,10 @@ static ossl_inline int ktls_read_record(int fd, void *data, size_t length) # define TCP_ULP 31 # endif +# ifndef TLS_RX +# define TLS_RX 2 +# endif + /* * When successful, this socket option doesn't change the behaviour of the * TCP socket, except changing the TCP setsockopt handler to enable the diff --git a/include/openssl/bio.h b/include/openssl/bio.h index 85cbe0ae..66e0b96b 100644 --- a/include/openssl/bio.h +++ b/include/openssl/bio.h @@ -152,13 +152,20 @@ extern "C" { * # define BIO_CTRL_CLEAR_KTLS_CTRL_MSG 75 */ -# define BIO_CTRL_GET_KTLS_SEND 73 -# define BIO_CTRL_GET_KTLS_RECV 76 +# define BIO_CTRL_GET_KTLS_SEND 73 +# define BIO_CTRL_GET_KTLS_RECV 76 +# ifndef OPENSSL_NO_KTLS # define BIO_get_ktls_send(b) \ - BIO_ctrl(b, BIO_CTRL_GET_KTLS_SEND, 0, NULL) + (BIO_method_type(b) == BIO_TYPE_SOCKET \ + && BIO_ctrl(b, BIO_CTRL_GET_KTLS_SEND, 0, NULL)) # define BIO_get_ktls_recv(b) \ - BIO_ctrl(b, BIO_CTRL_GET_KTLS_RECV, 0, NULL) + (BIO_method_type(b) == BIO_TYPE_SOCKET \ + && BIO_ctrl(b, BIO_CTRL_GET_KTLS_RECV, 0, NULL)) +# else +# define BIO_get_ktls_send(b) (0) +# define BIO_get_ktls_recv(b) (0) +# endif /* modifiers */ # define BIO_FP_READ 0x02 diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index be4a6478..35a23d74 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -34,6 +34,12 @@ extern "C" { */ #define OSSL_PROV_PARAM_BUILDINFO "buildinfo" + +/* Well known cipher parameters */ + +#define OSSL_CIPHER_PARAM_PADDING "padding" +#define OSSL_CIPHER_PARAM_MODE "mode" + # ifdef __cplusplus } # endif diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index 1e536277..d5888860 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -78,7 +78,7 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ALGORITHM *,provider_query_operation, # define OSSL_FUNC_DIGEST_NEWCTX 1 # define OSSL_FUNC_DIGEST_INIT 2 -# define OSSL_FUNC_DIGEST_UPDDATE 3 +# define OSSL_FUNC_DIGEST_UPDATE 3 # define OSSL_FUNC_DIGEST_FINAL 4 # define OSSL_FUNC_DIGEST_DIGEST 5 # define OSSL_FUNC_DIGEST_FREECTX 6 @@ -86,21 +86,74 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ALGORITHM *,provider_query_operation, # define OSSL_FUNC_DIGEST_SIZE 8 # define OSSL_FUNC_DIGEST_BLOCK_SIZE 9 + OSSL_CORE_MAKE_FUNC(void *, OP_digest_newctx, (void)) OSSL_CORE_MAKE_FUNC(int, OP_digest_init, (void *vctx)) OSSL_CORE_MAKE_FUNC(int, OP_digest_update, (void *, const unsigned char *in, size_t inl)) OSSL_CORE_MAKE_FUNC(int, OP_digest_final, - (void *, unsigned char *out, size_t *outl)) + (void *, unsigned char *out, size_t *outl, size_t outsz)) OSSL_CORE_MAKE_FUNC(int, OP_digest_digest, (const unsigned char *in, size_t inl, unsigned char *out, - size_t *out_l)) + size_t *out_l, size_t outsz)) + OSSL_CORE_MAKE_FUNC(void, OP_digest_cleanctx, (void *vctx)) OSSL_CORE_MAKE_FUNC(void, OP_digest_freectx, (void *vctx)) OSSL_CORE_MAKE_FUNC(void *, OP_digest_dupctx, (void *vctx)) OSSL_CORE_MAKE_FUNC(size_t, OP_digest_size, (void)) OSSL_CORE_MAKE_FUNC(size_t, OP_digest_block_size, (void)) + +/* Symmetric Ciphers */ + +# define OSSL_OP_CIPHER 2 + +# define OSSL_FUNC_CIPHER_NEWCTX 1 +# define OSSL_FUNC_CIPHER_ENCRYPT_INIT 2 +# define OSSL_FUNC_CIPHER_DECRYPT_INIT 3 +# define OSSL_FUNC_CIPHER_UPDATE 4 +# define OSSL_FUNC_CIPHER_FINAL 5 +# define OSSL_FUNC_CIPHER_CIPHER 6 +# define OSSL_FUNC_CIPHER_FREECTX 7 +# define OSSL_FUNC_CIPHER_DUPCTX 8 +# define OSSL_FUNC_CIPHER_KEY_LENGTH 9 +# define OSSL_FUNC_CIPHER_IV_LENGTH 10 +# define OSSL_FUNC_CIPHER_BLOCK_SIZE 11 +# define OSSL_FUNC_CIPHER_GET_PARAMS 12 +# define OSSL_FUNC_CIPHER_CTX_GET_PARAMS 13 +# define OSSL_FUNC_CIPHER_CTX_SET_PARAMS 14 + +OSSL_CORE_MAKE_FUNC(void *, OP_cipher_newctx, (void)) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_encrypt_init, (void *vctx, + const unsigned char *key, + size_t keylen, + const unsigned char *iv, + size_t ivlen)) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_decrypt_init, (void *vctx, + const unsigned char *key, + size_t keylen, + const unsigned char *iv, + size_t ivlen)) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_update, + (void *, unsigned char *out, size_t *outl, size_t outsize, + const unsigned char *in, size_t inl)) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_final, + (void *, unsigned char *out, size_t *outl, size_t outsize)) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_cipher, + (void *, unsigned char *out, const unsigned char *in, + size_t inl)) +OSSL_CORE_MAKE_FUNC(void, OP_cipher_freectx, (void *vctx)) +OSSL_CORE_MAKE_FUNC(void *, OP_cipher_dupctx, (void *vctx)) +OSSL_CORE_MAKE_FUNC(size_t, OP_cipher_key_length, (void)) +OSSL_CORE_MAKE_FUNC(size_t, OP_cipher_iv_length, (void)) +OSSL_CORE_MAKE_FUNC(size_t, OP_cipher_block_size, (void)) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_get_params, (const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_ctx_get_params, (void *vctx, + const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(int, OP_cipher_ctx_set_params, (void *vctx, + const OSSL_PARAM params[])) + + # ifdef __cplusplus } # endif diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h index deb369ee..a7e78e4c 100644 --- a/include/openssl/crypto.h +++ b/include/openssl/crypto.h @@ -163,6 +163,19 @@ const char *OpenSSL_version(int type); # define OPENSSL_ENGINES_DIR 5 # define OPENSSL_VERSION_STRING 6 # define OPENSSL_FULL_VERSION_STRING 7 +# define OPENSSL_MODULES_DIR 8 + +const char *OPENSSL_info(int type); +/* + * The series starts at 1001 to avoid confusion with the OpenSSL_version + * types. + */ +# define OPENSSL_INFO_CONFIG_DIR 1001 +# define OPENSSL_INFO_ENGINES_DIR 1002 +# define OPENSSL_INFO_MODULES_DIR 1003 +# define OPENSSL_INFO_DSO_EXTENSION 1004 +# define OPENSSL_INFO_DIR_FILENAME_SEPARATOR 1005 +# define OPENSSL_INFO_LIST_SEPARATOR 1006 int OPENSSL_issetugid(void); diff --git a/include/openssl/err.h b/include/openssl/err.h index 136b0009..8fcdfb4b 100644 --- a/include/openssl/err.h +++ b/include/openssl/err.h @@ -98,6 +98,7 @@ typedef struct err_state_st { # define ERR_LIB_ESS 54 # define ERR_LIB_PROP 55 # define ERR_LIB_CRMF 56 +# define ERR_LIB_PROV 57 # define ERR_LIB_USER 128 @@ -140,6 +141,7 @@ typedef struct err_state_st { # define SM2err(f,r) ERR_PUT_error(ERR_LIB_SM2,(f),(r),OPENSSL_FILE,OPENSSL_LINE) # define ESSerr(f,r) ERR_PUT_error(ERR_LIB_ESS,(f),(r),OPENSSL_FILE,OPENSSL_LINE) # define PROPerr(f,r) ERR_PUT_error(ERR_LIB_PROP,(f),(r),OPENSSL_FILE,OPENSSL_LINE) +# define PROVerr(f,r) ERR_PUT_error(ERR_LIB_PROV,(f),(r),OPENSSL_FILE,OPENSSL_LINE) # define ERR_PACK(l,f,r) ( \ (((unsigned int)(l) & 0x0FF) << 24L) | \ diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 059a38eb..c26c6d01 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -190,6 +190,7 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd, EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len); EVP_CIPHER *EVP_CIPHER_meth_dup(const EVP_CIPHER *cipher); void EVP_CIPHER_meth_free(EVP_CIPHER *cipher); +int EVP_CIPHER_upref(EVP_CIPHER *cipher); int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len); int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags); @@ -473,7 +474,9 @@ int EVP_CIPHER_impl_ctx_size(const EVP_CIPHER *cipher); int EVP_CIPHER_key_length(const EVP_CIPHER *cipher); int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher); unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher); -# define EVP_CIPHER_mode(e) (EVP_CIPHER_flags(e) & EVP_CIPH_MODE) +int EVP_CIPHER_mode(const EVP_CIPHER *cipher); +EVP_CIPHER *EVP_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm, + const char *properties); const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx); diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index e62cfb3b..d88d4a84 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -55,6 +55,9 @@ int ERR_load_EVP_strings(void); # define EVP_F_EVP_CIPHER_CTX_COPY 163 # define EVP_F_EVP_CIPHER_CTX_CTRL 124 # define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH 122 +# define EVP_F_EVP_CIPHER_CTX_SET_PADDING 237 +# define EVP_F_EVP_CIPHER_FROM_DISPATCH 238 +# define EVP_F_EVP_CIPHER_MODE 239 # define EVP_F_EVP_CIPHER_PARAM_TO_ASN1 205 # define EVP_F_EVP_DECRYPTFINAL_EX 101 # define EVP_F_EVP_DECRYPTUPDATE 166 @@ -190,6 +193,7 @@ int ERR_load_EVP_strings(void); # define EVP_R_INVALID_KEY 163 # define EVP_R_INVALID_KEY_LENGTH 130 # define EVP_R_INVALID_OPERATION 148 +# define EVP_R_INVALID_PROVIDER_FUNCTIONS 193 # define EVP_R_INVALID_SALT_LENGTH 186 # define EVP_R_KEYGEN_FAILURE 120 # define EVP_R_KEY_SETUP_FAILED 180 diff --git a/providers/build.info b/providers/build.info index 1628e1fe..ef107a73 100644 --- a/providers/build.info +++ b/providers/build.info @@ -7,7 +7,7 @@ IF[{- !$disabled{fips} -}] SOURCE[fips]=fips.ld GENERATE[fips.ld]=../util/providers.num ENDIF - INCLUDE[fips]=.. ../include ../crypto/include + INCLUDE[fips]=.. ../include ../crypto/include common/include DEFINE[fips]=FIPS_MODE ENDIF diff --git a/providers/common/build.info b/providers/common/build.info index 5cb7e438..1617467d 100644 --- a/providers/common/build.info +++ b/providers/common/build.info @@ -1 +1,4 @@ -SUBDIRS=digests +SUBDIRS=digests ciphers + +SOURCE[../../libcrypto]=\ + provider_err.c diff --git a/providers/common/ciphers/aes.c b/providers/common/ciphers/aes.c new file mode 100644 index 00000000..5c6e6703 --- /dev/null +++ b/providers/common/ciphers/aes.c @@ -0,0 +1,470 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include "internal/cryptlib.h" +#include "internal/provider_algs.h" +#include "ciphers_locl.h" +#include "internal/providercommonerr.h" + +static OSSL_OP_cipher_encrypt_init_fn aes_einit; +static OSSL_OP_cipher_decrypt_init_fn aes_dinit; +static OSSL_OP_cipher_update_fn aes_block_update; +static OSSL_OP_cipher_final_fn aes_block_final; +static OSSL_OP_cipher_update_fn aes_stream_update; +static OSSL_OP_cipher_final_fn aes_stream_final; +static OSSL_OP_cipher_cipher_fn aes_cipher; +static OSSL_OP_cipher_freectx_fn aes_freectx; +static OSSL_OP_cipher_dupctx_fn aes_dupctx; +static OSSL_OP_cipher_key_length_fn key_length_256; +static OSSL_OP_cipher_key_length_fn key_length_192; +static OSSL_OP_cipher_key_length_fn key_length_128; +static OSSL_OP_cipher_iv_length_fn iv_length_16; +static OSSL_OP_cipher_iv_length_fn iv_length_0; +static OSSL_OP_cipher_block_size_fn block_size_16; +static OSSL_OP_cipher_block_size_fn block_size_1; +static OSSL_OP_cipher_ctx_get_params_fn aes_ctx_get_params; +static OSSL_OP_cipher_ctx_set_params_fn aes_ctx_set_params; + +static int PROV_AES_KEY_generic_init(PROV_AES_KEY *ctx, + const unsigned char *iv, + size_t ivlen, + int enc) +{ + if (iv != NULL && ctx->mode != EVP_CIPH_ECB_MODE) { + if (ivlen != AES_BLOCK_SIZE) { + PROVerr(PROV_F_PROV_AES_KEY_GENERIC_INIT, ERR_R_INTERNAL_ERROR); + return 0; + } + memcpy(ctx->iv, iv, AES_BLOCK_SIZE); + } + ctx->enc = enc; + + return 1; +} + +static int aes_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + + if (!PROV_AES_KEY_generic_init(ctx, iv, ivlen, 1)) { + /* PROVerr already called */ + return 0; + } + if (key != NULL) { + if (keylen != ctx->keylen) { + PROVerr(PROV_F_AES_EINIT, PROV_R_INVALID_KEYLEN); + return 0; + } + return ctx->ciph->init(ctx, key, ctx->keylen); + } + + return 1; +} + +static int aes_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + + if (!PROV_AES_KEY_generic_init(ctx, iv, ivlen, 0)) { + /* PROVerr already called */ + return 0; + } + if (key != NULL) { + if (keylen != ctx->keylen) { + PROVerr(PROV_F_AES_DINIT, PROV_R_INVALID_KEYLEN); + return 0; + } + return ctx->ciph->init(ctx, key, ctx->keylen); + } + + return 1; +} + +static int aes_block_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + size_t nextblocks = fillblock(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE, &in, + &inl); + size_t outlint = 0; + + /* + * If we're decrypting and we end an update on a block boundary we hold + * the last block back in case this is the last update call and the last + * block is padded. + */ + if (ctx->bufsz == AES_BLOCK_SIZE + && (ctx->enc || inl > 0 || !ctx->pad)) { + if (outsize < AES_BLOCK_SIZE) { + PROVerr(PROV_F_AES_BLOCK_UPDATE, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ctx->ciph->cipher(ctx, out, ctx->buf, AES_BLOCK_SIZE)) { + PROVerr(PROV_F_AES_BLOCK_UPDATE, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + ctx->bufsz = 0; + outlint = AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (nextblocks > 0) { + if (!ctx->enc && ctx->pad && nextblocks == inl) { + if (!ossl_assert(inl >= AES_BLOCK_SIZE)) { + PROVerr(PROV_F_AES_BLOCK_UPDATE, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + nextblocks -= AES_BLOCK_SIZE; + } + outlint += nextblocks; + if (outsize < outlint) { + PROVerr(PROV_F_AES_BLOCK_UPDATE, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ctx->ciph->cipher(ctx, out, in, nextblocks)) { + PROVerr(PROV_F_AES_BLOCK_UPDATE, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + in += nextblocks; + inl -= nextblocks; + } + if (!trailingdata(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE, &in, &inl)) { + /* PROVerr already called */ + return 0; + } + + *outl = outlint; + return inl == 0; +} + +static int aes_block_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + + if (ctx->enc) { + if (ctx->pad) { + padblock(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE); + } else if (ctx->bufsz == 0) { + *outl = 0; + return 1; + } else if (ctx->bufsz != AES_BLOCK_SIZE) { + PROVerr(PROV_F_AES_BLOCK_FINAL, PROV_R_WRONG_FINAL_BLOCK_LENGTH); + return 0; + } + + if (outsize < AES_BLOCK_SIZE) { + PROVerr(PROV_F_AES_BLOCK_FINAL, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + if (!ctx->ciph->cipher(ctx, out, ctx->buf, AES_BLOCK_SIZE)) { + PROVerr(PROV_F_AES_BLOCK_FINAL, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + ctx->bufsz = 0; + *outl = AES_BLOCK_SIZE; + return 1; + } + + /* Decrypting */ + if (ctx->bufsz != AES_BLOCK_SIZE) { + if (ctx->bufsz == 0 && !ctx->pad) { + *outl = 0; + return 1; + } + PROVerr(PROV_F_AES_BLOCK_FINAL, PROV_R_WRONG_FINAL_BLOCK_LENGTH); + return 0; + } + + if (!ctx->ciph->cipher(ctx, ctx->buf, ctx->buf, AES_BLOCK_SIZE)) { + PROVerr(PROV_F_AES_BLOCK_FINAL, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (ctx->pad && !unpadblock(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE)) { + /* PROVerr already called */ + return 0; + } + + if (outsize < ctx->bufsz) { + PROVerr(PROV_F_AES_BLOCK_FINAL, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + memcpy(out, ctx->buf, ctx->bufsz); + *outl = ctx->bufsz; + ctx->bufsz = 0; + return 1; +} + +static int aes_stream_update(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + + if (outsize < inl) { + PROVerr(PROV_F_AES_STREAM_UPDATE, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!ctx->ciph->cipher(ctx, out, in, inl)) { + PROVerr(PROV_F_AES_STREAM_UPDATE, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + return 1; +} +static int aes_stream_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + *outl = 0; + return 1; +} + +static int aes_cipher(void *vctx, unsigned char *out, const unsigned char *in, + size_t inl) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + + if (!ctx->ciph->cipher(ctx, out, in, inl)) { + PROVerr(PROV_F_AES_CIPHER, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + return 1; +} + +#define IMPLEMENT_new_params(lcmode, UCMODE) \ + static OSSL_OP_cipher_get_params_fn aes_##lcmode##_get_params; \ + static int aes_##lcmode##_get_params(const OSSL_PARAM params[]) \ + { \ + const OSSL_PARAM *p; \ + \ + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_MODE); \ + if (p != NULL && !OSSL_PARAM_set_int(p, EVP_CIPH_##UCMODE##_MODE)) \ + return 0; \ + \ + return 1; \ + } + +#define IMPLEMENT_new_ctx(lcmode, UCMODE, len) \ + static OSSL_OP_cipher_newctx_fn aes_##len##_##lcmode##_newctx; \ + static void *aes_##len##_##lcmode##_newctx(void) \ + { \ + PROV_AES_KEY *ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + \ + ctx->pad = 1; \ + ctx->keylen = (len / 8); \ + ctx->ciph = PROV_AES_CIPHER_##lcmode(ctx->keylen); \ + ctx->mode = EVP_CIPH_##UCMODE##_MODE; \ + return ctx; \ + } + +/* ECB */ +IMPLEMENT_new_params(ecb, ECB) +IMPLEMENT_new_ctx(ecb, ECB, 256) +IMPLEMENT_new_ctx(ecb, ECB, 192) +IMPLEMENT_new_ctx(ecb, ECB, 128) + +/* CBC */ +IMPLEMENT_new_params(cbc, CBC) +IMPLEMENT_new_ctx(cbc, CBC, 256) +IMPLEMENT_new_ctx(cbc, CBC, 192) +IMPLEMENT_new_ctx(cbc, CBC, 128) + +/* OFB */ +IMPLEMENT_new_params(ofb, OFB) +IMPLEMENT_new_ctx(ofb, OFB, 256) +IMPLEMENT_new_ctx(ofb, OFB, 192) +IMPLEMENT_new_ctx(ofb, OFB, 128) + +/* CFB */ +IMPLEMENT_new_params(cfb, CFB) +IMPLEMENT_new_params(cfb1, CFB) +IMPLEMENT_new_params(cfb8, CFB) +IMPLEMENT_new_ctx(cfb, CFB, 256) +IMPLEMENT_new_ctx(cfb, CFB, 192) +IMPLEMENT_new_ctx(cfb, CFB, 128) +IMPLEMENT_new_ctx(cfb1, CFB, 256) +IMPLEMENT_new_ctx(cfb1, CFB, 192) +IMPLEMENT_new_ctx(cfb1, CFB, 128) +IMPLEMENT_new_ctx(cfb8, CFB, 256) +IMPLEMENT_new_ctx(cfb8, CFB, 192) +IMPLEMENT_new_ctx(cfb8, CFB, 128) + +/* CTR */ +IMPLEMENT_new_params(ctr, CTR) +IMPLEMENT_new_ctx(ctr, CTR, 256) +IMPLEMENT_new_ctx(ctr, CTR, 192) +IMPLEMENT_new_ctx(ctr, CTR, 128) + +static void aes_freectx(void *vctx) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *aes_dupctx(void *ctx) +{ + PROV_AES_KEY *in = (PROV_AES_KEY *)ctx; + PROV_AES_KEY *ret = OPENSSL_malloc(sizeof(*ret)); + + if (ret == NULL) { + PROVerr(PROV_F_AES_DUPCTX, ERR_R_MALLOC_FAILURE); + return NULL; + } + *ret = *in; + + return ret; +} + +static size_t key_length_256(void) +{ + return 256 / 8; +} + +static size_t key_length_192(void) +{ + return 192 / 8; +} + +static size_t key_length_128(void) +{ + return 128 / 8; +} + +static size_t iv_length_16(void) +{ + return 16; +} + +static size_t iv_length_0(void) +{ + return 0; +} + +static size_t block_size_16(void) +{ + return 16; +} + +static size_t block_size_1(void) +{ + return 1; +} + +static int aes_ctx_get_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_PADDING); + if (p != NULL && !OSSL_PARAM_set_int(p, ctx->pad)) { + PROVerr(PROV_F_AES_CTX_GET_PARAMS, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + return 1; +} + +static int aes_ctx_set_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_PADDING); + if (p != NULL) { + int pad; + + if (!OSSL_PARAM_get_int(p, &pad)) { + PROVerr(PROV_F_AES_CTX_SET_PARAMS, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->pad = pad ? 1 : 0; + } + return 1; +} + +#define IMPLEMENT_block_funcs(mode, keylen, ivlen) \ + const OSSL_DISPATCH aes##keylen##mode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))aes_##keylen##_##mode##_newctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_block_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_block_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_cipher }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_dupctx }, \ + { OSSL_FUNC_CIPHER_KEY_LENGTH, (void (*)(void))key_length_##keylen }, \ + { OSSL_FUNC_CIPHER_IV_LENGTH, (void (*)(void))iv_length_##ivlen }, \ + { OSSL_FUNC_CIPHER_BLOCK_SIZE, (void (*)(void))block_size_16 }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))aes_##mode##_get_params }, \ + { OSSL_FUNC_CIPHER_CTX_GET_PARAMS, (void (*)(void))aes_ctx_get_params }, \ + { OSSL_FUNC_CIPHER_CTX_SET_PARAMS, (void (*)(void))aes_ctx_set_params }, \ + { 0, NULL } \ + }; + +#define IMPLEMENT_stream_funcs(mode, keylen, ivlen) \ + const OSSL_DISPATCH aes##keylen##mode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))aes_##keylen##_##mode##_newctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_stream_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_stream_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_cipher }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_dupctx }, \ + { OSSL_FUNC_CIPHER_KEY_LENGTH, (void (*)(void))key_length_##keylen }, \ + { OSSL_FUNC_CIPHER_IV_LENGTH, (void (*)(void))iv_length_##ivlen }, \ + { OSSL_FUNC_CIPHER_BLOCK_SIZE, (void (*)(void))block_size_1 }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))aes_##mode##_get_params }, \ + { OSSL_FUNC_CIPHER_CTX_GET_PARAMS, (void (*)(void))aes_ctx_get_params }, \ + { OSSL_FUNC_CIPHER_CTX_SET_PARAMS, (void (*)(void))aes_ctx_set_params }, \ + { 0, NULL } \ + }; + +/* ECB */ +IMPLEMENT_block_funcs(ecb, 256, 0) +IMPLEMENT_block_funcs(ecb, 192, 0) +IMPLEMENT_block_funcs(ecb, 128, 0) + +/* CBC */ +IMPLEMENT_block_funcs(cbc, 256, 16) +IMPLEMENT_block_funcs(cbc, 192, 16) +IMPLEMENT_block_funcs(cbc, 128, 16) + +/* OFB */ +IMPLEMENT_stream_funcs(ofb, 256, 16) +IMPLEMENT_stream_funcs(ofb, 192, 16) +IMPLEMENT_stream_funcs(ofb, 128, 16) + +/* CFB */ +IMPLEMENT_stream_funcs(cfb, 256, 16) +IMPLEMENT_stream_funcs(cfb, 192, 16) +IMPLEMENT_stream_funcs(cfb, 128, 16) +IMPLEMENT_stream_funcs(cfb1, 256, 16) +IMPLEMENT_stream_funcs(cfb1, 192, 16) +IMPLEMENT_stream_funcs(cfb1, 128, 16) +IMPLEMENT_stream_funcs(cfb8, 256, 16) +IMPLEMENT_stream_funcs(cfb8, 192, 16) +IMPLEMENT_stream_funcs(cfb8, 128, 16) + +/* CTR */ +IMPLEMENT_stream_funcs(ctr, 256, 16) +IMPLEMENT_stream_funcs(ctr, 192, 16) +IMPLEMENT_stream_funcs(ctr, 128, 16) diff --git a/providers/common/ciphers/aes_basic.c b/providers/common/ciphers/aes_basic.c new file mode 100644 index 00000000..0f642966 --- /dev/null +++ b/providers/common/ciphers/aes_basic.c @@ -0,0 +1,866 @@ +/* + * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include "internal/evp_int.h" +#include +#include +#include "ciphers_locl.h" +#include "internal/providercommonerr.h" + +#define MAXBITCHUNK ((size_t)1 << (sizeof(size_t) * 8 - 4)) + +#ifdef VPAES_ASM +int vpaes_set_encrypt_key(const unsigned char *userKey, int bits, + AES_KEY *key); +int vpaes_set_decrypt_key(const unsigned char *userKey, int bits, + AES_KEY *key); + +void vpaes_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void vpaes_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + +void vpaes_cbc_encrypt(const unsigned char *in, + unsigned char *out, + size_t length, + const AES_KEY *key, unsigned char *ivec, int enc); +#endif +#ifdef BSAES_ASM +void bsaes_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char ivec[16], int enc); +void bsaes_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + const unsigned char ivec[16]); +#endif +#ifdef AES_CTR_ASM +void AES_ctr32_encrypt(const unsigned char *in, unsigned char *out, + size_t blocks, const AES_KEY *key, + const unsigned char ivec[AES_BLOCK_SIZE]); +#endif + + +#if defined(OPENSSL_CPUID_OBJ) && (defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC)) +# include "ppc_arch.h" +# ifdef VPAES_ASM +# define VPAES_CAPABLE (OPENSSL_ppccap_P & PPC_ALTIVEC) +# endif +# define HWAES_CAPABLE (OPENSSL_ppccap_P & PPC_CRYPTO207) +# define HWAES_set_encrypt_key aes_p8_set_encrypt_key +# define HWAES_set_decrypt_key aes_p8_set_decrypt_key +# define HWAES_encrypt aes_p8_encrypt +# define HWAES_decrypt aes_p8_decrypt +# define HWAES_cbc_encrypt aes_p8_cbc_encrypt +# define HWAES_ctr32_encrypt_blocks aes_p8_ctr32_encrypt_blocks +# define HWAES_xts_encrypt aes_p8_xts_encrypt +# define HWAES_xts_decrypt aes_p8_xts_decrypt +#endif + +#if defined(AES_ASM) && !defined(I386_ONLY) && ( \ + ((defined(__i386) || defined(__i386__) || \ + defined(_M_IX86)) && defined(OPENSSL_IA32_SSE2))|| \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_M_AMD64) || defined(_M_X64) ) + +extern unsigned int OPENSSL_ia32cap_P[]; + +# ifdef VPAES_ASM +# define VPAES_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(41-32))) +# endif +# ifdef BSAES_ASM +# define BSAES_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(41-32))) +# endif +/* + * AES-NI section + */ +# define AESNI_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(57-32))) + +int aesni_set_encrypt_key(const unsigned char *userKey, int bits, + AES_KEY *key); +int aesni_set_decrypt_key(const unsigned char *userKey, int bits, + AES_KEY *key); + +void aesni_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void aesni_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + +void aesni_ecb_encrypt(const unsigned char *in, + unsigned char *out, + size_t length, const AES_KEY *key, int enc); +void aesni_cbc_encrypt(const unsigned char *in, + unsigned char *out, + size_t length, + const AES_KEY *key, unsigned char *ivec, int enc); + +void aesni_ctr32_encrypt_blocks(const unsigned char *in, + unsigned char *out, + size_t blocks, + const void *key, const unsigned char *ivec); + +static int aesni_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen) +{ + int ret; + + if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE) + && !dat->enc) { + ret = aesni_set_decrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f) aesni_decrypt; + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) aesni_cbc_encrypt : NULL; + } else { + ret = aesni_set_encrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f) aesni_encrypt; + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f) aesni_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f) aesni_ctr32_encrypt_blocks; + else + dat->stream.cbc = NULL; + } + + if (ret < 0) { + PROVerr(PROV_F_AESNI_INIT_KEY, PROV_R_AES_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +static int aesni_cbc_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + aesni_cbc_encrypt(in, out, len, &ctx->ks.ks, ctx->iv, ctx->enc); + + return 1; +} + +static int aesni_ecb_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + if (len < AES_BLOCK_SIZE) + return 1; + + aesni_ecb_encrypt(in, out, len, &ctx->ks.ks, ctx->enc); + + return 1; +} + +# define aesni_ofb_cipher aes_ofb_cipher +static int aesni_ofb_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aesni_cfb_cipher aes_cfb_cipher +static int aesni_cfb_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aesni_cfb8_cipher aes_cfb8_cipher +static int aesni_cfb8_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aesni_cfb1_cipher aes_cfb1_cipher +static int aesni_cfb1_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aesni_ctr_cipher aes_ctr_cipher +static int aesni_ctr_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define BLOCK_CIPHER_generic_prov(mode) \ +static const PROV_AES_CIPHER aesni_##mode = { \ + aesni_init_key, \ + aesni_##mode##_cipher}; \ +static const PROV_AES_CIPHER aes_##mode = { \ + aes_init_key, \ + aes_##mode##_cipher}; \ +const PROV_AES_CIPHER *PROV_AES_CIPHER_##mode(size_t keylen) \ +{ return AESNI_CAPABLE?&aesni_##mode:&aes_##mode; } + + +#elif defined(AES_ASM) && (defined(__sparc) || defined(__sparc__)) + +# include "sparc_arch.h" + +extern unsigned int OPENSSL_sparcv9cap_P[]; + +/* + * Fujitsu SPARC64 X support + */ +# define HWAES_CAPABLE (OPENSSL_sparcv9cap_P[0] & SPARCV9_FJAESX) +# define HWAES_set_encrypt_key aes_fx_set_encrypt_key +# define HWAES_set_decrypt_key aes_fx_set_decrypt_key +# define HWAES_encrypt aes_fx_encrypt +# define HWAES_decrypt aes_fx_decrypt +# define HWAES_cbc_encrypt aes_fx_cbc_encrypt +# define HWAES_ctr32_encrypt_blocks aes_fx_ctr32_encrypt_blocks + +# define SPARC_AES_CAPABLE (OPENSSL_sparcv9cap_P[1] & CFR_AES) + +void aes_t4_set_encrypt_key(const unsigned char *key, int bits, AES_KEY *ks); +void aes_t4_set_decrypt_key(const unsigned char *key, int bits, AES_KEY *ks); +void aes_t4_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void aes_t4_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +/* + * Key-length specific subroutines were chosen for following reason. + * Each SPARC T4 core can execute up to 8 threads which share core's + * resources. Loading as much key material to registers allows to + * minimize references to shared memory interface, as well as amount + * of instructions in inner loops [much needed on T4]. But then having + * non-key-length specific routines would require conditional branches + * either in inner loops or on subroutines' entries. Former is hardly + * acceptable, while latter means code size increase to size occupied + * by multiple key-length specific subroutines, so why fight? + */ +void aes128_t4_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + unsigned char *ivec); +void aes128_t4_cbc_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + unsigned char *ivec); +void aes192_t4_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + unsigned char *ivec); +void aes192_t4_cbc_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + unsigned char *ivec); +void aes256_t4_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + unsigned char *ivec); +void aes256_t4_cbc_decrypt(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + unsigned char *ivec); +void aes128_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out, + size_t blocks, const AES_KEY *key, + unsigned char *ivec); +void aes192_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out, + size_t blocks, const AES_KEY *key, + unsigned char *ivec); +void aes256_t4_ctr32_encrypt(const unsigned char *in, unsigned char *out, + size_t blocks, const AES_KEY *key, + unsigned char *ivec); + +static int aes_t4_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen) +{ + int ret, bits; + + bits = keylen * 8; + if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE) + && !dat->enc) { + ret = 0; + aes_t4_set_decrypt_key(key, bits, &dat->ks.ks); + dat->block = (block128_f) aes_t4_decrypt; + switch (bits) { + case 128: + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) aes128_t4_cbc_decrypt : NULL; + break; + case 192: + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) aes192_t4_cbc_decrypt : NULL; + break; + case 256: + dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ? + (cbc128_f) aes256_t4_cbc_decrypt : NULL; + break; + default: + ret = -1; + } + } else { + ret = 0; + aes_t4_set_encrypt_key(key, bits, &dat->ks.ks); + dat->block = (block128_f)aes_t4_encrypt; + switch (bits) { + case 128: + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)aes128_t4_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)aes128_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + case 192: + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)aes192_t4_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)aes192_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + case 256: + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)aes256_t4_cbc_encrypt; + else if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)aes256_t4_ctr32_encrypt; + else + dat->stream.cbc = NULL; + break; + default: + ret = -1; + } + } + + if (ret < 0) { + PROVerr(PROV_F_AES_T4_INIT_KEY, PROV_R_AES_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +# define aes_t4_cbc_cipher aes_cbc_cipher +static int aes_t4_cbc_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aes_t4_ecb_cipher aes_ecb_cipher +static int aes_t4_ecb_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aes_t4_ofb_cipher aes_ofb_cipher +static int aes_t4_ofb_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aes_t4_cfb_cipher aes_cfb_cipher +static int aes_t4_cfb_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aes_t4_cfb8_cipher aes_cfb8_cipher +static int aes_t4_cfb8_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aes_t4_cfb1_cipher aes_cfb1_cipher +static int aes_t4_cfb1_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define aes_t4_ctr_cipher aes_ctr_cipher +static int aes_t4_ctr_cipher(PROV_AES_KEY *ctx, unsigned char *out, + const unsigned char *in, size_t len); + +# define BLOCK_CIPHER_generic_prov(mode) \ +static const PROV_AES_CIPHER aes_t4_##mode = { \ + aes_t4_init_key, \ + aes_t4_##mode##_cipher}; \ +static const PROV_AES_CIPHER aes_##mode = { \ + aes_init_key, \ + aes_##mode##_cipher}; \ +const PROV_AES_CIPHER *PROV_AES_CIPHER_##mode(size_t keylen) \ +{ return SPARC_AES_CAPABLE?&aes_t4_##mode:&aes_##mode; } + + +#elif defined(OPENSSL_CPUID_OBJ) && defined(__s390__) +/* + * IBM S390X support + */ +# include "s390x_arch.h" + +/* Convert key size to function code: [16,24,32] -> [18,19,20]. */ +# define S390X_AES_FC(keylen) (S390X_AES_128 + ((((keylen) << 3) - 128) >> 6)) + +/* Most modes of operation need km for partial block processing. */ +# define S390X_aes_128_CAPABLE (OPENSSL_s390xcap_P.km[0] & \ + S390X_CAPBIT(S390X_AES_128)) +# define S390X_aes_192_CAPABLE (OPENSSL_s390xcap_P.km[0] & \ + S390X_CAPBIT(S390X_AES_192)) +# define S390X_aes_256_CAPABLE (OPENSSL_s390xcap_P.km[0] & \ + S390X_CAPBIT(S390X_AES_256)) + +# define s390x_aes_init_key aes_init_key +static int s390x_aes_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen); + +# define S390X_aes_128_cbc_CAPABLE 1 /* checked by callee */ +# define S390X_aes_192_cbc_CAPABLE 1 +# define S390X_aes_256_cbc_CAPABLE 1 +# define S390X_AES_CBC_CTX PROV_AES_KEY + +# define s390x_aes_cbc_init_key aes_init_key + +# define s390x_aes_cbc_cipher aes_cbc_cipher +static int s390x_aes_cbc_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len); + +# define S390X_aes_128_ecb_CAPABLE S390X_aes_128_CAPABLE +# define S390X_aes_192_ecb_CAPABLE S390X_aes_192_CAPABLE +# define S390X_aes_256_ecb_CAPABLE S390X_aes_256_CAPABLE + +static int s390x_aes_ecb_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen) +{ + dat->plat.s390x.fc = S390X_AES_FC(keylen); + if (!dat->enc) + dat->plat.s390x.fc |= S390X_DECRYPT; + + memcpy(dat->plat.s390x.param.km.k, key, keylen); + return 1; +} + +static int s390x_aes_ecb_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + s390x_km(in, len, out, dat->plat.s390x.fc, + &dat->plat.s390x.param.km); + return 1; +} + +# define S390X_aes_128_ofb_CAPABLE (S390X_aes_128_CAPABLE && \ + (OPENSSL_s390xcap_P.kmo[0] & \ + S390X_CAPBIT(S390X_AES_128))) +# define S390X_aes_192_ofb_CAPABLE (S390X_aes_192_CAPABLE && \ + (OPENSSL_s390xcap_P.kmo[0] & \ + S390X_CAPBIT(S390X_AES_192))) +# define S390X_aes_256_ofb_CAPABLE (S390X_aes_256_CAPABLE && \ + (OPENSSL_s390xcap_P.kmo[0] & \ + S390X_CAPBIT(S390X_AES_256))) + +static int s390x_aes_ofb_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen) +{ + memcpy(dat->plat.s390x.param.kmo_kmf.cv, dat->iv, AES_BLOCK_SIZE); + memcpy(dat->plat.s390x.param.kmo_kmf.k, key, keylen); + dat->plat.s390x.fc = S390X_AES_FC(keylen); + dat->plat.s390x.res = 0; + return 1; +} + +static int s390x_aes_ofb_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int n = dat->plat.s390x.res; + int rem; + + while (n && len) { + *out = *in ^ dat->plat.s390x.param.kmo_kmf.cv[n]; + n = (n + 1) & 0xf; + --len; + ++in; + ++out; + } + + rem = len & 0xf; + + len &= ~(size_t)0xf; + if (len) { + s390x_kmo(in, len, out, dat->plat.s390x.fc, + &dat->plat.s390x.param.kmo_kmf); + + out += len; + in += len; + } + + if (rem) { + s390x_km(dat->plat.s390x.param.kmo_kmf.cv, 16, + dat->plat.s390x.param.kmo_kmf.cv, dat->plat.s390x.fc, + dat->plat.s390x.param.kmo_kmf.k); + + while (rem--) { + out[n] = in[n] ^ dat->plat.s390x.param.kmo_kmf.cv[n]; + ++n; + } + } + + dat->plat.s390x.res = n; + return 1; +} + +# define S390X_aes_128_cfb_CAPABLE (S390X_aes_128_CAPABLE && \ + (OPENSSL_s390xcap_P.kmf[0] & \ + S390X_CAPBIT(S390X_AES_128))) +# define S390X_aes_192_cfb_CAPABLE (S390X_aes_192_CAPABLE && \ + (OPENSSL_s390xcap_P.kmf[0] & \ + S390X_CAPBIT(S390X_AES_192))) +# define S390X_aes_256_cfb_CAPABLE (S390X_aes_256_CAPABLE && \ + (OPENSSL_s390xcap_P.kmf[0] & \ + S390X_CAPBIT(S390X_AES_256))) + +static int s390x_aes_cfb_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen) +{ + dat->plat.s390x.fc = S390X_AES_FC(keylen); + dat->plat.s390x.fc |= 16 << 24; /* 16 bytes cipher feedback */ + if (!dat->enc) + dat->plat.s390x.fc |= S390X_DECRYPT; + + dat->plat.s390x.res = 0; + memcpy(dat->plat.s390x.param.kmo_kmf.cv, dat->iv, AES_BLOCK_SIZE); + memcpy(dat->plat.s390x.param.kmo_kmf.k, key, keylen); + return 1; +} + +static int s390x_aes_cfb_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int n = dat->plat.s390x.res; + int rem; + unsigned char tmp; + + while (n && len) { + tmp = *in; + *out = dat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp; + dat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? *out : tmp; + n = (n + 1) & 0xf; + --len; + ++in; + ++out; + } + + rem = len & 0xf; + + len &= ~(size_t)0xf; + if (len) { + s390x_kmf(in, len, out, dat->plat.s390x.fc, + &dat->plat.s390x.param.kmo_kmf); + + out += len; + in += len; + } + + if (rem) { + s390x_km(dat->plat.s390x.param.kmo_kmf.cv, 16, + dat->plat.s390x.param.kmo_kmf.cv, + S390X_AES_FC(dat->keylen), dat->plat.s390x.param.kmo_kmf.k); + + while (rem--) { + tmp = in[n]; + out[n] = dat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp; + dat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? out[n] : tmp; + ++n; + } + } + + dat->plat.s390x.res = n; + return 1; +} + +# define S390X_aes_128_cfb8_CAPABLE (OPENSSL_s390xcap_P.kmf[0] & \ + S390X_CAPBIT(S390X_AES_128)) +# define S390X_aes_192_cfb8_CAPABLE (OPENSSL_s390xcap_P.kmf[0] & \ + S390X_CAPBIT(S390X_AES_192)) +# define S390X_aes_256_cfb8_CAPABLE (OPENSSL_s390xcap_P.kmf[0] & \ + S390X_CAPBIT(S390X_AES_256)) + +static int s390x_aes_cfb8_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen) +{ + dat->plat.s390x.fc = S390X_AES_FC(keylen); + dat->plat.s390x.fc |= 1 << 24; /* 1 byte cipher feedback */ + if (!dat->enc) + dat->plat.s390x.fc |= S390X_DECRYPT; + + memcpy(dat->plat.s390x.param.kmo_kmf.cv, dat->iv, AES_BLOCK_SIZE); + memcpy(dat->plat.s390x.param.kmo_kmf.k, key, keylen); + return 1; +} + +static int s390x_aes_cfb8_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + s390x_kmf(in, len, out, dat->plat.s390x.fc, + &dat->plat.s390x.param.kmo_kmf); + return 1; +} + +# define S390X_aes_128_cfb1_CAPABLE 0 +# define S390X_aes_192_cfb1_CAPABLE 0 +# define S390X_aes_256_cfb1_CAPABLE 0 + +# define s390x_aes_cfb1_init_key aes_init_key + +# define s390x_aes_cfb1_cipher aes_cfb1_cipher +static int s390x_aes_cfb1_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len); + +# define S390X_aes_128_ctr_CAPABLE 1 /* checked by callee */ +# define S390X_aes_192_ctr_CAPABLE 1 +# define S390X_aes_256_ctr_CAPABLE 1 +# define S390X_AES_CTR_CTX PROV_AES_KEY + +# define s390x_aes_ctr_init_key aes_init_key + +# define s390x_aes_ctr_cipher aes_ctr_cipher +static int s390x_aes_ctr_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len); + +# define BLOCK_CIPHER_generic_prov(mode) \ +static const PROV_AES_CIPHER s390x_aes_##mode = { \ + s390x_aes_##mode##_init_key, \ + s390x_aes_##mode##_cipher \ +}; \ +static const PROV_AES_CIPHER aes_##mode = { \ + aes_init_key, \ + aes_##mode##_cipher \ +}; \ +const PROV_AES_CIPHER *PROV_AES_CIPHER_##mode(size_t keylen) \ +{ \ + if ((keylen == 128 && S390X_aes_128_##mode##_CAPABLE) \ + || (keylen == 192 && S390X_aes_192_##mode##_CAPABLE) \ + || (keylen == 256 && S390X_aes_256_##mode##_CAPABLE)) \ + return &s390x_aes_##mode; \ + \ + return &aes_##mode; \ +} + +#else + +# define BLOCK_CIPHER_generic_prov(mode) \ +static const PROV_AES_CIPHER aes_##mode = { \ + aes_init_key, \ + aes_##mode##_cipher}; \ +const PROV_AES_CIPHER *PROV_AES_CIPHER_##mode(size_t keylen) \ +{ return &aes_##mode; } + +#endif + +#if defined(OPENSSL_CPUID_OBJ) && (defined(__arm__) || defined(__arm) || defined(__aarch64__)) +# include "arm_arch.h" +# if __ARM_MAX_ARCH__>=7 +# if defined(BSAES_ASM) +# define BSAES_CAPABLE (OPENSSL_armcap_P & ARMV7_NEON) +# endif +# if defined(VPAES_ASM) +# define VPAES_CAPABLE (OPENSSL_armcap_P & ARMV7_NEON) +# endif +# define HWAES_CAPABLE (OPENSSL_armcap_P & ARMV8_AES) +# define HWAES_set_encrypt_key aes_v8_set_encrypt_key +# define HWAES_set_decrypt_key aes_v8_set_decrypt_key +# define HWAES_encrypt aes_v8_encrypt +# define HWAES_decrypt aes_v8_decrypt +# define HWAES_cbc_encrypt aes_v8_cbc_encrypt +# define HWAES_ctr32_encrypt_blocks aes_v8_ctr32_encrypt_blocks +# endif +#endif + +#if defined(HWAES_CAPABLE) +int HWAES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int HWAES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +void HWAES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void HWAES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void HWAES_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); +void HWAES_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, + const unsigned char ivec[16]); +#endif + +static int aes_init_key(PROV_AES_KEY *dat, const unsigned char *key, + size_t keylen) +{ + int ret; + + if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE) + && !dat->enc) { +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { + ret = HWAES_set_decrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)HWAES_decrypt; + dat->stream.cbc = NULL; +# ifdef HWAES_cbc_encrypt + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt; +# endif + } else +#endif +#ifdef BSAES_CAPABLE + if (BSAES_CAPABLE && dat->mode == EVP_CIPH_CBC_MODE) { + ret = AES_set_decrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt; + } else +#endif +#ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + ret = vpaes_set_decrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)vpaes_decrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ?(cbc128_f)vpaes_cbc_encrypt : NULL; + } else +#endif + { + ret = AES_set_decrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ? (cbc128_f)AES_cbc_encrypt : NULL; + } + } else +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) { + ret = HWAES_set_encrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)HWAES_encrypt; + dat->stream.cbc = NULL; +# ifdef HWAES_cbc_encrypt + if (dat->mode == EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt; + else +# endif +# ifdef HWAES_ctr32_encrypt_blocks + if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)HWAES_ctr32_encrypt_blocks; + else +# endif + (void)0; /* terminate potentially open 'else' */ + } else +#endif +#ifdef BSAES_CAPABLE + if (BSAES_CAPABLE && dat->mode == EVP_CIPH_CTR_MODE) { + ret = AES_set_encrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks; + } else +#endif +#ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) { + ret = vpaes_set_encrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)vpaes_encrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ? (cbc128_f)vpaes_cbc_encrypt : NULL; + } else +#endif + { + ret = AES_set_encrypt_key(key, keylen * 8, &dat->ks.ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE) + ? (cbc128_f)AES_cbc_encrypt : NULL; +#ifdef AES_CTR_ASM + if (dat->mode == EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)AES_ctr32_encrypt; +#endif + } + + if (ret < 0) { + PROVerr(PROV_F_AES_INIT_KEY, PROV_R_AES_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +static int aes_cbc_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + if (dat->stream.cbc) + (*dat->stream.cbc) (in, out, len, &dat->ks, dat->iv, dat->enc); + else if (dat->enc) + CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, dat->iv, dat->block); + else + CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, dat->iv, dat->block); + + return 1; +} + +static int aes_ecb_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + size_t i; + + if (len < AES_BLOCK_SIZE) + return 1; + + for (i = 0, len -= AES_BLOCK_SIZE; i <= len; i += AES_BLOCK_SIZE) + (*dat->block) (in + i, out + i, &dat->ks); + + return 1; +} + +static int aes_ofb_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + CRYPTO_ofb128_encrypt(in, out, len, &dat->ks, dat->iv, &num, dat->block); + dat->num = num; + + return 1; +} + +static int aes_cfb_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + CRYPTO_cfb128_encrypt(in, out, len, &dat->ks, dat->iv, &num, dat->enc, + dat->block); + dat->num = num; + + return 1; +} + +static int aes_cfb8_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + CRYPTO_cfb128_8_encrypt(in, out, len, &dat->ks, dat->iv, &num, dat->enc, + dat->block); + dat->num = num; + + return 1; +} + +static int aes_cfb1_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + int num = dat->num; + + if ((dat->flags & EVP_CIPH_FLAG_LENGTH_BITS) != 0) { + CRYPTO_cfb128_1_encrypt(in, out, len, &dat->ks, dat->iv, &num, + dat->enc, dat->block); + dat->num = num; + return 1; + } + + while (len >= MAXBITCHUNK) { + CRYPTO_cfb128_1_encrypt(in, out, MAXBITCHUNK * 8, &dat->ks, + dat->iv, &num, dat->enc, dat->block); + len -= MAXBITCHUNK; + out += MAXBITCHUNK; + in += MAXBITCHUNK; + } + if (len) + CRYPTO_cfb128_1_encrypt(in, out, len * 8, &dat->ks, dat->iv, &num, + dat->enc, dat->block); + + dat->num = num; + + return 1; +} + +static int aes_ctr_cipher(PROV_AES_KEY *dat, unsigned char *out, + const unsigned char *in, size_t len) +{ + unsigned int num = dat->num; + + if (dat->stream.ctr) + CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, dat->iv, dat->buf, + &num, dat->stream.ctr); + else + CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, dat->iv, dat->buf, + &num, dat->block); + dat->num = num; + + return 1; +} + +BLOCK_CIPHER_generic_prov(cbc) +BLOCK_CIPHER_generic_prov(ecb) +BLOCK_CIPHER_generic_prov(ofb) +BLOCK_CIPHER_generic_prov(cfb) +BLOCK_CIPHER_generic_prov(cfb1) +BLOCK_CIPHER_generic_prov(cfb8) +BLOCK_CIPHER_generic_prov(ctr) + diff --git a/providers/common/ciphers/block.c b/providers/common/ciphers/block.c new file mode 100644 index 00000000..03aa429b --- /dev/null +++ b/providers/common/ciphers/block.c @@ -0,0 +1,118 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "ciphers_locl.h" +#include +#include "internal/providercommonerr.h" + +/* + * Fills a single block of buffered data from the input, and returns the amount + * of data remaining in the input that is a multiple of the blocksize. The buffer + * is only filled if it already has some data in it, isn't full already or we + * don't have at least one block in the input. + * + * buf: a buffer of blocksize bytes + * buflen: contains the amount of data already in buf on entry. Updated with the + * amount of data in buf at the end. On entry *buflen must always be + * less than the blocksize + * blocksize: size of a block. Must be greater than 0 and a power of 2 + * in: pointer to a pointer containing the input data + * inlen: amount of input data available + * + * On return buf is filled with as much data as possible up to a full block, + * *buflen is updated containing the amount of data in buf. *in is updated to + * the new location where input data should be read from, *inlen is updated with + * the remaining amount of data in *in. Returns the largest value <= *inlen + * which is a multiple of the blocksize. + */ +size_t fillblock(unsigned char *buf, size_t *buflen, size_t blocksize, + const unsigned char **in, size_t *inlen) +{ + size_t blockmask = ~(blocksize - 1); + + assert(*buflen <= blocksize); + assert(blocksize > 0 && (blocksize & (blocksize - 1)) == 0); + + if (*buflen != blocksize && (*buflen != 0 || *inlen < blocksize)) { + size_t bufremain = blocksize - *buflen; + + if (*inlen < bufremain) + bufremain = *inlen; + memcpy(buf + *buflen, *in, bufremain); + *in += bufremain; + *inlen -= bufremain; + *buflen += bufremain; + } + + return *inlen & blockmask; +} + +/* + * Fills the buffer with trailing data from an encryption/decryption that didn't + * fit into a full block. + */ +int trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize, + const unsigned char **in, size_t *inlen) +{ + if (*inlen == 0) + return 1; + + if (*buflen + *inlen > blocksize) { + PROVerr(PROV_F_TRAILINGDATA, ERR_R_INTERNAL_ERROR); + return 0; + } + + memcpy(buf + *buflen, *in, *inlen); + *buflen += *inlen; + *inlen = 0; + + return 1; +} + +/* Pad the final block for encryption */ +void padblock(unsigned char *buf, size_t *buflen, size_t blocksize) +{ + size_t i; + unsigned char pad = (unsigned char)(blocksize - *buflen); + + for (i = *buflen; i < blocksize; i++) + buf[i] = pad; +} + +int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize) +{ + size_t pad, i; + size_t len = *buflen; + + if(len != blocksize) { + PROVerr(PROV_F_UNPADBLOCK, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* + * The following assumes that the ciphertext has been authenticated. + * Otherwise it provides a padding oracle. + */ + pad = buf[blocksize - 1]; + if (pad == 0 || pad > blocksize) { + PROVerr(PROV_F_UNPADBLOCK, PROV_R_BAD_DECRYPT); + return 0; + } + for (i = 0; i < pad; i++) { + if (buf[--len] != pad) { + PROVerr(PROV_F_UNPADBLOCK, PROV_R_BAD_DECRYPT); + return 0; + } + } + *buflen = len; + return 1; +} diff --git a/providers/common/ciphers/build.info b/providers/common/ciphers/build.info new file mode 100644 index 00000000..f4ff2ce8 --- /dev/null +++ b/providers/common/ciphers/build.info @@ -0,0 +1,4 @@ +LIBS=../../../libcrypto +SOURCE[../../../libcrypto]=\ + block.c aes.c aes_basic.c +INCLUDE[../../../libcrypto]=. ../../../crypto diff --git a/providers/common/ciphers/ciphers_locl.h b/providers/common/ciphers/ciphers_locl.h new file mode 100644 index 00000000..a874bbf1 --- /dev/null +++ b/providers/common/ciphers/ciphers_locl.h @@ -0,0 +1,107 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include + +typedef struct prov_aes_cipher_st PROV_AES_CIPHER; + +typedef struct prov_aes_key_st { + union { + double align; + AES_KEY ks; + } ks; + block128_f block; + union { + cbc128_f cbc; + ctr128_f ctr; + } stream; + + /* Platform specific data */ + union { + int dummy; +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) + struct { + union { + double align; + /*- + * KM-AES parameter block - begin + * (see z/Architecture Principles of Operation >= SA22-7832-06) + */ + struct { + unsigned char k[32]; + } km; + /* KM-AES parameter block - end */ + /*- + * KMO-AES/KMF-AES parameter block - begin + * (see z/Architecture Principles of Operation >= SA22-7832-08) + */ + struct { + unsigned char cv[16]; + unsigned char k[32]; + } kmo_kmf; + /* KMO-AES/KMF-AES parameter block - end */ + } param; + unsigned int fc; + int res; + } s390x; +#endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */ + } plat; + + /* The cipher functions we are going to use */ + const PROV_AES_CIPHER *ciph; + + /* The mode that we are using */ + int mode; + + /* Set to 1 if we are encrypting or 0 otherwise */ + int enc; + + unsigned char iv[AES_BLOCK_SIZE]; + + /* + * num contains the number of bytes of |iv| which are valid for modes that + * manage partial blocks themselves. + */ + size_t num; + + /* Buffer of partial blocks processed via update calls */ + unsigned char buf[AES_BLOCK_SIZE]; + + /* Number of bytes in buf */ + size_t bufsz; + + uint64_t flags; + + size_t keylen; + + /* Whether padding should be used or not */ + unsigned int pad : 1; +} PROV_AES_KEY; + +struct prov_aes_cipher_st { + int (*init)(PROV_AES_KEY *dat, const uint8_t *key, size_t keylen); + int (*cipher)(PROV_AES_KEY *dat, uint8_t *out, const uint8_t *in, + size_t inl); +}; + +const PROV_AES_CIPHER *PROV_AES_CIPHER_ecb(size_t keylen); +const PROV_AES_CIPHER *PROV_AES_CIPHER_cbc(size_t keylen); +const PROV_AES_CIPHER *PROV_AES_CIPHER_ofb(size_t keylen); +const PROV_AES_CIPHER *PROV_AES_CIPHER_cfb(size_t keylen); +const PROV_AES_CIPHER *PROV_AES_CIPHER_cfb1(size_t keylen); +const PROV_AES_CIPHER *PROV_AES_CIPHER_cfb8(size_t keylen); +const PROV_AES_CIPHER *PROV_AES_CIPHER_ctr(size_t keylen); + +size_t fillblock(unsigned char *buf, size_t *buflen, size_t blocksize, + const unsigned char **in, size_t *inlen); +int trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize, + const unsigned char **in, size_t *inlen); +void padblock(unsigned char *buf, size_t *buflen, size_t blocksize); +int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize); diff --git a/providers/common/digests/sha2.c b/providers/common/digests/sha2.c index 4332e981..c9f616db 100644 --- a/providers/common/digests/sha2.c +++ b/providers/common/digests/sha2.c @@ -10,11 +10,30 @@ #include #include #include +#include "internal/provider_algs.h" -static int sha256_final(void *ctx, unsigned char *md, size_t *size) +/* + * Forward declaration of everything implemented here. This is not strictly + * necessary for the compiler, but provides an assurance that the signatures + * of the functions in the dispatch table are correct. + */ +static OSSL_OP_digest_newctx_fn sha256_newctx; +#if 0 /* Not defined here */ +static OSSL_OP_digest_init_fn sha256_init; +static OSSL_OP_digest_update_fn sha256_update; +#endif +static OSSL_OP_digest_final_fn sha256_final; +static OSSL_OP_digest_freectx_fn sha256_freectx; +static OSSL_OP_digest_dupctx_fn sha256_dupctx; +static OSSL_OP_digest_size_fn sha256_size; +static OSSL_OP_digest_block_size_fn sha256_size; + +static int sha256_final(void *ctx, + unsigned char *md, size_t *mdl, size_t mdsz) { - if (SHA256_Final(md, ctx)) { - *size = SHA256_DIGEST_LENGTH; + if (mdsz >= SHA256_DIGEST_LENGTH + && SHA256_Final(md, ctx)) { + *mdl = SHA256_DIGEST_LENGTH; return 1; } @@ -55,11 +74,10 @@ static size_t sha256_block_size(void) return SHA256_CBLOCK; } -extern const OSSL_DISPATCH sha256_functions[]; const OSSL_DISPATCH sha256_functions[] = { { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))sha256_newctx }, { OSSL_FUNC_DIGEST_INIT, (void (*)(void))SHA256_Init }, - { OSSL_FUNC_DIGEST_UPDDATE, (void (*)(void))SHA256_Update }, + { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))SHA256_Update }, { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))sha256_final }, { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))sha256_freectx }, { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))sha256_dupctx }, diff --git a/providers/common/include/internal/provider_algs.h b/providers/common/include/internal/provider_algs.h new file mode 100644 index 00000000..dd9211bb --- /dev/null +++ b/providers/common/include/internal/provider_algs.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Digests */ +extern const OSSL_DISPATCH sha256_functions[]; + +/* Ciphers */ +extern const OSSL_DISPATCH aes256ecb_functions[]; +extern const OSSL_DISPATCH aes192ecb_functions[]; +extern const OSSL_DISPATCH aes128ecb_functions[]; +extern const OSSL_DISPATCH aes256cbc_functions[]; +extern const OSSL_DISPATCH aes192cbc_functions[]; +extern const OSSL_DISPATCH aes128cbc_functions[]; +extern const OSSL_DISPATCH aes256ofb_functions[]; +extern const OSSL_DISPATCH aes192ofb_functions[]; +extern const OSSL_DISPATCH aes128ofb_functions[]; +extern const OSSL_DISPATCH aes256cfb_functions[]; +extern const OSSL_DISPATCH aes192cfb_functions[]; +extern const OSSL_DISPATCH aes128cfb_functions[]; +extern const OSSL_DISPATCH aes256cfb1_functions[]; +extern const OSSL_DISPATCH aes192cfb1_functions[]; +extern const OSSL_DISPATCH aes128cfb1_functions[]; +extern const OSSL_DISPATCH aes256cfb8_functions[]; +extern const OSSL_DISPATCH aes192cfb8_functions[]; +extern const OSSL_DISPATCH aes128cfb8_functions[]; +extern const OSSL_DISPATCH aes256ctr_functions[]; +extern const OSSL_DISPATCH aes192ctr_functions[]; +extern const OSSL_DISPATCH aes128ctr_functions[]; diff --git a/providers/common/include/internal/providercommon.h b/providers/common/include/internal/providercommon.h new file mode 100644 index 00000000..e69de29b diff --git a/providers/common/include/internal/providercommonerr.h b/providers/common/include/internal/providercommonerr.h new file mode 100644 index 00000000..609fd5bf --- /dev/null +++ b/providers/common/include/internal/providercommonerr.h @@ -0,0 +1,54 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef HEADER_PROVERR_H +# define HEADER_PROVERR_H + +# ifndef HEADER_SYMHACKS_H +# include +# endif + +# ifdef __cplusplus +extern "C" +# endif +int ERR_load_PROV_strings(void); + +/* + * PROV function codes. + */ +# define PROV_F_AESNI_INIT_KEY 101 +# define PROV_F_AES_BLOCK_FINAL 102 +# define PROV_F_AES_BLOCK_UPDATE 103 +# define PROV_F_AES_CIPHER 104 +# define PROV_F_AES_CTX_GET_PARAMS 105 +# define PROV_F_AES_CTX_SET_PARAMS 106 +# define PROV_F_AES_DINIT 107 +# define PROV_F_AES_DUPCTX 108 +# define PROV_F_AES_EINIT 109 +# define PROV_F_AES_INIT_KEY 110 +# define PROV_F_AES_STREAM_UPDATE 111 +# define PROV_F_AES_T4_INIT_KEY 112 +# define PROV_F_PROV_AES_KEY_GENERIC_INIT 113 +# define PROV_F_TRAILINGDATA 114 +# define PROV_F_UNPADBLOCK 100 + +/* + * PROV reason codes. + */ +# define PROV_R_AES_KEY_SETUP_FAILED 101 +# define PROV_R_BAD_DECRYPT 100 +# define PROV_R_CIPHER_OPERATION_FAILED 102 +# define PROV_R_FAILED_TO_GET_PARAMETER 103 +# define PROV_R_FAILED_TO_SET_PARAMETER 104 +# define PROV_R_INVALID_KEYLEN 105 +# define PROV_R_OUTPUT_BUFFER_TOO_SMALL 106 +# define PROV_R_WRONG_FINAL_BLOCK_LENGTH 107 + +#endif diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c new file mode 100644 index 00000000..e6b577fe --- /dev/null +++ b/providers/common/provider_err.c @@ -0,0 +1,67 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include "internal/providercommonerr.h" + +#ifndef OPENSSL_NO_ERR + +static const ERR_STRING_DATA PROV_str_functs[] = { + {ERR_PACK(ERR_LIB_PROV, PROV_F_AESNI_INIT_KEY, 0), "aesni_init_key"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_BLOCK_FINAL, 0), "aes_block_final"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_BLOCK_UPDATE, 0), "aes_block_update"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_CIPHER, 0), "aes_cipher"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_CTX_GET_PARAMS, 0), + "aes_ctx_get_params"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_CTX_SET_PARAMS, 0), + "aes_ctx_set_params"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_DINIT, 0), "aes_dinit"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_DUPCTX, 0), "aes_dupctx"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_EINIT, 0), "aes_einit"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_INIT_KEY, 0), "aes_init_key"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_STREAM_UPDATE, 0), "aes_stream_update"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_AES_T4_INIT_KEY, 0), "aes_t4_init_key"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_PROV_AES_KEY_GENERIC_INIT, 0), + "PROV_AES_KEY_generic_init"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_TRAILINGDATA, 0), "trailingdata"}, + {ERR_PACK(ERR_LIB_PROV, PROV_F_UNPADBLOCK, 0), "unpadblock"}, + {0, NULL} +}; + +static const ERR_STRING_DATA PROV_str_reasons[] = { + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_AES_KEY_SETUP_FAILED), + "aes key setup failed"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_DECRYPT), "bad decrypt"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_CIPHER_OPERATION_FAILED), + "cipher operation failed"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_GET_PARAMETER), + "failed to get parameter"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_SET_PARAMETER), + "failed to set parameter"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEYLEN), "invalid keylen"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_OUTPUT_BUFFER_TOO_SMALL), + "output buffer too small"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_WRONG_FINAL_BLOCK_LENGTH), + "wrong final block length"}, + {0, NULL} +}; + +#endif + +int ERR_load_PROV_strings(void) +{ +#ifndef OPENSSL_NO_ERR + if (ERR_func_error_string(PROV_str_functs[0].error) == NULL) { + ERR_load_strings_const(PROV_str_functs); + ERR_load_strings_const(PROV_str_reasons); + } +#endif + return 1; +} diff --git a/providers/default/defltprov.c b/providers/default/defltprov.c index 9b52429b..cba2dccf 100644 --- a/providers/default/defltprov.c +++ b/providers/default/defltprov.c @@ -13,6 +13,7 @@ #include #include #include +#include "internal/provider_algs.h" /* Functions provided by the core */ static OSSL_core_get_param_types_fn *c_get_param_types = NULL; @@ -49,13 +50,36 @@ static int deflt_get_params(const OSSL_PROVIDER *prov, return 1; } -extern const OSSL_DISPATCH sha256_functions[]; - static const OSSL_ALGORITHM deflt_digests[] = { { "SHA256", "default=yes", sha256_functions }, { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM deflt_ciphers[] = { + { "AES-256-ECB", "default=yes", aes256ecb_functions }, + { "AES-192-ECB", "default=yes", aes192ecb_functions }, + { "AES-128-ECB", "default=yes", aes128ecb_functions }, + { "AES-256-CBC", "default=yes", aes256cbc_functions }, + { "AES-192-CBC", "default=yes", aes192cbc_functions }, + { "AES-128-CBC", "default=yes", aes128cbc_functions }, + { "AES-256-OFB", "default=yes", aes256ofb_functions }, + { "AES-192-OFB", "default=yes", aes192ofb_functions }, + { "AES-128-OFB", "default=yes", aes128ofb_functions }, + { "AES-256-CFB", "default=yes", aes256cfb_functions }, + { "AES-192-CFB", "default=yes", aes192cfb_functions }, + { "AES-128-CFB", "default=yes", aes128cfb_functions }, + { "AES-256-CFB1", "default=yes", aes256cfb1_functions }, + { "AES-192-CFB1", "default=yes", aes192cfb1_functions }, + { "AES-128-CFB1", "default=yes", aes128cfb1_functions }, + { "AES-256-CFB8", "default=yes", aes256cfb8_functions }, + { "AES-192-CFB8", "default=yes", aes192cfb8_functions }, + { "AES-128-CFB8", "default=yes", aes128cfb8_functions }, + { "AES-256-CTR", "default=yes", aes256ctr_functions }, + { "AES-192-CTR", "default=yes", aes192ctr_functions }, + { "AES-128-CTR", "default=yes", aes128ctr_functions }, + { NULL, NULL, NULL } +}; + static const OSSL_ALGORITHM *deflt_query(OSSL_PROVIDER *prov, int operation_id, int *no_cache) @@ -64,6 +88,8 @@ static const OSSL_ALGORITHM *deflt_query(OSSL_PROVIDER *prov, switch (operation_id) { case OSSL_OP_DIGEST: return deflt_digests; + case OSSL_OP_CIPHER: + return deflt_ciphers; } return NULL; } diff --git a/providers/legacy/digests/md2.c b/providers/legacy/digests/md2.c index c941dd7d..017a5111 100644 --- a/providers/legacy/digests/md2.c +++ b/providers/legacy/digests/md2.c @@ -54,7 +54,7 @@ extern const OSSL_DISPATCH md2_functions[]; const OSSL_DISPATCH md2_functions[] = { { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))md2_newctx }, { OSSL_FUNC_DIGEST_INIT, (void (*)(void))MD2_Init }, - { OSSL_FUNC_DIGEST_UPDDATE, (void (*)(void))MD2_Update }, + { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))MD2_Update }, { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))md2_final }, { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))md2_freectx }, { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))md2_dupctx }, diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index 24694b3f..f758f17d 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -211,9 +211,9 @@ int ssl3_get_record(SSL *s) SSL3_BUFFER_get_len(rbuf), 0, num_recs == 0 ? 1 : 0, &n); if (rret <= 0) { +#ifndef OPENSSL_NO_KTLS if (!BIO_get_ktls_recv(s->rbio)) return rret; /* error or non-blocking */ -#ifndef OPENSSL_NO_KTLS switch (errno) { case EBADMSG: SSLfatal(s, SSL_AD_BAD_RECORD_MAC, @@ -233,8 +233,8 @@ int ssl3_get_record(SSL *s) default: break; } - return rret; #endif + return rret; } RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY); diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 9828b43b..feee2d9d 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5201,6 +5201,11 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) if (ext->present) num++; } + if (num == 0) { + *out = NULL; + *outlen = 0; + return 1; + } if ((present = OPENSSL_malloc(sizeof(*present) * num)) == NULL) { SSLerr(SSL_F_SSL_CLIENT_HELLO_GET1_EXTENSIONS_PRESENT, ERR_R_MALLOC_FAILURE); diff --git a/test/bio_memleak_test.c b/test/bio_memleak_test.c index 36680e30..fab5ce73 100644 --- a/test/bio_memleak_test.c +++ b/test/bio_memleak_test.c @@ -18,28 +18,170 @@ static int test_bio_memleak(void) int ok = 0; BIO *bio; BUF_MEM bufmem; - const char *str = "BIO test\n"; + static const char str[] = "BIO test\n"; char buf[100]; bio = BIO_new(BIO_s_mem()); - if (bio == NULL) + if (!TEST_ptr(bio)) goto finish; - bufmem.length = strlen(str) + 1; + bufmem.length = sizeof(str); bufmem.data = (char *) str; bufmem.max = bufmem.length; BIO_set_mem_buf(bio, &bufmem, BIO_NOCLOSE); BIO_set_flags(bio, BIO_FLAGS_MEM_RDONLY); - - if (BIO_read(bio, buf, sizeof(buf)) <= 0) - goto finish; - - ok = strcmp(buf, str) == 0; + if (!TEST_int_eq(BIO_read(bio, buf, sizeof(buf)), sizeof(str))) + goto finish; + if (!TEST_mem_eq(buf, sizeof(str), str, sizeof(str))) + goto finish; + ok = 1; finish: BIO_free(bio); return ok; } +static int test_bio_get_mem(void) +{ + int ok = 0; + BIO *bio = NULL; + BUF_MEM *bufmem = NULL; + + bio = BIO_new(BIO_s_mem()); + if (!TEST_ptr(bio)) + goto finish; + if (!TEST_int_eq(BIO_puts(bio, "Hello World\n"), 12)) + goto finish; + BIO_get_mem_ptr(bio, &bufmem); + if (!TEST_ptr(bufmem)) + goto finish; + if (!TEST_int_gt(BIO_set_close(bio, BIO_NOCLOSE), 0)) + goto finish; + BIO_free(bio); + bio = NULL; + if (!TEST_mem_eq(bufmem->data, bufmem->length, "Hello World\n", 12)) + goto finish; + ok = 1; + +finish: + BIO_free(bio); + BUF_MEM_free(bufmem); + return ok; +} + +static int test_bio_new_mem_buf(void) +{ + int ok = 0; + BIO *bio; + BUF_MEM *bufmem; + char data[16]; + + bio = BIO_new_mem_buf("Hello World\n", 12); + if (!TEST_ptr(bio)) + goto finish; + if (!TEST_int_eq(BIO_read(bio, data, 5), 5)) + goto finish; + if (!TEST_mem_eq(data, 5, "Hello", 5)) + goto finish; + if (!TEST_int_gt(BIO_get_mem_ptr(bio, &bufmem), 0)) + goto finish; + if (!TEST_int_lt(BIO_write(bio, "test", 4), 0)) + goto finish; + if (!TEST_int_eq(BIO_read(bio, data, 16), 7)) + goto finish; + if (!TEST_mem_eq(data, 7, " World\n", 7)) + goto finish; + if (!TEST_int_gt(BIO_reset(bio), 0)) + goto finish; + if (!TEST_int_eq(BIO_read(bio, data, 16), 12)) + goto finish; + if (!TEST_mem_eq(data, 12, "Hello World\n", 12)) + goto finish; + ok = 1; + +finish: + BIO_free(bio); + return ok; +} + +static int test_bio_rdonly_mem_buf(void) +{ + int ok = 0; + BIO *bio, *bio2 = NULL; + BUF_MEM *bufmem; + char data[16]; + + bio = BIO_new_mem_buf("Hello World\n", 12); + if (!TEST_ptr(bio)) + goto finish; + if (!TEST_int_eq(BIO_read(bio, data, 5), 5)) + goto finish; + if (!TEST_mem_eq(data, 5, "Hello", 5)) + goto finish; + if (!TEST_int_gt(BIO_get_mem_ptr(bio, &bufmem), 0)) + goto finish; + (void)BIO_set_close(bio, BIO_NOCLOSE); + + bio2 = BIO_new(BIO_s_mem()); + if (!TEST_ptr(bio2)) + goto finish; + BIO_set_mem_buf(bio2, bufmem, BIO_CLOSE); + BIO_set_flags(bio2, BIO_FLAGS_MEM_RDONLY); + + if (!TEST_int_eq(BIO_read(bio2, data, 16), 7)) + goto finish; + if (!TEST_mem_eq(data, 7, " World\n", 7)) + goto finish; + if (!TEST_int_gt(BIO_reset(bio2), 0)) + goto finish; + if (!TEST_int_eq(BIO_read(bio2, data, 16), 7)) + goto finish; + if (!TEST_mem_eq(data, 7, " World\n", 7)) + goto finish; + ok = 1; + +finish: + BIO_free(bio); + BIO_free(bio2); + return ok; +} + +static int test_bio_rdwr_rdonly(void) +{ + int ok = 0; + BIO *bio = NULL; + char data[16]; + + bio = BIO_new(BIO_s_mem()); + if (!TEST_ptr(bio)) + goto finish; + if (!TEST_int_eq(BIO_puts(bio, "Hello World\n"), 12)) + goto finish; + + BIO_set_flags(bio, BIO_FLAGS_MEM_RDONLY); + if (!TEST_int_eq(BIO_read(bio, data, 16), 12)) + goto finish; + if (!TEST_mem_eq(data, 12, "Hello World\n", 12)) + goto finish; + if (!TEST_int_gt(BIO_reset(bio), 0)) + goto finish; + + BIO_clear_flags(bio, BIO_FLAGS_MEM_RDONLY); + if (!TEST_int_eq(BIO_puts(bio, "Hi!\n"), 4)) + goto finish; + if (!TEST_int_eq(BIO_read(bio, data, 16), 16)) + goto finish; + + if (!TEST_mem_eq(data, 16, "Hello World\nHi!\n", 16)) + goto finish; + + ok = 1; + +finish: + BIO_free(bio); + return ok; +} + + int global_init(void) { CRYPTO_set_mem_debug(1); @@ -50,5 +192,9 @@ int global_init(void) int setup_tests(void) { ADD_TEST(test_bio_memleak); + ADD_TEST(test_bio_get_mem); + ADD_TEST(test_bio_new_mem_buf); + ADD_TEST(test_bio_rdonly_mem_buf); + ADD_TEST(test_bio_rdwr_rdonly); return 1; } diff --git a/test/bntest.c b/test/bntest.c index 976dbf44..2043e43e 100644 --- a/test/bntest.c +++ b/test/bntest.c @@ -1954,6 +1954,73 @@ static int test_rand(void) return st; } +/* + * Run some statistical tests to provide a degree confidence that the + * BN_rand_range() function works as expected. The critical value + * is computed using the R statistical suite: + * + * qchisq(alpha, df=iterations - 1) + * + * where alpha is the significance level (0.95 is used here) and iterations + * is the number of samples being drawn. + */ +static const struct { + unsigned int range; + unsigned int iterations; + double critical; +} rand_range_cases[] = { + { 2, 100, 123.2252 /* = qchisq(.95, df=99) */ }, + { 12, 1000, 1073.643 /* = qchisq(.95, df=999) */ }, + { 1023, 100000, 100735.7 /* = qchisq(.95, df=99999) */ }, +}; + +static int test_rand_range(int n) +{ + const unsigned int range = rand_range_cases[n].range; + const unsigned int iterations = rand_range_cases[n].iterations; + const double critical = rand_range_cases[n].critical; + const double expected = iterations / (double)range; + double sum = 0; + BIGNUM *rng = NULL, *val = NULL; + size_t *counts; + unsigned int i, v; + int res = 0; + + if (!TEST_ptr(counts = OPENSSL_zalloc(sizeof(*counts) * range)) + || !TEST_ptr(rng = BN_new()) + || !TEST_ptr(val = BN_new()) + || !TEST_true(BN_set_word(rng, range))) + goto err; + for (i = 0; i < iterations; i++) { + if (!TEST_true(BN_rand_range(val, rng)) + || !TEST_uint_lt(v = (unsigned int)BN_get_word(val), range)) + goto err; + counts[v]++; + } + + TEST_note("range %u iterations %u critical %.4f", range, iterations, + critical); + if (range < 20) { + TEST_note("frequencies (expected %.2f)", expected); + for (i = 0; i < range; i++) + TEST_note(" %2u %6zu", i, counts[i]); + } + for (i = 0; i < range; i++) { + const double delta = counts[i] - expected; + sum += delta * delta; + } + sum /= expected; + TEST_note("test statistic %.4f", sum); + + if (TEST_double_lt(sum, critical)) + res = 1; +err: + BN_free(rng); + BN_free(val); + OPENSSL_free(counts); + return res; +} + static int test_negzero(void) { BIGNUM *a = NULL, *b = NULL, *c = NULL, *d = NULL; @@ -2432,6 +2499,7 @@ int setup_tests(void) #endif ADD_ALL_TESTS(test_is_prime, (int)OSSL_NELEM(primes)); ADD_ALL_TESTS(test_not_prime, (int)OSSL_NELEM(not_primes)); + ADD_ALL_TESTS(test_rand_range, OSSL_NELEM(rand_range_cases)); } else { ADD_ALL_TESTS(run_file_tests, n); } diff --git a/test/ectest.c b/test/ectest.c index ab75acea..3f7747e5 100644 --- a/test/ectest.c +++ b/test/ectest.c @@ -1884,11 +1884,14 @@ static int check_ec_key_field_public_range_test(int id) * be the same point on the curve). The add is different for char2 fields. */ type = EC_METHOD_get_field_type(meth); +#ifndef OPENSSL_NO_EC2M if (type == NID_X9_62_characteristic_two_field) { /* test for binary curves */ if (!TEST_true(BN_GF2m_add(x, x, field))) goto err; - } else if (type == NID_X9_62_prime_field) { + } else +#endif + if (type == NID_X9_62_prime_field) { /* test for prime curves */ if (!TEST_true(BN_add(x, x, field))) goto err; diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 4215fe35..955daf7b 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -253,6 +253,60 @@ static int test_kdf_ss_kmac(void) return ret; } +static int test_kdf_sshkdf(void) +{ + int ret; + EVP_KDF_CTX *kctx; + unsigned char out[8]; + /* Test data from NIST CAVS 14.1 test vectors */ + const unsigned char key[] = { + 0x00, 0x00, 0x00, 0x81, 0x00, 0x87, 0x5c, 0x55, 0x1c, 0xef, 0x52, 0x6a, + 0x4a, 0x8b, 0xe1, 0xa7, 0xdf, 0x27, 0xe9, 0xed, 0x35, 0x4b, 0xac, 0x9a, + 0xfb, 0x71, 0xf5, 0x3d, 0xba, 0xe9, 0x05, 0x67, 0x9d, 0x14, 0xf9, 0xfa, + 0xf2, 0x46, 0x9c, 0x53, 0x45, 0x7c, 0xf8, 0x0a, 0x36, 0x6b, 0xe2, 0x78, + 0x96, 0x5b, 0xa6, 0x25, 0x52, 0x76, 0xca, 0x2d, 0x9f, 0x4a, 0x97, 0xd2, + 0x71, 0xf7, 0x1e, 0x50, 0xd8, 0xa9, 0xec, 0x46, 0x25, 0x3a, 0x6a, 0x90, + 0x6a, 0xc2, 0xc5, 0xe4, 0xf4, 0x8b, 0x27, 0xa6, 0x3c, 0xe0, 0x8d, 0x80, + 0x39, 0x0a, 0x49, 0x2a, 0xa4, 0x3b, 0xad, 0x9d, 0x88, 0x2c, 0xca, 0xc2, + 0x3d, 0xac, 0x88, 0xbc, 0xad, 0xa4, 0xb4, 0xd4, 0x26, 0xa3, 0x62, 0x08, + 0x3d, 0xab, 0x65, 0x69, 0xc5, 0x4c, 0x22, 0x4d, 0xd2, 0xd8, 0x76, 0x43, + 0xaa, 0x22, 0x76, 0x93, 0xe1, 0x41, 0xad, 0x16, 0x30, 0xce, 0x13, 0x14, + 0x4e + }; + const unsigned char xcghash[] = { + 0x0e, 0x68, 0x3f, 0xc8, 0xa9, 0xed, 0x7c, 0x2f, 0xf0, 0x2d, 0xef, 0x23, + 0xb2, 0x74, 0x5e, 0xbc, 0x99, 0xb2, 0x67, 0xda, 0xa8, 0x6a, 0x4a, 0xa7, + 0x69, 0x72, 0x39, 0x08, 0x82, 0x53, 0xf6, 0x42 + }; + const unsigned char sessid[] = { + 0x0e, 0x68, 0x3f, 0xc8, 0xa9, 0xed, 0x7c, 0x2f, 0xf0, 0x2d, 0xef, 0x23, + 0xb2, 0x74, 0x5e, 0xbc, 0x99, 0xb2, 0x67, 0xda, 0xa8, 0x6a, 0x4a, 0xa7, + 0x69, 0x72, 0x39, 0x08, 0x82, 0x53, 0xf6, 0x42 + }; + const unsigned char expected[sizeof(out)] = { + 0x41, 0xff, 0x2e, 0xad, 0x16, 0x83, 0xf1, 0xe6 + }; + + ret = TEST_ptr(kctx = EVP_KDF_CTX_new_id(EVP_KDF_SSHKDF)) + && TEST_int_gt(EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, EVP_sha256()), + 0) + && TEST_int_gt(EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, key, + sizeof(key)), 0) + && TEST_int_gt(EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, + xcghash, sizeof(xcghash)), 0) + && TEST_int_gt(EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, + sessid, sizeof(sessid)), 0) + && TEST_int_gt( + EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SSHKDF_TYPE, + (int)EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV), + 0) + && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out)), 0) + && TEST_mem_eq(out, sizeof(out), expected, sizeof(expected)); + + EVP_KDF_CTX_free(kctx); + return ret; +} + int setup_tests(void) { ADD_TEST(test_kdf_tls1_prf); @@ -264,5 +318,6 @@ int setup_tests(void) ADD_TEST(test_kdf_ss_hash); ADD_TEST(test_kdf_ss_hmac); ADD_TEST(test_kdf_ss_kmac); + ADD_TEST(test_kdf_sshkdf); return 1; } diff --git a/test/recipes/20-test_kdf.t b/test/recipes/20-test_kdf.t new file mode 100644 index 00000000..62cbb050 --- /dev/null +++ b/test/recipes/20-test_kdf.t @@ -0,0 +1,78 @@ +#! /usr/bin/env perl +# Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +use strict; +use warnings; + +use OpenSSL::Test; +use OpenSSL::Test::Utils; + +setup("test_kdf"); + +my @kdf_tests = ( + { cmd => [qw{openssl kdf -keylen 16 -kdfopt digest:SHA256 -kdfopt secret:secret -kdfopt seed:seed TLS1-PRF}], + expected => '8E:4D:93:25:30:D7:65:A0:AA:E9:74:C3:04:73:5E:CC', + desc => 'TLS1-PRF SHA256' }, + { cmd => [qw{openssl kdf -keylen 16 -kdfopt digest:MD5-SHA1 -kdfopt secret:secret -kdfopt seed:seed TLS1-PRF}], + expected => '65:6F:31:CB:04:03:D6:51:E2:E8:71:F8:20:04:AB:BA', + desc => 'TLS1-PRF MD5-SHA1' }, + { cmd => [qw{openssl kdf -keylen 10 -kdfopt digest:SHA256 -kdfopt key:secret -kdfopt salt:salt -kdfopt info:label HKDF}], + expected => '2a:c4:36:9f:52:59:96:f8:de:13', + desc => 'HKDF SHA256' }, + { cmd => [qw{openssl kdf -keylen 32 -kdfopt digest:SHA256 -kdfopt pass:password -kdfopt salt:salt -kdfopt iter:2 PBKDF2}], + expected => 'ae:4d:0c:95:af:6b:46:d3:2d:0a:df:f9:28:f0:6d:d0:2a:30:3f:8e:f3:c2:51:df:d6:e2:d8:5a:95:47:4c:43', + desc => 'PBKDF2 SHA256'}, + { cmd => [qw{openssl kdf -keylen 64 -kdfopt mac:KMAC128 -kdfopt maclen:20 -kdfopt hexkey:b74a149a161546f8c20b06ac4ed4 -kdfopt hexinfo:348a37a27ef1282f5f020dcc -kdfopt hexsalt:3638271ccd68a25dc24ecddd39ef3f89 SSKDF}], + expected => 'e9:c1:84:53:a0:62:b5:3b:db:fc:bb:5a:34:bd:b8:e5:e7:07:ee:bb:5d:d1:34:42:43:d8:cf:c2:c2:e6:33:2f:91:bd:a5:86:f3:7d:e4:8a:65:d4:c5:14:fd:ef:aa:1e:67:54:f3:73:d2:38:e1:95:ae:15:7e:1d:e8:14:98:03', + desc => 'SSKDF KMAC128'}, + { cmd => [qw{openssl kdf -keylen 16 -kdfopt mac:HMAC -kdfopt digest:SHA256 -kdfopt hexkey:b74a149a161546f8c20b06ac4ed4 -kdfopt hexinfo:348a37a27ef1282f5f020dcc -kdfopt hexsalt:3638271ccd68a25dc24ecddd39ef3f89 SSKDF}], + expected => '44:f6:76:e8:5c:1b:1a:8b:bc:3d:31:92:18:63:1c:a3', + desc => 'SSKDF HMAC SHA256'}, + { cmd => [qw{openssl kdf -keylen 14 -kdfopt digest:SHA224 -kdfopt hexkey:6dbdc23f045488e4062757b06b9ebae183fc5a5946d80db93fec6f62ec07e3727f0126aed12ce4b262f47d48d54287f81d474c7c3b1850e9 -kdfopt hexinfo:a1b2c3d4e54341565369643c832e9849dcdba71e9a3139e606e095de3c264a66e98a165854cd07989b1ee0ec3f8dbe SSKDF}], + expected => 'a4:62:de:16:a8:9d:e8:46:6e:f5:46:0b:47:b8', + desc => 'SSKDF HASH SHA224'}, + { cmd => [qw{openssl kdf -keylen 16 -kdfopt md:SHA256 -kdfopt hexkey:0102030405 -kdfopt hexxcghash:06090A -kdfopt hexsession_id:01020304 -kdfopt type:A SSHKDF}], + expected => '5C:49:94:47:3B:B1:53:3A:58:EB:19:42:04:D3:78:16', + desc => 'SSHKDF SHA256'}, +); + +my @scrypt_tests = ( + { cmd => [qw{openssl kdf -keylen 64 -kdfopt pass:password -kdfopt salt:NaCl -kdfopt N:1024 -kdfopt r:8 -kdfopt p:16 -kdfopt maxmem_bytes:10485760 id-scrypt}], + expected => 'fd:ba:be:1c:9d:34:72:00:78:56:e7:19:0d:01:e9:fe:7c:6a:d7:cb:c8:23:78:30:e7:73:76:63:4b:37:31:62:2e:af:30:d9:2e:22:a3:88:6f:f1:09:27:9d:98:30:da:c7:27:af:b9:4a:83:ee:6d:83:60:cb:df:a2:cc:06:40', + desc => 'SCRYPT' }, +); + +push @kdf_tests, @scrypt_tests unless disabled("scrypt"); + +plan tests => scalar @kdf_tests; + +foreach (@kdf_tests) { + ok(compareline($_->{cmd}, $_->{expected}), $_->{desc}); +} + +# Check that the stdout output matches the expected value. +sub compareline { + my ($cmdarray, $expect) = @_; + if (defined($expect)) { + $expect = uc $expect; + } + + my @lines = run(app($cmdarray), capture => 1); + + if (defined($expect)) { + if ($lines[0] =~ m|^\Q${expect}\E\R$|) { + return 1; + } else { + print "Got: $lines[0]"; + print "Exp: $expect\n"; + return 0; + } + } + return 0; +} diff --git a/test/recipes/30-test_evp_data/evpciph.txt b/test/recipes/30-test_evp_data/evpciph.txt index 7c87a6fd..553bee55 100644 --- a/test/recipes/30-test_evp_data/evpciph.txt +++ b/test/recipes/30-test_evp_data/evpciph.txt @@ -2388,14 +2388,41 @@ Operation = ENCRYPT Plaintext = B41E6BE2EBA84A148E2EED84593C5EC7 Ciphertext = 9B9B7BFCD1813CB95D0B3618F40F5122 -Title = Chacha20 +Title = Chacha20 test vectors from RFC7539 +# A.1 Test Vector 1 Cipher = chacha20 Key = 0000000000000000000000000000000000000000000000000000000000000000 IV = 00000000000000000000000000000000 Plaintext = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Ciphertext = 76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586 +# A.1 Test Vector 2 +Cipher = chacha20 +Key = 0000000000000000000000000000000000000000000000000000000000000000 +IV = 01000000000000000000000000000000 +Plaintext = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +Ciphertext = 9f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32ee7aed29b721769ce64e43d57133b074d839d531ed1f28510afb45ace10a1f4b794d6f + +# A.2 Test Vector 1 is the same as A.1 Test Vector 1 +# A.2 Test Vector 2 +Cipher = chacha20 +Key = 0000000000000000000000000000000000000000000000000000000000000001 +#Counter (first 4 bytes) expressed in little-endian order +IV = 01000000000000000000000000000002 +Plaintext = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f +Ciphertext = a3fbf07df3fa2fde4f376ca23e82737041605d9f4f4f57bd8cff2c1d4b7955ec2a97948bd3722915c8f3d337f7d370050e9e96d647b7c39f56e031ca5eb6250d4042e02785ececfa4b4bb5e8ead0440e20b6e8db09d881a7c6132f420e52795042bdfa7773d8a9051447b3291ce1411c680465552aa6c405b7764d5e87bea85ad00f8449ed8f72d0d662ab052691ca66424bc86d2df80ea41f43abf937d3259dc4b2d0dfb48a6c9139ddd7f76966e928e635553ba76c5c879d7b35d49eb2e62b0871cdac638939e25e8a1e0ef9d5280fa8ca328b351c3c765989cbcf3daa8b6ccc3aaf9f3979c92b3720fc88dc95ed84a1be059c6499b9fda236e7e818b04b0bc39c1e876b193bfe5569753f88128cc08aaa9b63d1a16f80ef2554d7189c411f5869ca52c5b83fa36ff216b9c1d30062bebcfd2dc5bce0911934fda79a86f6e698ced759c3ff9b6477338f3da4f9cd8514ea9982ccafb341b2384dd902f3d1ab7ac61dd29c6f21ba5b862f3730e37cfdc4fd806c22f221 + +# A.2 Test Vector 3 +Cipher = chacha20 +Key = 1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0 +#Counter (first 4 bytes) expressed in little-endian order +IV = 2a000000000000000000000000000002 +Plaintext = 2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e642067696d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e6420746865206d6f6d65207261746873206f757467726162652e +Ciphertext = 62e6347f95ed87a45ffae7426f27a1df5fb69110044c0d73118effa95b01e5cf166d3df2d721caf9b21e5fb14c616871fd84c54f9d65b283196c7fe4f60553ebf39c6402c42234e32a356b3e764312a61a5532055716ead6962568f87d3f3f7704c6a8d1bcd1bf4d50d6154b6da731b187b58dfd728afa36757a797ac188d1 + +Title = Chacha20 + Cipher = chacha20 Key = 0000000000000000000000000000000000000000000000000000000000000001 IV = 00000000000000000000000000000000 diff --git a/util/ck_errf.pl b/util/ck_errf.pl index cc7224ad..681535e7 100755 --- a/util/ck_errf.pl +++ b/util/ck_errf.pl @@ -72,7 +72,8 @@ if ( $internal ) { die "Extra parameters given.\n" if @ARGV; $config = "crypto/err/openssl.ec" unless defined $config; @source = ( glob('crypto/*.c'), glob('crypto/*/*.c'), - glob('ssl/*.c'), glob('ssl/*/*.c') ); + glob('ssl/*.c'), glob('ssl/*/*.c'), glob('providers/*.c'), + glob('providers/*/*.c'), glob('providers/*/*/*.c') ); } else { die "Configuration file not given.\nSee '$0 -help' for information\n" unless defined $config; diff --git a/util/libcrypto.num b/util/libcrypto.num index 3cd27492..1869da0d 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4796,4 +4796,8 @@ EVP_MD_fetch 4743 3_0_0 EXIST::FUNCTION: EVP_set_default_properties 4744 3_0_0 EXIST::FUNCTION: OSSL_PARAM_construct_end 4745 3_0_0 EXIST::FUNCTION: EC_GROUP_check_named_curve 4746 3_0_0 EXIST::FUNCTION:EC -EVP_chacha20_poly1305_draft 4747 3_0_0 EXIST::FUNCTION:CHACHA,POLY1305 +EVP_CIPHER_upref 4747 3_0_0 EXIST::FUNCTION: +EVP_CIPHER_fetch 4748 3_0_0 EXIST::FUNCTION: +EVP_CIPHER_mode 4749 3_0_0 EXIST::FUNCTION: +OPENSSL_info 4750 3_0_0 EXIST::FUNCTION: +EVP_chacha20_poly1305_draft 4751 3_0_0 EXIST::FUNCTION:CHACHA,POLY1305 diff --git a/util/mkerr.pl b/util/mkerr.pl index 7139ee3b..f1d9b39b 100755 --- a/util/mkerr.pl +++ b/util/mkerr.pl @@ -114,7 +114,8 @@ if ( $internal ) { die "Cannot mix -internal and -static\n" if $static; die "Extra parameters given.\n" if @ARGV; @source = ( glob('crypto/*.c'), glob('crypto/*/*.c'), - glob('ssl/*.c'), glob('ssl/*/*.c') ); + glob('ssl/*.c'), glob('ssl/*/*.c'), glob('providers/*.c'), + glob('providers/*/*.c'), glob('providers/*/*/*.c') ); } else { die "-module isn't useful without -internal\n" if scalar keys %modules > 0; @source = @ARGV;